diff --git a/aws/resource_aws_lb_listener_rule.go b/aws/resource_aws_lb_listener_rule.go index 96b1d7ba36a3..ef73a43de108 100644 --- a/aws/resource_aws_lb_listener_rule.go +++ b/aws/resource_aws_lb_listener_rule.go @@ -12,9 +12,10 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/elbv2" - "github.com/hashicorp/terraform/helper/resource" - "github.com/hashicorp/terraform/helper/schema" - "github.com/hashicorp/terraform/helper/validation" + "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" ) func resourceAwsLbbListenerRule() *schema.Resource { @@ -152,24 +153,270 @@ func resourceAwsLbbListenerRule() *schema.Resource { }, }, }, + + "authenticate_cognito": { + Type: schema.TypeList, + Optional: true, + DiffSuppressFunc: suppressIfActionTypeNot(elbv2.ActionTypeEnumAuthenticateCognito), + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authentication_request_extra_params": { + Type: schema.TypeMap, + Optional: true, + }, + "on_unauthenticated_request": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{ + elbv2.AuthenticateCognitoActionConditionalBehaviorEnumDeny, + elbv2.AuthenticateCognitoActionConditionalBehaviorEnumAllow, + elbv2.AuthenticateCognitoActionConditionalBehaviorEnumAuthenticate, + }, true), + }, + "scope": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "session_cookie_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "session_timeout": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "user_pool_arn": { + Type: schema.TypeString, + Required: true, + }, + "user_pool_client_id": { + Type: schema.TypeString, + Required: true, + }, + "user_pool_domain": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + + "authenticate_oidc": { + Type: schema.TypeList, + Optional: true, + DiffSuppressFunc: suppressIfActionTypeNot(elbv2.ActionTypeEnumAuthenticateOidc), + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authentication_request_extra_params": { + Type: schema.TypeMap, + Optional: true, + }, + "authorization_endpoint": { + Type: schema.TypeString, + Required: true, + }, + "client_id": { + Type: schema.TypeString, + Required: true, + }, + "client_secret": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + }, + "issuer": { + Type: schema.TypeString, + Required: true, + }, + "on_unauthenticated_request": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{ + elbv2.AuthenticateOidcActionConditionalBehaviorEnumDeny, + elbv2.AuthenticateOidcActionConditionalBehaviorEnumAllow, + elbv2.AuthenticateOidcActionConditionalBehaviorEnumAuthenticate, + }, true), + }, + "scope": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "session_cookie_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "session_timeout": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "token_endpoint": { + Type: schema.TypeString, + Required: true, + }, + "user_info_endpoint": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, }, }, }, "condition": { Type: schema.TypeSet, Required: true, + Set: lbListenerRuleConditionSetHash, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "field": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateMaxLength(64), + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{ + "host-header", + "path-pattern", + }, true), + Deprecated: "use 'host_header' or 'path_pattern' attribute instead", }, - "values": { + "host_header": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, // Deprecated: remove Computed + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "values": { + Type: schema.TypeSet, + // Deprecated: Change Optional & Computed to Required in next major version of the provider + Optional: true, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(1, 128), + }, + Set: schema.HashString, + }, + }, + }, + }, + "http_header": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "http_header_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringMatch(regexp.MustCompile("^[A-Za-z0-9!#$%&'*+-.^_`|~]{1,40}$"), ""), + }, + "values": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(1, 128), + }, + Required: true, + Set: schema.HashString, + }, + }, + }, + }, + "http_request_method": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "values": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[A-Za-z-_]{1,40}$`), ""), + }, + Required: true, + Set: schema.HashString, + }, + }, + }, + }, + "path_pattern": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, // Deprecated: remove Computed + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "values": { + Type: schema.TypeSet, + // Deprecated: Change Optional & Computed to Required in next major version of the provider + Optional: true, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(1, 128), + }, + Set: schema.HashString, + }, + }, + }, + }, + "query_string": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Optional: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + Set: lbListenerRuleConditionQueryStringHash, + }, + "source_ip": { Type: schema.TypeList, MaxItems: 1, - Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "values": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validateCIDRNetworkAddress, + }, + Required: true, + Set: schema.HashString, + }, + }, + }, + }, + "values": { + Type: schema.TypeList, + MaxItems: 1, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(1, 128), + }, + Optional: true, + Computed: true, + Deprecated: "use 'host_header' or 'path_pattern' attribute instead", }, }, }, @@ -178,6 +425,92 @@ func resourceAwsLbbListenerRule() *schema.Resource { } } +/* DEPRECATED Backwards compatibility: This primarily exists to set a hash that handles the values to host_header or path_pattern migration. +Can probably be removed on the next major version of the provider. +*/ +func lbListenerRuleConditionSetHash(v interface{}) int { + if v == nil { + return 0 + } + + var field string + var buf strings.Builder + + m := v.(map[string]interface{}) + + if hostHeader, ok := m["host_header"].([]interface{}); ok && len(hostHeader) > 0 { + if hostHeader[0] != nil { + field = "host-header" + values := hostHeader[0].(map[string]interface{})["values"].(*schema.Set) + for _, l := range values.List() { + fmt.Fprint(&buf, l, "-") + } + } + } else if m["field"].(string) == "host-header" { + // Backwards compatibility + field = "host-header" + for _, l := range m["values"].([]interface{}) { + fmt.Fprint(&buf, l, "-") + } + } + + if httpHeader, ok := m["http_header"].([]interface{}); ok && len(httpHeader) > 0 && httpHeader[0] != nil { + field = "http-header" + httpHeaderMap := httpHeader[0].(map[string]interface{}) + fmt.Fprint(&buf, httpHeaderMap["http_header_name"].(string), ":") + httpHeaderValues := httpHeaderMap["values"].(*schema.Set) + for _, l := range httpHeaderValues.List() { + fmt.Fprint(&buf, l, "-") + } + } + + if httpRequestMethod, ok := m["http_request_method"].([]interface{}); ok && len(httpRequestMethod) > 0 && httpRequestMethod[0] != nil { + field = "http-request-method" + values := httpRequestMethod[0].(map[string]interface{})["values"].(*schema.Set) + for _, l := range values.List() { + fmt.Fprint(&buf, l, "-") + } + } + + if pathPattern, ok := m["path_pattern"].([]interface{}); ok && len(pathPattern) > 0 { + if pathPattern[0] != nil { + field = "path-pattern" + values := pathPattern[0].(map[string]interface{})["values"].(*schema.Set) + for _, l := range values.List() { + fmt.Fprint(&buf, l, "-") + } + } + } else if m["field"].(string) == "path-pattern" { + // Backwards compatibility + field = "path-pattern" + for _, l := range m["values"].([]interface{}) { + fmt.Fprint(&buf, l, "-") + } + } + + if queryString, ok := m["query_string"].(*schema.Set); ok && queryString.Len() > 0 { + field = "query-string" + for _, l := range queryString.List() { + fmt.Fprint(&buf, lbListenerRuleConditionQueryStringHash(l), "-") + } + } + + if sourceIp, ok := m["source_ip"].([]interface{}); ok && len(sourceIp) > 0 && sourceIp[0] != nil { + field = "source-ip" + values := sourceIp[0].(map[string]interface{})["values"].(*schema.Set) + for _, l := range values.List() { + fmt.Fprint(&buf, l, "-") + } + } + + return hashcode.String(fmt.Sprintf("%s-%s", field, buf.String())) +} + +func lbListenerRuleConditionQueryStringHash(v interface{}) int { + m := v.(map[string]interface{}) + return hashcode.String(fmt.Sprintf("%s-%s", m["key"], m["value"])) +} + func suppressIfActionTypeNot(t string) schema.SchemaDiffSuppressFunc { return func(k, old, new string, d *schema.ResourceData) bool { take := 2 @@ -250,18 +583,10 @@ func resourceAwsLbListenerRuleCreate(d *schema.ResourceData, meta interface{}) e params.Actions[i] = action } - conditions := d.Get("condition").(*schema.Set).List() - params.Conditions = make([]*elbv2.RuleCondition, len(conditions)) - for i, condition := range conditions { - conditionMap := condition.(map[string]interface{}) - values := conditionMap["values"].([]interface{}) - params.Conditions[i] = &elbv2.RuleCondition{ - Field: aws.String(conditionMap["field"].(string)), - Values: make([]*string, len(values)), - } - for j, value := range values { - params.Conditions[i].Values[j] = aws.String(value.(string)) - } + var err error + params.Conditions, err = lbListenerRuleConditions(d.Get("condition").(*schema.Set).List()) + if err != nil { + return err } var resp *elbv2.CreateRuleOutput @@ -378,15 +703,64 @@ func resourceAwsLbListenerRuleRead(d *schema.ResourceData, meta interface{}) err conditions := make([]interface{}, len(rule.Conditions)) for i, condition := range rule.Conditions { conditionMap := make(map[string]interface{}) + + // Deprecated: remove in next major version of provider conditionMap["field"] = aws.StringValue(condition.Field) - conditionValues := make([]string, len(condition.Values)) - for k, value := range condition.Values { - conditionValues[k] = aws.StringValue(value) + conditionMap["values"] = aws.StringValueSlice(condition.Values) + + switch conditionMap["field"] { + case "host-header": + conditionMap["host_header"] = []interface{}{ + map[string]interface{}{ + "values": flattenStringSet(condition.HostHeaderConfig.Values), + }, + } + + case "http-header": + conditionMap["http_header"] = []interface{}{ + map[string]interface{}{ + "http_header_name": aws.StringValue(condition.HttpHeaderConfig.HttpHeaderName), + "values": flattenStringSet(condition.HttpHeaderConfig.Values), + }, + } + + case "http-request-method": + conditionMap["http_request_method"] = []interface{}{ + map[string]interface{}{ + "values": flattenStringSet(condition.HttpRequestMethodConfig.Values), + }, + } + + case "path-pattern": + conditionMap["path_pattern"] = []interface{}{ + map[string]interface{}{ + "values": flattenStringSet(condition.PathPatternConfig.Values), + }, + } + + case "query-string": + values := make([]interface{}, len(condition.QueryStringConfig.Values)) + for k, value := range condition.QueryStringConfig.Values { + values[k] = map[string]interface{}{ + "key": aws.StringValue(value.Key), + "value": aws.StringValue(value.Value), + } + } + conditionMap["query_string"] = schema.NewSet(lbListenerRuleConditionQueryStringHash, values) + + case "source-ip": + conditionMap["source_ip"] = []interface{}{ + map[string]interface{}{ + "values": flattenStringSet(condition.SourceIpConfig.Values), + }, + } } - conditionMap["values"] = conditionValues + conditions[i] = conditionMap } - d.Set("condition", conditions) + if err := d.Set("condition", conditions); err != nil { + return fmt.Errorf("error setting condition: %s", err) + } return nil } @@ -473,18 +847,10 @@ func resourceAwsLbListenerRuleUpdate(d *schema.ResourceData, meta interface{}) e } if d.HasChange("condition") { - conditions := d.Get("condition").(*schema.Set).List() - params.Conditions = make([]*elbv2.RuleCondition, len(conditions)) - for i, condition := range conditions { - conditionMap := condition.(map[string]interface{}) - values := conditionMap["values"].([]interface{}) - params.Conditions[i] = &elbv2.RuleCondition{ - Field: aws.String(conditionMap["field"].(string)), - Values: make([]*string, len(values)), - } - for j, value := range values { - params.Conditions[i].Values[j] = aws.String(value.(string)) - } + var err error + params.Conditions, err = lbListenerRuleConditions(d.Get("condition").(*schema.Set).List()) + if err != nil { + return err } requestUpdate = true d.SetPartial("condition") @@ -577,3 +943,111 @@ func highestListenerRulePriority(conn *elbv2.ELBV2, arn string) (priority int64, return } + +// lbListenerRuleConditions converts data source generated by Terraform into +// an elbv2.RuleCondition object suitable for submitting to AWS API. +func lbListenerRuleConditions(conditions []interface{}) ([]*elbv2.RuleCondition, error) { + elbConditions := make([]*elbv2.RuleCondition, len(conditions)) + for i, condition := range conditions { + elbConditions[i] = &elbv2.RuleCondition{} + conditionMap := condition.(map[string]interface{}) + var field string + var attrs int + + if hostHeader, ok := conditionMap["host_header"].([]interface{}); ok && len(hostHeader) > 0 { + field = "host-header" + attrs += 1 + values := hostHeader[0].(map[string]interface{})["values"].(*schema.Set) + + elbConditions[i].HostHeaderConfig = &elbv2.HostHeaderConditionConfig{ + Values: expandStringSet(values), + } + } + + if httpHeader, ok := conditionMap["http_header"].([]interface{}); ok && len(httpHeader) > 0 { + field = "http-header" + attrs += 1 + httpHeaderMap := httpHeader[0].(map[string]interface{}) + values := httpHeaderMap["values"].(*schema.Set) + + elbConditions[i].HttpHeaderConfig = &elbv2.HttpHeaderConditionConfig{ + HttpHeaderName: aws.String(httpHeaderMap["http_header_name"].(string)), + Values: expandStringSet(values), + } + } + + if httpRequestMethod, ok := conditionMap["http_request_method"].([]interface{}); ok && len(httpRequestMethod) > 0 { + field = "http-request-method" + attrs += 1 + values := httpRequestMethod[0].(map[string]interface{})["values"].(*schema.Set) + + elbConditions[i].HttpRequestMethodConfig = &elbv2.HttpRequestMethodConditionConfig{ + Values: expandStringSet(values), + } + } + + if pathPattern, ok := conditionMap["path_pattern"].([]interface{}); ok && len(pathPattern) > 0 { + field = "path-pattern" + attrs += 1 + values := pathPattern[0].(map[string]interface{})["values"].(*schema.Set) + + elbConditions[i].PathPatternConfig = &elbv2.PathPatternConditionConfig{ + Values: expandStringSet(values), + } + } + + if queryString, ok := conditionMap["query_string"].(*schema.Set); ok && queryString.Len() > 0 { + field = "query-string" + attrs += 1 + values := queryString.List() + + elbConditions[i].QueryStringConfig = &elbv2.QueryStringConditionConfig{ + Values: make([]*elbv2.QueryStringKeyValuePair, len(values)), + } + for j, p := range values { + valuePair := p.(map[string]interface{}) + elbValuePair := &elbv2.QueryStringKeyValuePair{ + Value: aws.String(valuePair["value"].(string)), + } + if valuePair["key"].(string) != "" { + elbValuePair.Key = aws.String(valuePair["key"].(string)) + } + elbConditions[i].QueryStringConfig.Values[j] = elbValuePair + } + } + + if sourceIp, ok := conditionMap["source_ip"].([]interface{}); ok && len(sourceIp) > 0 { + field = "source-ip" + attrs += 1 + values := sourceIp[0].(map[string]interface{})["values"].(*schema.Set) + + elbConditions[i].SourceIpConfig = &elbv2.SourceIpConditionConfig{ + Values: expandStringSet(values), + } + } + + // Deprecated backwards compatibility + if cmField, ok := conditionMap["field"].(string); ok && cmField != "" { + field = cmField + attrs += 1 + values := conditionMap["values"].([]interface{}) + if len(values) == 0 { + return nil, errors.New("Both field and values must be set in a condition block") + } + elbConditions[i].Values = expandStringList(values) + } + + // FIXME Rework this and use ConflictsWith when it finally works with collections: + // https://github.com/hashicorp/terraform/issues/13016 + // Still need to ensure that one of the condition attributes is set. + if attrs == 0 { + return nil, errors.New("One of host_header, http_header, http_request_method, path_pattern, query_string or source_ip must be set in a condition block") + } else if attrs > 1 { + // Deprecated: remove `field` from message + return nil, errors.New("Only one of field, host_header, http_header, http_request_method, path_pattern, query_string or source_ip can be set in a condition block") + } + + elbConditions[i].Field = aws.String(field) + } + return elbConditions, nil +} diff --git a/aws/resource_aws_lb_listener_rule_test.go b/aws/resource_aws_lb_listener_rule_test.go index e9850740fcee..4a147cea8587 100644 --- a/aws/resource_aws_lb_listener_rule_test.go +++ b/aws/resource_aws_lb_listener_rule_test.go @@ -77,10 +77,18 @@ func TestAccAWSLBListenerRule_basic(t *testing.T) { resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "action.0.target_group_arn"), resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.0.redirect.#", "0"), resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.0.fixed_response.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.0.authenticate_cognito.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.0.authenticate_oidc.#", "0"), resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.#", "1"), - resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1366281676.field", "path-pattern"), - resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1366281676.values.#", "1"), - resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "condition.1366281676.values.0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.447032695.field", "path-pattern"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.447032695.host_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.447032695.http_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.447032695.http_request_method.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.447032695.path_pattern.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.447032695.query_string.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.447032695.source_ip.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.447032695.values.#", "1"), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "condition.447032695.values.0"), ), }, }, @@ -110,10 +118,18 @@ func TestAccAWSLBListenerRuleBackwardsCompatibility(t *testing.T) { resource.TestCheckResourceAttrSet("aws_alb_listener_rule.static", "action.0.target_group_arn"), resource.TestCheckResourceAttr("aws_alb_listener_rule.static", "action.0.redirect.#", "0"), resource.TestCheckResourceAttr("aws_alb_listener_rule.static", "action.0.fixed_response.#", "0"), + resource.TestCheckResourceAttr("aws_alb_listener_rule.static", "action.0.authenticate_cognito.#", "0"), + resource.TestCheckResourceAttr("aws_alb_listener_rule.static", "action.0.authenticate_oidc.#", "0"), resource.TestCheckResourceAttr("aws_alb_listener_rule.static", "condition.#", "1"), - resource.TestCheckResourceAttr("aws_alb_listener_rule.static", "condition.1366281676.field", "path-pattern"), - resource.TestCheckResourceAttr("aws_alb_listener_rule.static", "condition.1366281676.values.#", "1"), - resource.TestCheckResourceAttrSet("aws_alb_listener_rule.static", "condition.1366281676.values.0"), + resource.TestCheckResourceAttr("aws_alb_listener_rule.static", "condition.447032695.field", "path-pattern"), + resource.TestCheckResourceAttr("aws_alb_listener_rule.static", "condition.447032695.host_header.#", "0"), + resource.TestCheckResourceAttr("aws_alb_listener_rule.static", "condition.447032695.http_header.#", "0"), + resource.TestCheckResourceAttr("aws_alb_listener_rule.static", "condition.447032695.http_request_method.#", "0"), + resource.TestCheckResourceAttr("aws_alb_listener_rule.static", "condition.447032695.path_pattern.#", "1"), + resource.TestCheckResourceAttr("aws_alb_listener_rule.static", "condition.447032695.query_string.#", "0"), + resource.TestCheckResourceAttr("aws_alb_listener_rule.static", "condition.447032695.source_ip.#", "0"), + resource.TestCheckResourceAttr("aws_alb_listener_rule.static", "condition.447032695.values.#", "1"), + resource.TestCheckResourceAttrSet("aws_alb_listener_rule.static", "condition.447032695.values.0"), ), }, }, @@ -148,10 +164,9 @@ func TestAccAWSLBListenerRule_redirect(t *testing.T) { resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.0.redirect.0.query", "#{query}"), resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.0.redirect.0.status_code", "HTTP_301"), resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.0.fixed_response.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.0.authenticate_cognito.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.0.authenticate_oidc.#", "0"), resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.#", "1"), - resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1366281676.field", "path-pattern"), - resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1366281676.values.#", "1"), - resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "condition.1366281676.values.0"), ), }, }, @@ -183,10 +198,9 @@ func TestAccAWSLBListenerRule_fixedResponse(t *testing.T) { resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.0.fixed_response.0.content_type", "text/plain"), resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.0.fixed_response.0.message_body", "Fixed response content"), resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.0.fixed_response.0.status_code", "200"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.0.authenticate_cognito.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.0.authenticate_oidc.#", "0"), resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.#", "1"), - resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1366281676.field", "path-pattern"), - resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1366281676.values.#", "1"), - resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "condition.1366281676.values.0"), ), }, }, @@ -341,6 +355,625 @@ func TestAccAWSLBListenerRule_priority(t *testing.T) { }) } +<<<<<<< HEAD +======= +func TestAccAWSLBListenerRule_cognito(t *testing.T) { + var conf elbv2.Rule + key := tlsRsaPrivateKeyPem(2048) + certificate := tlsRsaX509SelfSignedCertificatePem(key, "example.com") + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: "aws_lb_listener_rule.cognito", + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBListenerRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBListenerRuleConfig_cognito(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBListenerRuleExists("aws_lb_listener_rule.cognito", &conf), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.cognito", "arn"), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.cognito", "listener_arn"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.cognito", "priority", "100"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.cognito", "action.#", "2"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.cognito", "action.0.order", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.cognito", "action.0.type", "authenticate-cognito"), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.cognito", "action.0.authenticate_cognito.0.user_pool_arn"), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.cognito", "action.0.authenticate_cognito.0.user_pool_client_id"), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.cognito", "action.0.authenticate_cognito.0.user_pool_domain"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.cognito", "action.0.authenticate_cognito.0.authentication_request_extra_params.%", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.cognito", "action.0.authenticate_cognito.0.authentication_request_extra_params.param", "test"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.cognito", "action.1.order", "2"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.cognito", "action.1.type", "forward"), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.cognito", "action.1.target_group_arn"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.cognito", "condition.#", "1"), + ), + }, + }, + }) +} + +func TestAccAWSLBListenerRule_oidc(t *testing.T) { + var conf elbv2.Rule + key := tlsRsaPrivateKeyPem(2048) + certificate := tlsRsaX509SelfSignedCertificatePem(key, "example.com") + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: "aws_lb_listener_rule.oidc", + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBListenerRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBListenerRuleConfig_oidc(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBListenerRuleExists("aws_lb_listener_rule.oidc", &conf), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.oidc", "arn"), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.oidc", "listener_arn"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.oidc", "priority", "100"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.oidc", "action.#", "2"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.oidc", "action.0.order", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.oidc", "action.0.type", "authenticate-oidc"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.oidc", "action.0.authenticate_oidc.0.authorization_endpoint", "https://example.com/authorization_endpoint"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.oidc", "action.0.authenticate_oidc.0.client_id", "s6BhdRkqt3"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.oidc", "action.0.authenticate_oidc.0.client_secret", "7Fjfp0ZBr1KtDRbnfVdmIw"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.oidc", "action.0.authenticate_oidc.0.issuer", "https://example.com"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.oidc", "action.0.authenticate_oidc.0.token_endpoint", "https://example.com/token_endpoint"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.oidc", "action.0.authenticate_oidc.0.user_info_endpoint", "https://example.com/user_info_endpoint"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.oidc", "action.0.authenticate_oidc.0.authentication_request_extra_params.%", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.oidc", "action.0.authenticate_oidc.0.authentication_request_extra_params.param", "test"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.oidc", "action.1.order", "2"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.oidc", "action.1.type", "forward"), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.oidc", "action.1.target_group_arn"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.oidc", "condition.#", "1"), + ), + }, + }, + }) +} + +func TestAccAWSLBListenerRule_Action_Order(t *testing.T) { + var rule elbv2.Rule + key := tlsRsaPrivateKeyPem(2048) + certificate := tlsRsaX509SelfSignedCertificatePem(key, "example.com") + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lb_listener_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBListenerRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBListenerRuleConfig_Action_Order(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBListenerRuleExists(resourceName, &rule), + resource.TestCheckResourceAttr(resourceName, "action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "action.0.order", "1"), + resource.TestCheckResourceAttr(resourceName, "action.1.order", "2"), + ), + }, + }, + }) +} + +// Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/6171 +func TestAccAWSLBListenerRule_Action_Order_Recreates(t *testing.T) { + var rule elbv2.Rule + key := tlsRsaPrivateKeyPem(2048) + certificate := tlsRsaX509SelfSignedCertificatePem(key, "example.com") + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lb_listener_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBListenerRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBListenerRuleConfig_Action_Order(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBListenerRuleExists(resourceName, &rule), + resource.TestCheckResourceAttr(resourceName, "action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "action.0.order", "1"), + resource.TestCheckResourceAttr(resourceName, "action.1.order", "2"), + testAccCheckAWSLBListenerRuleActionOrderDisappears(&rule, 1), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSLBListenerRule_conditionAttributesCount(t *testing.T) { + err_zero := regexp.MustCompile("One of host_header, http_header, http_request_method, path_pattern, query_string or source_ip must be set in a condition block") + err_many := regexp.MustCompile("Only one of field, host_header, http_header, http_request_method, path_pattern, query_string or source_ip can be set in a condition block") + err_deprecated := regexp.MustCompile("Both field and values must be set in a condition block") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBListenerRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBListenerRuleConfig_conditionAttributesCount_empty(), + ExpectError: err_zero, + }, + { + Config: testAccAWSLBListenerRuleConfig_conditionAttributesCount_field(), + ExpectError: err_deprecated, + }, + { + Config: testAccAWSLBListenerRuleConfig_conditionAttributesCount_values(), + ExpectError: err_zero, + }, + { + Config: testAccAWSLBListenerRuleConfig_conditionAttributesCount_http_header(), + ExpectError: err_many, + }, + { + Config: testAccAWSLBListenerRuleConfig_conditionAttributesCount_http_request_method(), + ExpectError: err_many, + }, + { + Config: testAccAWSLBListenerRuleConfig_conditionAttributesCount_path_pattern(), + ExpectError: err_many, + }, + { + Config: testAccAWSLBListenerRuleConfig_conditionAttributesCount_query_string(), + ExpectError: err_many, + }, + { + Config: testAccAWSLBListenerRuleConfig_conditionAttributesCount_source_ip(), + ExpectError: err_many, + }, + { + Config: testAccAWSLBListenerRuleConfig_conditionAttributesCount_classic(), + ExpectError: err_many, + }, + }, + }) +} + +func TestAccAWSLBListenerRule_conditionHostHeader(t *testing.T) { + var conf elbv2.Rule + lbName := fmt.Sprintf("testrule-hostHeader-%s", acctest.RandStringFromCharSet(12, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: "aws_lb_listener_rule.static", + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBListenerRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBListenerRuleConfig_conditionHostHeader(lbName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBListenerRuleExists("aws_lb_listener_rule.static", &conf), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "arn"), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "listener_arn"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "priority", "100"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1089289132.field", "host-header"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1089289132.host_header.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1089289132.host_header.0.values.#", "2"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1089289132.host_header.0.values.3069857465", "example.com"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1089289132.host_header.0.values.785793723", "www.example.com"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1089289132.http_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1089289132.http_request_method.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1089289132.path_pattern.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1089289132.query_string.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1089289132.source_ip.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1089289132.values.#", "2"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1089289132.values.0", "example.com"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1089289132.values.1", "www.example.com"), + ), + }, + }, + }) +} + +func TestAccAWSLBListenerRule_conditionHostHeader_deprecated(t *testing.T) { + var conf elbv2.Rule + lbName := fmt.Sprintf("testrule-hostHeader-%s", acctest.RandStringFromCharSet(12, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: "aws_lb_listener_rule.static", + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBListenerRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBListenerRuleConfig_conditionHostHeader_deprecated(lbName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBListenerRuleExists("aws_lb_listener_rule.static", &conf), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "arn"), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "listener_arn"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "priority", "100"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.field", "host-header"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.host_header.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.host_header.0.values.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.host_header.0.values.3069857465", "example.com"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.http_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.http_request_method.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.path_pattern.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.query_string.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.source_ip.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.values.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.values.0", "example.com"), + ), + }, + }, + }) +} + +func TestAccAWSLBListenerRule_conditionHttpHeader(t *testing.T) { + var conf elbv2.Rule + lbName := fmt.Sprintf("testrule-httpHeader-%s", acctest.RandStringFromCharSet(12, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: "aws_lb_listener_rule.static", + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBListenerRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBListenerRuleConfig_conditionHttpHeader(lbName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBListenerRuleExists("aws_lb_listener_rule.static", &conf), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "arn"), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "listener_arn"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "priority", "100"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.#", "2"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.168627567.field", "http-header"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.168627567.host_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.168627567.http_header.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.168627567.http_header.0.http_header_name", "X-Forwarded-For"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.168627567.http_header.0.values.#", "2"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.168627567.http_header.0.values.2895841407", "10.0.0.*"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.168627567.http_header.0.values.35666611", "192.168.1.*"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.168627567.http_request_method.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.168627567.path_pattern.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.168627567.query_string.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.168627567.source_ip.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.168627567.values.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4090220723.field", "http-header"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4090220723.host_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4090220723.http_header.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4090220723.http_header.0.http_header_name", "Zz9~|_^.-+*'&%$#!0aA"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4090220723.http_header.0.values.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4090220723.http_header.0.values.1801271041", "RFC7230 Validity"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4090220723.http_request_method.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4090220723.path_pattern.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4090220723.query_string.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4090220723.source_ip.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4090220723.values.#", "0"), + ), + }, + }, + }) +} + +func TestAccAWSLBListenerRule_conditionHttpHeader_invalid(t *testing.T) { + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBListenerRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBListenerRuleConfig_conditionHttpHeader_invalid(), + ExpectError: regexp.MustCompile(`expected value of condition.0.http_header.0.http_header_name to match regular expression`), + }, + }, + }) +} + +func TestAccAWSLBListenerRule_conditionHttpRequestMethod(t *testing.T) { + var conf elbv2.Rule + lbName := fmt.Sprintf("testrule-httpRequest-%s", acctest.RandStringFromCharSet(11, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: "aws_lb_listener_rule.static", + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBListenerRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBListenerRuleConfig_conditionHttpRequestMethod(lbName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBListenerRuleExists("aws_lb_listener_rule.static", &conf), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "arn"), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "listener_arn"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "priority", "100"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2223521492.field", "http-request-method"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2223521492.host_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2223521492.http_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2223521492.http_request_method.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2223521492.http_request_method.0.values.#", "2"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2223521492.http_request_method.0.values.1805413626", "GET"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2223521492.http_request_method.0.values.1814004025", "POST"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2223521492.path_pattern.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2223521492.query_string.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2223521492.source_ip.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2223521492.values.#", "0"), + ), + }, + }, + }) +} + +func TestAccAWSLBListenerRule_conditionPathPattern(t *testing.T) { + var conf elbv2.Rule + lbName := fmt.Sprintf("testrule-pathPattern-%s", acctest.RandStringFromCharSet(11, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: "aws_lb_listener_rule.static", + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBListenerRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBListenerRuleConfig_conditionPathPattern(lbName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBListenerRuleExists("aws_lb_listener_rule.static", &conf), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "arn"), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "listener_arn"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "priority", "100"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2177156802.field", "path-pattern"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2177156802.host_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2177156802.http_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2177156802.http_request_method.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2177156802.path_pattern.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2177156802.path_pattern.0.values.#", "2"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2177156802.path_pattern.0.values.1764929539", "/cgi-bin/*"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2177156802.path_pattern.0.values.1973895062", "/public/*"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2177156802.query_string.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2177156802.source_ip.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2177156802.values.#", "2"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2177156802.values.0", "/cgi-bin/*"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2177156802.values.1", "/public/*"), + ), + }, + }, + }) +} + +func TestAccAWSLBListenerRule_conditionPathPattern_deprecated(t *testing.T) { + var conf elbv2.Rule + lbName := fmt.Sprintf("testrule-pathPattern-%s", acctest.RandStringFromCharSet(11, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: "aws_lb_listener_rule.static", + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBListenerRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBListenerRuleConfig_conditionPathPattern_deprecated(lbName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBListenerRuleExists("aws_lb_listener_rule.static", &conf), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "arn"), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "listener_arn"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "priority", "100"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.field", "path-pattern"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.host_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.http_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.http_request_method.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.path_pattern.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.path_pattern.0.values.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.path_pattern.0.values.1973895062", "/public/*"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.query_string.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.source_ip.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.values.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.values.0", "/public/*"), + ), + }, + }, + }) +} + +func TestAccAWSLBListenerRule_conditionQueryString(t *testing.T) { + var conf elbv2.Rule + lbName := fmt.Sprintf("testrule-queryString-%s", acctest.RandStringFromCharSet(11, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: "aws_lb_listener_rule.static", + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBListenerRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBListenerRuleConfig_conditionQueryString(lbName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBListenerRuleExists("aws_lb_listener_rule.static", &conf), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "arn"), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "listener_arn"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "priority", "100"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.#", "2"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1697057359.field", "query-string"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1697057359.host_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1697057359.http_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1697057359.http_request_method.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1697057359.path_pattern.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1697057359.query_string.#", "2"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1697057359.query_string.167408634.key", ""), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1697057359.query_string.167408634.value", "surprise"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1697057359.query_string.4042884147.key", ""), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1697057359.query_string.4042884147.value", "blank"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1697057359.source_ip.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.1697057359.values.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.863121889.field", "query-string"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.863121889.host_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.863121889.http_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.863121889.http_request_method.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.863121889.path_pattern.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.863121889.query_string.#", "2"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.863121889.query_string.1123504603.key", "foo"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.863121889.query_string.1123504603.value", "baz"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.863121889.query_string.1278007785.key", "foo"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.863121889.query_string.1278007785.value", "bar"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.863121889.source_ip.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.863121889.values.#", "0"), + ), + }, + }, + }) +} + +func TestAccAWSLBListenerRule_conditionSourceIp(t *testing.T) { + var conf elbv2.Rule + lbName := fmt.Sprintf("testrule-sourceIp-%s", acctest.RandStringFromCharSet(14, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: "aws_lb_listener_rule.static", + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBListenerRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBListenerRuleConfig_conditionSourceIp(lbName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBListenerRuleExists("aws_lb_listener_rule.static", &conf), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "arn"), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "listener_arn"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "priority", "100"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.3009583077.field", "source-ip"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.3009583077.host_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.3009583077.http_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.3009583077.http_request_method.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.3009583077.path_pattern.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.3009583077.query_string.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.3009583077.source_ip.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.3009583077.source_ip.0.values.#", "2"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.3009583077.source_ip.0.values.1567875353", "dead:cafe::/64"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.3009583077.source_ip.0.values.3901788224", "192.168.0.0/16"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.3009583077.values.#", "0"), + ), + }, + }, + }) +} + +func TestAccAWSLBListenerRule_conditionMultiple(t *testing.T) { + var conf elbv2.Rule + lbName := fmt.Sprintf("testrule-condMulti-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: "aws_lb_listener_rule.static", + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBListenerRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBListenerRuleConfig_conditionMultiple(lbName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBListenerRuleExists("aws_lb_listener_rule.static", &conf), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "arn"), + resource.TestCheckResourceAttrSet("aws_lb_listener_rule.static", "listener_arn"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "priority", "100"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "action.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.#", "5"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.139999317.field", "http-header"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.139999317.host_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.139999317.http_header.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.139999317.http_header.0.http_header_name", "X-Forwarded-For"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.139999317.http_header.0.values.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.139999317.http_header.0.values.35666611", "192.168.1.*"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.139999317.http_request_method.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.139999317.path_pattern.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.139999317.query_string.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.139999317.source_ip.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.139999317.values.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2986919393.field", "source-ip"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2986919393.host_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2986919393.http_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2986919393.http_request_method.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2986919393.path_pattern.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2986919393.query_string.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2986919393.source_ip.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2986919393.source_ip.0.values.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2986919393.source_ip.0.values.3901788224", "192.168.0.0/16"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.2986919393.values.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4038921246.field", "http-request-method"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4038921246.host_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4038921246.http_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4038921246.http_request_method.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4038921246.http_request_method.0.values.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4038921246.http_request_method.0.values.1805413626", "GET"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4038921246.path_pattern.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4038921246.query_string.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4038921246.source_ip.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.4038921246.values.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.field", "path-pattern"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.host_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.http_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.http_request_method.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.path_pattern.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.path_pattern.0.values.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.path_pattern.0.values.1973895062", "/public/*"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.query_string.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.source_ip.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.values.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.837782343.values.0", "/public/*"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.field", "host-header"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.host_header.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.host_header.0.values.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.host_header.0.values.3069857465", "example.com"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.http_header.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.http_request_method.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.path_pattern.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.query_string.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.source_ip.#", "0"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.values.#", "1"), + resource.TestCheckResourceAttr("aws_lb_listener_rule.static", "condition.887624213.values.0", "example.com"), + ), + }, + }, + }) +} + +func testAccCheckAWSLBListenerRuleActionOrderDisappears(rule *elbv2.Rule, actionOrderToDelete int) resource.TestCheckFunc { + return func(s *terraform.State) error { + var newActions []*elbv2.Action + + for i, action := range rule.Actions { + if int(aws.Int64Value(action.Order)) == actionOrderToDelete { + newActions = append(rule.Actions[:i], rule.Actions[i+1:]...) + break + } + } + + if len(newActions) == 0 { + return fmt.Errorf("Unable to find action order %d from actions: %#v", actionOrderToDelete, rule.Actions) + } + + conn := testAccProvider.Meta().(*AWSClient).elbv2conn + + input := &elbv2.ModifyRuleInput{ + Actions: newActions, + RuleArn: rule.RuleArn, + } + + _, err := conn.ModifyRule(input) + + return err + } +} + func testAccCheckAWSLbListenerRuleRecreated(t *testing.T, before, after *elbv2.Rule) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -351,71 +984,607 @@ func testAccCheckAWSLbListenerRuleRecreated(t *testing.T, } } -func testAccCheckAWSLBListenerRuleExists(n string, res *elbv2.Rule) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if !ok { - return fmt.Errorf("Not found: %s", n) - } +func testAccCheckAWSLBListenerRuleExists(n string, res *elbv2.Rule) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No Listener Rule ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).elbv2conn + + describe, err := conn.DescribeRules(&elbv2.DescribeRulesInput{ + RuleArns: []*string{aws.String(rs.Primary.ID)}, + }) + + if err != nil { + return err + } + + if len(describe.Rules) != 1 || + *describe.Rules[0].RuleArn != rs.Primary.ID { + return errors.New("Listener Rule not found") + } + + *res = *describe.Rules[0] + return nil + } +} + +func testAccCheckAWSLBListenerRuleDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).elbv2conn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_lb_listener_rule" && rs.Type != "aws_alb_listener_rule" { + continue + } + + describe, err := conn.DescribeRules(&elbv2.DescribeRulesInput{ + RuleArns: []*string{aws.String(rs.Primary.ID)}, + }) + + if err == nil { + if len(describe.Rules) != 0 && + *describe.Rules[0].RuleArn == rs.Primary.ID { + return fmt.Errorf("Listener Rule %q still exists", rs.Primary.ID) + } + } + + // Verify the error + if isAWSErr(err, elbv2.ErrCodeRuleNotFoundException, "") { + return nil + } else { + return fmt.Errorf("Unexpected error checking LB Listener Rule destroyed: %s", err) + } + } + + return nil +} + +func testAccAWSLBListenerRuleConfig_multipleConditions(lbName, targetGroupName string) string { + return fmt.Sprintf(`resource "aws_lb_listener_rule" "static" { + listener_arn = "${aws_lb_listener.front_end.arn}" + priority = 100 + + action { + type = "forward" + target_group_arn = "${aws_lb_target_group.test.arn}" + } + + condition { + field = "path-pattern" + values = ["/static/*", "static"] + } +} + +resource "aws_lb_listener" "front_end" { + load_balancer_arn = "${aws_lb.alb_test.id}" + protocol = "HTTP" + port = "80" + + default_action { + target_group_arn = "${aws_lb_target_group.test.id}" + type = "forward" + } +} + +resource "aws_lb" "alb_test" { + name = "%s" + internal = true + security_groups = ["${aws_security_group.alb_test.id}"] + subnets = ["${aws_subnet.alb_test.*.id}"] + + idle_timeout = 30 + enable_deletion_protection = false + + tags { + Name = "TestAccAWSALB_basic" + } +} + +resource "aws_lb_target_group" "test" { + name = "%s" + port = 8080 + protocol = "HTTP" + vpc_id = "${aws_vpc.alb_test.id}" + + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" + } +} + +variable "subnets" { + default = ["10.0.1.0/24", "10.0.2.0/24"] + type = "list" +} + +data "aws_availability_zones" "available" {} + +resource "aws_vpc" "alb_test" { + cidr_block = "10.0.0.0/16" + + tags { + Name = "terraform-testacc-lb-listener-rule-multiple-conditions" + } +} + +resource "aws_subnet" "alb_test" { + count = 2 + vpc_id = "${aws_vpc.alb_test.id}" + cidr_block = "${element(var.subnets, count.index)}" + map_public_ip_on_launch = true + availability_zone = "${element(data.aws_availability_zones.available.names, count.index)}" + + tags { + Name = "tf-acc-lb-listener-rule-multiple-conditions-${count.index}" + } +} + +resource "aws_security_group" "alb_test" { + name = "allow_all_alb_test" + description = "Used for ALB Testing" + vpc_id = "${aws_vpc.alb_test.id}" + + ingress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags { + Name = "TestAccAWSALB_basic" + } +}`, lbName, targetGroupName) +} + +func testAccAWSLBListenerRuleConfig_basic(lbName, targetGroupName string) string { + return fmt.Sprintf(`resource "aws_lb_listener_rule" "static" { + listener_arn = "${aws_lb_listener.front_end.arn}" + priority = 100 + + action { + type = "forward" + target_group_arn = "${aws_lb_target_group.test.arn}" + } + + condition { + field = "path-pattern" + values = ["/static/*"] + } +} + +resource "aws_lb_listener" "front_end" { + load_balancer_arn = "${aws_lb.alb_test.id}" + protocol = "HTTP" + port = "80" + + default_action { + target_group_arn = "${aws_lb_target_group.test.id}" + type = "forward" + } +} + +resource "aws_lb" "alb_test" { + name = "%s" + internal = true + security_groups = ["${aws_security_group.alb_test.id}"] + subnets = ["${aws_subnet.alb_test.*.id}"] + + idle_timeout = 30 + enable_deletion_protection = false + + tags { + Name = "TestAccAWSALB_basic" + } +} + +resource "aws_lb_target_group" "test" { + name = "%s" + port = 8080 + protocol = "HTTP" + vpc_id = "${aws_vpc.alb_test.id}" + + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" + } +} + +variable "subnets" { + default = ["10.0.1.0/24", "10.0.2.0/24"] + type = "list" +} + +data "aws_availability_zones" "available" {} + +resource "aws_vpc" "alb_test" { + cidr_block = "10.0.0.0/16" + + tags { + Name = "terraform-testacc-lb-listener-rule-basic" + } +} + +resource "aws_subnet" "alb_test" { + count = 2 + vpc_id = "${aws_vpc.alb_test.id}" + cidr_block = "${element(var.subnets, count.index)}" + map_public_ip_on_launch = true + availability_zone = "${element(data.aws_availability_zones.available.names, count.index)}" + + tags { + Name = "tf-acc-lb-listener-rule-basic-${count.index}" + } +} + +resource "aws_security_group" "alb_test" { + name = "allow_all_alb_test" + description = "Used for ALB Testing" + vpc_id = "${aws_vpc.alb_test.id}" + + ingress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags { + Name = "TestAccAWSALB_basic" + } +}`, lbName, targetGroupName) +} + +func testAccAWSLBListenerRuleConfigBackwardsCompatibility(lbName, targetGroupName string) string { + return fmt.Sprintf(`resource "aws_alb_listener_rule" "static" { + listener_arn = "${aws_alb_listener.front_end.arn}" + priority = 100 + + action { + type = "forward" + target_group_arn = "${aws_alb_target_group.test.arn}" + } + + condition { + field = "path-pattern" + values = ["/static/*"] + } +} + +resource "aws_alb_listener" "front_end" { + load_balancer_arn = "${aws_alb.alb_test.id}" + protocol = "HTTP" + port = "80" + + default_action { + target_group_arn = "${aws_alb_target_group.test.id}" + type = "forward" + } +} + +resource "aws_alb" "alb_test" { + name = "%s" + internal = true + security_groups = ["${aws_security_group.alb_test.id}"] + subnets = ["${aws_subnet.alb_test.*.id}"] + + idle_timeout = 30 + enable_deletion_protection = false + + tags { + Name = "TestAccAWSALB_basic" + } +} + +resource "aws_alb_target_group" "test" { + name = "%s" + port = 8080 + protocol = "HTTP" + vpc_id = "${aws_vpc.alb_test.id}" + + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" + } +} + +variable "subnets" { + default = ["10.0.1.0/24", "10.0.2.0/24"] + type = "list" +} + +data "aws_availability_zones" "available" {} + +resource "aws_vpc" "alb_test" { + cidr_block = "10.0.0.0/16" + + tags { + Name = "terraform-testacc-lb-listener-rule-bc" + } +} + +resource "aws_subnet" "alb_test" { + count = 2 + vpc_id = "${aws_vpc.alb_test.id}" + cidr_block = "${element(var.subnets, count.index)}" + map_public_ip_on_launch = true + availability_zone = "${element(data.aws_availability_zones.available.names, count.index)}" + + tags { + Name = "tf-acc-lb-listener-rule-bc-${count.index}" + } +} + +resource "aws_security_group" "alb_test" { + name = "allow_all_alb_test" + description = "Used for ALB Testing" + vpc_id = "${aws_vpc.alb_test.id}" + + ingress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags { + Name = "TestAccAWSALB_basic" + } +}`, lbName, targetGroupName) +} + +func testAccAWSLBListenerRuleConfig_redirect(lbName string) string { + return fmt.Sprintf(`resource "aws_lb_listener_rule" "static" { + listener_arn = "${aws_lb_listener.front_end.arn}" + priority = 100 + + action { + type = "redirect" + redirect { + port = "443" + protocol = "HTTPS" + status_code = "HTTP_301" + } + } + + condition { + field = "path-pattern" + values = ["/static/*"] + } +} + +resource "aws_lb_listener" "front_end" { + load_balancer_arn = "${aws_lb.alb_test.id}" + protocol = "HTTP" + port = "80" + + default_action { + type = "redirect" + redirect { + port = "443" + protocol = "HTTPS" + status_code = "HTTP_301" + } + } +} + +resource "aws_lb" "alb_test" { + name = "%s" + internal = true + security_groups = ["${aws_security_group.alb_test.id}"] + subnets = ["${aws_subnet.alb_test.*.id}"] + + idle_timeout = 30 + enable_deletion_protection = false + + tags { + Name = "TestAccAWSALB_redirect" + } +} + +variable "subnets" { + default = ["10.0.1.0/24", "10.0.2.0/24"] + type = "list" +} + +data "aws_availability_zones" "available" {} + +resource "aws_vpc" "alb_test" { + cidr_block = "10.0.0.0/16" + + tags { + Name = "terraform-testacc-lb-listener-rule-redirect" + } +} + +resource "aws_subnet" "alb_test" { + count = 2 + vpc_id = "${aws_vpc.alb_test.id}" + cidr_block = "${element(var.subnets, count.index)}" + map_public_ip_on_launch = true + availability_zone = "${element(data.aws_availability_zones.available.names, count.index)}" + + tags { + Name = "tf-acc-lb-listener-rule-redirect-${count.index}" + } +} + +resource "aws_security_group" "alb_test" { + name = "allow_all_alb_test" + description = "Used for ALB Testing" + vpc_id = "${aws_vpc.alb_test.id}" + + ingress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags { + Name = "TestAccAWSALB_redirect" + } +}`, lbName) +} + +func testAccAWSLBListenerRuleConfig_fixedResponse(lbName string) string { + return fmt.Sprintf(`resource "aws_lb_listener_rule" "static" { + listener_arn = "${aws_lb_listener.front_end.arn}" + priority = 100 + + action { + type = "fixed-response" + fixed_response { + content_type = "text/plain" + message_body = "Fixed response content" + status_code = "200" + } + } + + condition { + field = "path-pattern" + values = ["/static/*"] + } +} + +resource "aws_lb_listener" "front_end" { + load_balancer_arn = "${aws_lb.alb_test.id}" + protocol = "HTTP" + port = "80" + + default_action { + type = "fixed-response" + fixed_response { + content_type = "text/plain" + message_body = "Fixed response content" + status_code = "200" + } + } +} + +resource "aws_lb" "alb_test" { + name = "%s" + internal = true + security_groups = ["${aws_security_group.alb_test.id}"] + subnets = ["${aws_subnet.alb_test.*.id}"] - if rs.Primary.ID == "" { - return errors.New("No Listener Rule ID is set") - } + idle_timeout = 30 + enable_deletion_protection = false - conn := testAccProvider.Meta().(*AWSClient).elbv2conn + tags { + Name = "TestAccAWSALB_fixedResponse" + } +} - describe, err := conn.DescribeRules(&elbv2.DescribeRulesInput{ - RuleArns: []*string{aws.String(rs.Primary.ID)}, - }) +variable "subnets" { + default = ["10.0.1.0/24", "10.0.2.0/24"] + type = "list" +} - if err != nil { - return err - } +data "aws_availability_zones" "available" {} - if len(describe.Rules) != 1 || - *describe.Rules[0].RuleArn != rs.Primary.ID { - return errors.New("Listener Rule not found") - } +resource "aws_vpc" "alb_test" { + cidr_block = "10.0.0.0/16" - *res = *describe.Rules[0] - return nil - } + tags { + Name = "terraform-testacc-lb-listener-rule-fixedresponse" + } } -func testAccCheckAWSLBListenerRuleDestroy(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).elbv2conn +resource "aws_subnet" "alb_test" { + count = 2 + vpc_id = "${aws_vpc.alb_test.id}" + cidr_block = "${element(var.subnets, count.index)}" + map_public_ip_on_launch = true + availability_zone = "${element(data.aws_availability_zones.available.names, count.index)}" - for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_lb_listener_rule" && rs.Type != "aws_alb_listener_rule" { - continue - } + tags { + Name = "tf-acc-lb-listener-rule-fixedresponse-${count.index}" + } +} - describe, err := conn.DescribeRules(&elbv2.DescribeRulesInput{ - RuleArns: []*string{aws.String(rs.Primary.ID)}, - }) +resource "aws_security_group" "alb_test" { + name = "allow_all_alb_test" + description = "Used for ALB Testing" + vpc_id = "${aws_vpc.alb_test.id}" - if err == nil { - if len(describe.Rules) != 0 && - *describe.Rules[0].RuleArn == rs.Primary.ID { - return fmt.Errorf("Listener Rule %q still exists", rs.Primary.ID) - } - } + ingress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } - // Verify the error - if isAWSErr(err, elbv2.ErrCodeRuleNotFoundException, "") { - return nil - } else { - return fmt.Errorf("Unexpected error checking LB Listener Rule destroyed: %s", err) - } - } + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } - return nil + tags { + Name = "TestAccAWSALB_fixedresponse" + } +}`, lbName) } -func testAccAWSLBListenerRuleConfig_multipleConditions(lbName, targetGroupName string) string { - return fmt.Sprintf(`resource "aws_lb_listener_rule" "static" { +func testAccAWSLBListenerRuleConfig_updateRulePriority(lbName, targetGroupName string) string { + return fmt.Sprintf(` +resource "aws_lb_listener_rule" "static" { listener_arn = "${aws_lb_listener.front_end.arn}" - priority = 100 + priority = 101 action { type = "forward" @@ -424,7 +1593,7 @@ func testAccAWSLBListenerRuleConfig_multipleConditions(lbName, targetGroupName s condition { field = "path-pattern" - values = ["/static/*", "static"] + values = ["/static/*"] } } @@ -482,7 +1651,7 @@ resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" tags { - Name = "terraform-testacc-lb-listener-rule-multiple-conditions" + Name = "terraform-testacc-lb-listener-rule-update-rule-priority" } } @@ -494,7 +1663,7 @@ resource "aws_subnet" "alb_test" { availability_zone = "${element(data.aws_availability_zones.available.names, count.index)}" tags { - Name = "tf-acc-lb-listener-rule-multiple-conditions-${count.index}" + Name = "tf-acc-lb-listener-rule-update-rule-priority-${count.index}" } } @@ -523,10 +1692,11 @@ resource "aws_security_group" "alb_test" { }`, lbName, targetGroupName) } -func testAccAWSLBListenerRuleConfig_basic(lbName, targetGroupName string) string { - return fmt.Sprintf(`resource "aws_lb_listener_rule" "static" { - listener_arn = "${aws_lb_listener.front_end.arn}" - priority = 100 +func testAccAWSLBListenerRuleConfig_changeRuleArn(lbName, targetGroupName string) string { + return fmt.Sprintf(` +resource "aws_lb_listener_rule" "static" { + listener_arn = "${aws_lb_listener.front_end_ruleupdate.arn}" + priority = 101 action { type = "forward" @@ -550,6 +1720,17 @@ resource "aws_lb_listener" "front_end" { } } +resource "aws_lb_listener" "front_end_ruleupdate" { + load_balancer_arn = "${aws_lb.alb_test.id}" + protocol = "HTTP" + port = "8080" + + default_action { + target_group_arn = "${aws_lb_target_group.test.id}" + type = "forward" + } +} + resource "aws_lb" "alb_test" { name = "%s" internal = true @@ -593,7 +1774,7 @@ resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" tags { - Name = "terraform-testacc-lb-listener-rule-basic" + Name = "terraform-testacc-lb-listener-rule-change-rule-arn" } } @@ -605,7 +1786,7 @@ resource "aws_subnet" "alb_test" { availability_zone = "${element(data.aws_availability_zones.available.names, count.index)}" tags { - Name = "tf-acc-lb-listener-rule-basic-${count.index}" + Name = "tf-acc-lb-listener-rule-change-rule-arn-${count.index}" } } @@ -634,34 +1815,20 @@ resource "aws_security_group" "alb_test" { }`, lbName, targetGroupName) } -func testAccAWSLBListenerRuleConfigBackwardsCompatibility(lbName, targetGroupName string) string { - return fmt.Sprintf(`resource "aws_alb_listener_rule" "static" { - listener_arn = "${aws_alb_listener.front_end.arn}" - priority = 100 - - action { - type = "forward" - target_group_arn = "${aws_alb_target_group.test.arn}" - } - - condition { - field = "path-pattern" - values = ["/static/*"] - } -} - -resource "aws_alb_listener" "front_end" { - load_balancer_arn = "${aws_alb.alb_test.id}" +func testAccAWSLBListenerRuleConfig_priorityBase(lbName, targetGroupName string) string { + return fmt.Sprintf(` +resource "aws_lb_listener" "front_end" { + load_balancer_arn = "${aws_lb.alb_test.id}" protocol = "HTTP" port = "80" default_action { - target_group_arn = "${aws_alb_target_group.test.id}" + target_group_arn = "${aws_lb_target_group.test.id}" type = "forward" } } -resource "aws_alb" "alb_test" { +resource "aws_lb" "alb_test" { name = "%s" internal = true security_groups = ["${aws_security_group.alb_test.id}"] @@ -675,7 +1842,7 @@ resource "aws_alb" "alb_test" { } } -resource "aws_alb_target_group" "test" { +resource "aws_lb_target_group" "test" { name = "%s" port = 8080 protocol = "HTTP" @@ -704,7 +1871,7 @@ resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" tags { - Name = "terraform-testacc-lb-listener-rule-bc" + Name = "terraform-testacc-lb-listener-rule-priority" } } @@ -716,7 +1883,7 @@ resource "aws_subnet" "alb_test" { availability_zone = "${element(data.aws_availability_zones.available.names, count.index)}" tags { - Name = "tf-acc-lb-listener-rule-bc-${count.index}" + Name = "tf-acc-lb-listener-rule-priority-${count.index}" } } @@ -745,153 +1912,234 @@ resource "aws_security_group" "alb_test" { }`, lbName, targetGroupName) } -func testAccAWSLBListenerRuleConfig_redirect(lbName string) string { - return fmt.Sprintf(`resource "aws_lb_listener_rule" "static" { +func testAccAWSLBListenerRuleConfig_priorityFirst(lbName, targetGroupName string) string { + return testAccAWSLBListenerRuleConfig_priorityBase(lbName, targetGroupName) + fmt.Sprintf(` +resource "aws_lb_listener_rule" "first" { listener_arn = "${aws_lb_listener.front_end.arn}" - priority = 100 action { - type = "redirect" - redirect { - port = "443" - protocol = "HTTPS" - status_code = "HTTP_301" - } + type = "forward" + target_group_arn = "${aws_lb_target_group.test.arn}" } condition { field = "path-pattern" - values = ["/static/*"] + values = ["/first/*"] } } -resource "aws_lb_listener" "front_end" { - load_balancer_arn = "${aws_lb.alb_test.id}" - protocol = "HTTP" - port = "80" +resource "aws_lb_listener_rule" "third" { + listener_arn = "${aws_lb_listener.front_end.arn}" + priority = 3 - default_action { - type = "redirect" - redirect { - port = "443" - protocol = "HTTPS" - status_code = "HTTP_301" - } + action { + type = "forward" + target_group_arn = "${aws_lb_target_group.test.arn}" + } + + condition { + field = "path-pattern" + values = ["/third/*"] + } + + depends_on = ["aws_lb_listener_rule.first"] +} +`) +} + +func testAccAWSLBListenerRuleConfig_priorityLast(lbName, targetGroupName string) string { + return testAccAWSLBListenerRuleConfig_priorityFirst(lbName, targetGroupName) + fmt.Sprintf(` +resource "aws_lb_listener_rule" "last" { + listener_arn = "${aws_lb_listener.front_end.arn}" + + action { + type = "forward" + target_group_arn = "${aws_lb_target_group.test.arn}" + } + + condition { + field = "path-pattern" + values = ["/last/*"] + } +} +`) +} + +func testAccAWSLBListenerRuleConfig_priorityStatic(lbName, targetGroupName string) string { + return testAccAWSLBListenerRuleConfig_priorityFirst(lbName, targetGroupName) + fmt.Sprintf(` +resource "aws_lb_listener_rule" "last" { + listener_arn = "${aws_lb_listener.front_end.arn}" + priority = 7 + + action { + type = "forward" + target_group_arn = "${aws_lb_target_group.test.arn}" + } + + condition { + field = "path-pattern" + values = ["/last/*"] } } +`) +} + +func testAccAWSLBListenerRuleConfig_priorityParallelism(lbName, targetGroupName string) string { + return testAccAWSLBListenerRuleConfig_priorityStatic(lbName, targetGroupName) + fmt.Sprintf(` +resource "aws_lb_listener_rule" "parallelism" { + count = 10 -resource "aws_lb" "alb_test" { - name = "%s" - internal = true - security_groups = ["${aws_security_group.alb_test.id}"] - subnets = ["${aws_subnet.alb_test.*.id}"] + listener_arn = "${aws_lb_listener.front_end.arn}" - idle_timeout = 30 - enable_deletion_protection = false + action { + type = "forward" + target_group_arn = "${aws_lb_target_group.test.arn}" + } - tags { - Name = "TestAccAWSALB_redirect" + condition { + field = "path-pattern" + values = ["/${count.index}/*"] } } - -variable "subnets" { - default = ["10.0.1.0/24", "10.0.2.0/24"] - type = "list" +`) } -data "aws_availability_zones" "available" {} +func testAccAWSLBListenerRuleConfig_priority50000(lbName, targetGroupName string) string { + return testAccAWSLBListenerRuleConfig_priorityBase(lbName, targetGroupName) + fmt.Sprintf(` +resource "aws_lb_listener_rule" "50000" { + listener_arn = "${aws_lb_listener.front_end.arn}" + priority = 50000 -resource "aws_vpc" "alb_test" { - cidr_block = "10.0.0.0/16" + action { + type = "forward" + target_group_arn = "${aws_lb_target_group.test.arn}" + } - tags { - Name = "terraform-testacc-lb-listener-rule-redirect" + condition { + field = "path-pattern" + values = ["/50000/*"] } } +`) +} -resource "aws_subnet" "alb_test" { - count = 2 - vpc_id = "${aws_vpc.alb_test.id}" - cidr_block = "${element(var.subnets, count.index)}" - map_public_ip_on_launch = true - availability_zone = "${element(data.aws_availability_zones.available.names, count.index)}" +// priority out of range (1, 50000) +func testAccAWSLBListenerRuleConfig_priority50001(lbName, targetGroupName string) string { + return testAccAWSLBListenerRuleConfig_priority50000(lbName, targetGroupName) + fmt.Sprintf(` +resource "aws_lb_listener_rule" "50001" { + listener_arn = "${aws_lb_listener.front_end.arn}" - tags { - Name = "tf-acc-lb-listener-rule-redirect-${count.index}" + action { + type = "forward" + target_group_arn = "${aws_lb_target_group.test.arn}" } -} - -resource "aws_security_group" "alb_test" { - name = "allow_all_alb_test" - description = "Used for ALB Testing" - vpc_id = "${aws_vpc.alb_test.id}" - ingress { - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] + condition { + field = "path-pattern" + values = ["/50001/*"] } +} +`) +} - egress { - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] +func testAccAWSLBListenerRuleConfig_priorityInUse(lbName, targetGroupName string) string { + return testAccAWSLBListenerRuleConfig_priority50000(lbName, targetGroupName) + fmt.Sprintf(` +resource "aws_lb_listener_rule" "50000_in_use" { + listener_arn = "${aws_lb_listener.front_end.arn}" + priority = 50000 + + action { + type = "forward" + target_group_arn = "${aws_lb_target_group.test.arn}" } - tags { - Name = "TestAccAWSALB_redirect" + condition { + field = "path-pattern" + values = ["/50000_in_use/*"] } -}`, lbName) +} +`) } -func testAccAWSLBListenerRuleConfig_fixedResponse(lbName string) string { - return fmt.Sprintf(`resource "aws_lb_listener_rule" "static" { +func testAccAWSLBListenerRuleConfig_cognito(rName, key, certificate string) string { + return fmt.Sprintf(` +resource "aws_lb_listener_rule" "cognito" { listener_arn = "${aws_lb_listener.front_end.arn}" - priority = 100 + priority = 100 action { - type = "fixed-response" - fixed_response { - content_type = "text/plain" - message_body = "Fixed response content" - status_code = "200" + type = "authenticate-cognito" + + authenticate_cognito { + user_pool_arn = "${aws_cognito_user_pool.test.arn}" + user_pool_client_id = "${aws_cognito_user_pool_client.test.id}" + user_pool_domain = "${aws_cognito_user_pool_domain.test.domain}" + + authentication_request_extra_params = { + param = "test" + } } } + action { + type = "forward" + target_group_arn = "${aws_lb_target_group.test.arn}" + } + condition { - field = "path-pattern" + field = "path-pattern" values = ["/static/*"] } } +resource "aws_iam_server_certificate" "test" { + name = "%[1]s" + certificate_body = "%[2]s" + private_key = "%[3]s" +} + resource "aws_lb_listener" "front_end" { load_balancer_arn = "${aws_lb.alb_test.id}" - protocol = "HTTP" - port = "80" + protocol = "HTTPS" + port = "443" + ssl_policy = "ELBSecurityPolicy-2016-08" + certificate_arn = "${aws_iam_server_certificate.test.arn}" default_action { - type = "fixed-response" - fixed_response { - content_type = "text/plain" - message_body = "Fixed response content" - status_code = "200" - } + target_group_arn = "${aws_lb_target_group.test.id}" + type = "forward" } } resource "aws_lb" "alb_test" { - name = "%s" + name = "%[1]s" internal = true security_groups = ["${aws_security_group.alb_test.id}"] - subnets = ["${aws_subnet.alb_test.*.id}"] + subnets = ["${aws_subnet.alb_test.*.id[0]}", "${aws_subnet.alb_test.*.id[1]}"] - idle_timeout = 30 + idle_timeout = 30 enable_deletion_protection = false - tags { - Name = "TestAccAWSALB_fixedResponse" + tags = { + Name = "TestAccAWSALB_cognito" + } +} + +resource "aws_lb_target_group" "test" { + name = "%[1]s" + port = 8080 + protocol = "HTTP" + vpc_id = "${aws_vpc.alb_test.id}" + + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" } } @@ -905,8 +2153,8 @@ data "aws_availability_zones" "available" {} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" - tags { - Name = "terraform-testacc-lb-listener-rule-fixedresponse" + tags = { + Name = "terraform-testacc-lb-listener-rule-cognito" } } @@ -917,8 +2165,8 @@ resource "aws_subnet" "alb_test" { map_public_ip_on_launch = true availability_zone = "${element(data.aws_availability_zones.available.names, count.index)}" - tags { - Name = "tf-acc-lb-listener-rule-fixedresponse-${count.index}" + tags = { + Name = "tf-acc-lb-listener-rule-cognito-${count.index}" } } @@ -941,69 +2189,116 @@ resource "aws_security_group" "alb_test" { cidr_blocks = ["0.0.0.0/0"] } - tags { - Name = "TestAccAWSALB_fixedresponse" + tags = { + Name = "TestAccAWSALB_cognito" } -}`, lbName) } -func testAccAWSLBListenerRuleConfig_updateRulePriority(lbName, targetGroupName string) string { +resource "aws_cognito_user_pool" "test" { + name = "%[1]s-pool" +} + +resource "aws_cognito_user_pool_client" "test" { + name = "%[1]s-pool-client" + user_pool_id = "${aws_cognito_user_pool.test.id}" + generate_secret = true + allowed_oauth_flows_user_pool_client = true + allowed_oauth_flows = ["code", "implicit"] + allowed_oauth_scopes = ["phone", "email", "openid", "profile", "aws.cognito.signin.user.admin"] + callback_urls = ["https://www.example.com/callback", "https://www.example.com/redirect"] + default_redirect_uri = "https://www.example.com/redirect" + logout_urls = ["https://www.example.com/login"] +} + +resource "aws_cognito_user_pool_domain" "test" { + domain = "%[1]s-pool-domain" + user_pool_id = "${aws_cognito_user_pool.test.id}" +} +`, rName, tlsPemEscapeNewlines(certificate), tlsPemEscapeNewlines(key)) +} + +func testAccAWSLBListenerRuleConfig_oidc(rName, key, certificate string) string { return fmt.Sprintf(` -resource "aws_lb_listener_rule" "static" { +resource "aws_lb_listener_rule" "oidc" { listener_arn = "${aws_lb_listener.front_end.arn}" - priority = 101 + priority = 100 action { - type = "forward" + type = "authenticate-oidc" + + authenticate_oidc { + authorization_endpoint = "https://example.com/authorization_endpoint" + client_id = "s6BhdRkqt3" + client_secret = "7Fjfp0ZBr1KtDRbnfVdmIw" + issuer = "https://example.com" + token_endpoint = "https://example.com/token_endpoint" + user_info_endpoint = "https://example.com/user_info_endpoint" + + authentication_request_extra_params = { + param = "test" + } + } + } + + action { + type = "forward" target_group_arn = "${aws_lb_target_group.test.arn}" } condition { - field = "path-pattern" + field = "path-pattern" values = ["/static/*"] } } +resource "aws_iam_server_certificate" "test" { + name = "%[1]s" + certificate_body = "%[2]s" + private_key = "%[3]s" +} + resource "aws_lb_listener" "front_end" { - load_balancer_arn = "${aws_lb.alb_test.id}" - protocol = "HTTP" - port = "80" + load_balancer_arn = "${aws_lb.alb_test.id}" + protocol = "HTTPS" + port = "443" + ssl_policy = "ELBSecurityPolicy-2016-08" + certificate_arn = "${aws_iam_server_certificate.test.arn}" - default_action { - target_group_arn = "${aws_lb_target_group.test.id}" - type = "forward" - } + default_action { + target_group_arn = "${aws_lb_target_group.test.id}" + type = "forward" + } } resource "aws_lb" "alb_test" { - name = "%s" + name = "%[1]s" internal = true security_groups = ["${aws_security_group.alb_test.id}"] - subnets = ["${aws_subnet.alb_test.*.id}"] + subnets = ["${aws_subnet.alb_test.*.id[0]}", "${aws_subnet.alb_test.*.id[1]}"] - idle_timeout = 30 + idle_timeout = 30 enable_deletion_protection = false - tags { - Name = "TestAccAWSALB_basic" + tags = { + Name = "TestAccAWSALB_cognito" } } resource "aws_lb_target_group" "test" { - name = "%s" - port = 8080 + name = "%[1]s" + port = 8080 protocol = "HTTP" - vpc_id = "${aws_vpc.alb_test.id}" + vpc_id = "${aws_vpc.alb_test.id}" health_check { - path = "/health" - interval = 60 - port = 8081 - protocol = "HTTP" - timeout = 3 - healthy_threshold = 3 + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 unhealthy_threshold = 3 - matcher = "200-299" + matcher = "200-299" } } @@ -1017,8 +2312,8 @@ data "aws_availability_zones" "available" {} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" - tags { - Name = "terraform-testacc-lb-listener-rule-update-rule-priority" + tags = { + Name = "terraform-testacc-lb-listener-rule-cognito" } } @@ -1029,8 +2324,8 @@ resource "aws_subnet" "alb_test" { map_public_ip_on_launch = true availability_zone = "${element(data.aws_availability_zones.available.names, count.index)}" - tags { - Name = "tf-acc-lb-listener-rule-update-rule-priority-${count.index}" + tags = { + Name = "tf-acc-lb-listener-rule-cognito-${count.index}" } } @@ -1053,114 +2348,122 @@ resource "aws_security_group" "alb_test" { cidr_blocks = ["0.0.0.0/0"] } - tags { - Name = "TestAccAWSALB_basic" + tags = { + Name = "TestAccAWSALB_cognito" } -}`, lbName, targetGroupName) +} +`, rName, tlsPemEscapeNewlines(certificate), tlsPemEscapeNewlines(key)) } -func testAccAWSLBListenerRuleConfig_changeRuleArn(lbName, targetGroupName string) string { +func testAccAWSLBListenerRuleConfig_Action_Order(rName, key, certificate string) string { return fmt.Sprintf(` -resource "aws_lb_listener_rule" "static" { - listener_arn = "${aws_lb_listener.front_end_ruleupdate.arn}" - priority = 101 +variable "rName" { + default = %[1]q +} + +data "aws_availability_zones" "available" {} + +resource "aws_lb_listener_rule" "test" { + listener_arn = "${aws_lb_listener.test.arn}" action { - type = "forward" + order = 1 + type = "authenticate-oidc" + + authenticate_oidc { + authorization_endpoint = "https://example.com/authorization_endpoint" + client_id = "s6BhdRkqt3" + client_secret = "7Fjfp0ZBr1KtDRbnfVdmIw" + issuer = "https://example.com" + token_endpoint = "https://example.com/token_endpoint" + user_info_endpoint = "https://example.com/user_info_endpoint" + + authentication_request_extra_params = { + param = "test" + } + } + } + + action { + order = 2 + type = "forward" target_group_arn = "${aws_lb_target_group.test.arn}" } condition { - field = "path-pattern" + field = "path-pattern" values = ["/static/*"] } } -resource "aws_lb_listener" "front_end" { - load_balancer_arn = "${aws_lb.alb_test.id}" - protocol = "HTTP" - port = "80" - - default_action { - target_group_arn = "${aws_lb_target_group.test.id}" - type = "forward" - } -} - -resource "aws_lb_listener" "front_end_ruleupdate" { - load_balancer_arn = "${aws_lb.alb_test.id}" - protocol = "HTTP" - port = "8080" - - default_action { - target_group_arn = "${aws_lb_target_group.test.id}" - type = "forward" - } -} - -resource "aws_lb" "alb_test" { - name = "%s" - internal = true - security_groups = ["${aws_security_group.alb_test.id}"] - subnets = ["${aws_subnet.alb_test.*.id}"] - - idle_timeout = 30 - enable_deletion_protection = false - - tags { - Name = "TestAccAWSALB_basic" - } +resource "aws_iam_server_certificate" "test" { + certificate_body = "%[2]s" + name = "${var.rName}" + private_key = "%[3]s" } -resource "aws_lb_target_group" "test" { - name = "%s" - port = 8080 - protocol = "HTTP" - vpc_id = "${aws_vpc.alb_test.id}" +resource "aws_lb_listener" "test" { + load_balancer_arn = "${aws_lb.test.id}" + protocol = "HTTPS" + port = "443" + ssl_policy = "ELBSecurityPolicy-2016-08" + certificate_arn = "${aws_iam_server_certificate.test.arn}" - health_check { - path = "/health" - interval = 60 - port = 8081 - protocol = "HTTP" - timeout = 3 - healthy_threshold = 3 - unhealthy_threshold = 3 - matcher = "200-299" + default_action { + target_group_arn = "${aws_lb_target_group.test.id}" + type = "forward" } } -variable "subnets" { - default = ["10.0.1.0/24", "10.0.2.0/24"] - type = "list" +resource "aws_lb" "test" { + internal = true + name = "${var.rName}" + security_groups = ["${aws_security_group.test.id}"] + subnets = ["${aws_subnet.test.*.id[0]}", "${aws_subnet.test.*.id[1]}"] } -data "aws_availability_zones" "available" {} +resource "aws_lb_target_group" "test" { + name = "${var.rName}" + port = 8080 + protocol = "HTTP" + vpc_id = "${aws_vpc.test.id}" -resource "aws_vpc" "alb_test" { + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" + } +} + +resource "aws_vpc" "test" { cidr_block = "10.0.0.0/16" - tags { - Name = "terraform-testacc-lb-listener-rule-change-rule-arn" + tags = { + Name = "${var.rName}" } } -resource "aws_subnet" "alb_test" { - count = 2 - vpc_id = "${aws_vpc.alb_test.id}" - cidr_block = "${element(var.subnets, count.index)}" +resource "aws_subnet" "test" { + count = 2 + + availability_zone = "${data.aws_availability_zones.available.names[count.index]}" + cidr_block = "10.0.${count.index}.0/24" map_public_ip_on_launch = true - availability_zone = "${element(data.aws_availability_zones.available.names, count.index)}" + vpc_id = "${aws_vpc.test.id}" - tags { - Name = "tf-acc-lb-listener-rule-change-rule-arn-${count.index}" + tags = { + Name = "${var.rName}" } } -resource "aws_security_group" "alb_test" { - name = "allow_all_alb_test" - description = "Used for ALB Testing" - vpc_id = "${aws_vpc.alb_test.id}" +resource "aws_security_group" "test" { + name = "${var.rName}" + vpc_id = "${aws_vpc.test.id}" ingress { from_port = 0 @@ -1176,54 +2479,165 @@ resource "aws_security_group" "alb_test" { cidr_blocks = ["0.0.0.0/0"] } - tags { - Name = "TestAccAWSALB_basic" + tags = { + Name = "${var.rName}" } -}`, lbName, targetGroupName) +} +`, rName, tlsPemEscapeNewlines(certificate), tlsPemEscapeNewlines(key)) } -func testAccAWSLBListenerRuleConfig_priorityBase(lbName, targetGroupName string) string { +func testAccAWSLBListenerRuleConfig_condition_error(condition string) string { + return fmt.Sprintf(` +resource "aws_lb_listener_rule" "error" { + listener_arn = "arn:aws:elasticloadbalancing:us-west-2:111111111111:listener/app/example/1234567890abcdef/1234567890abcdef" + priority = 100 + + action { + type = "fixed-response" + + fixed_response { + content_type = "text/plain" + message_body = "Static" + status_code = 200 + } + } + + %s +} +`, condition) +} + +func testAccAWSLBListenerRuleConfig_conditionAttributesCount_empty() string { + return testAccAWSLBListenerRuleConfig_condition_error("condition {}") +} + +func testAccAWSLBListenerRuleConfig_conditionAttributesCount_field() string { + return testAccAWSLBListenerRuleConfig_condition_error(`condition { field = "host-header" }`) +} + +func testAccAWSLBListenerRuleConfig_conditionAttributesCount_values() string { + return testAccAWSLBListenerRuleConfig_condition_error(`condition { values = ["example.com"] }`) +} + +func testAccAWSLBListenerRuleConfig_conditionAttributesCount_http_header() string { + return testAccAWSLBListenerRuleConfig_condition_error(` +condition { + host_header { + values = ["example.com"] + } + http_header { + http_header_name = "X-Clacks-Overhead" + values = ["GNU Terry Pratchett"] + } +}`) +} + +func testAccAWSLBListenerRuleConfig_conditionAttributesCount_http_request_method() string { + return testAccAWSLBListenerRuleConfig_condition_error(` +condition { + host_header { + values = ["example.com"] + } + http_request_method { + values = ["POST"] + } +}`) +} + +func testAccAWSLBListenerRuleConfig_conditionAttributesCount_path_pattern() string { + return testAccAWSLBListenerRuleConfig_condition_error(` +condition { + host_header { + values = ["example.com"] + } + path_pattern { + values = ["/"] + } +}`) +} + +func testAccAWSLBListenerRuleConfig_conditionAttributesCount_query_string() string { + return testAccAWSLBListenerRuleConfig_condition_error(` +condition { + host_header { + values = ["example.com"] + } + query_string { + key = "foo" + value = "bar" + } +}`) +} + +func testAccAWSLBListenerRuleConfig_conditionAttributesCount_source_ip() string { + return testAccAWSLBListenerRuleConfig_condition_error(` +condition { + host_header { + values = ["example.com"] + } + source_ip { + values = ["192.168.0.0/16"] + } +}`) +} + +func testAccAWSLBListenerRuleConfig_conditionAttributesCount_classic() string { + return testAccAWSLBListenerRuleConfig_condition_error(` +condition { + host_header { + values = ["example.com"] + } + field = "host-header" + values = ["example.com"] +}`) +} + +func testAccAWSLBListenerRuleConfig_condition_base(condition, name, lbName string) string { return fmt.Sprintf(` +resource "aws_lb_listener_rule" "static" { + listener_arn = "${aws_lb_listener.front_end.arn}" + priority = 100 + + action { + type = "fixed-response" + + fixed_response { + content_type = "text/plain" + message_body = "Static" + status_code = 200 + } + } + + %s +} + resource "aws_lb_listener" "front_end" { - load_balancer_arn = "${aws_lb.alb_test.id}" - protocol = "HTTP" - port = "80" + load_balancer_arn = "${aws_lb.alb_test.id}" + protocol = "HTTP" + port = "80" - default_action { - target_group_arn = "${aws_lb_target_group.test.id}" - type = "forward" - } + default_action { + type = "fixed-response" + + fixed_response { + content_type = "text/plain" + message_body = "Not Found" + status_code = 404 + } + } } resource "aws_lb" "alb_test" { name = "%s" internal = true security_groups = ["${aws_security_group.alb_test.id}"] - subnets = ["${aws_subnet.alb_test.*.id}"] + subnets = ["${aws_subnet.alb_test.*.id[0]}", "${aws_subnet.alb_test.*.id[1]}"] - idle_timeout = 30 + idle_timeout = 30 enable_deletion_protection = false - tags { - Name = "TestAccAWSALB_basic" - } -} - -resource "aws_lb_target_group" "test" { - name = "%s" - port = 8080 - protocol = "HTTP" - vpc_id = "${aws_vpc.alb_test.id}" - - health_check { - path = "/health" - interval = 60 - port = 8081 - protocol = "HTTP" - timeout = 3 - healthy_threshold = 3 - unhealthy_threshold = 3 - matcher = "200-299" + tags = { + Name = "TestAccAWSALB_condition%s" } } @@ -1237,8 +2651,8 @@ data "aws_availability_zones" "available" {} resource "aws_vpc" "alb_test" { cidr_block = "10.0.0.0/16" - tags { - Name = "terraform-testacc-lb-listener-rule-priority" + tags = { + Name = "TestAccAWSALB_condition%s" } } @@ -1249,8 +2663,8 @@ resource "aws_subnet" "alb_test" { map_public_ip_on_launch = true availability_zone = "${element(data.aws_availability_zones.available.names, count.index)}" - tags { - Name = "tf-acc-lb-listener-rule-priority-${count.index}" + tags = { + Name = "TestAccAWSALB_condition%s-${count.index}" } } @@ -1273,157 +2687,175 @@ resource "aws_security_group" "alb_test" { cidr_blocks = ["0.0.0.0/0"] } - tags { - Name = "TestAccAWSALB_basic" + tags = { + Name = "TestAccAWSALB_condition%s" } -}`, lbName, targetGroupName) +} +`, condition, lbName, name, name, name, name) } -func testAccAWSLBListenerRuleConfig_priorityFirst(lbName, targetGroupName string) string { - return testAccAWSLBListenerRuleConfig_priorityBase(lbName, targetGroupName) + fmt.Sprintf(` -resource "aws_lb_listener_rule" "first" { - listener_arn = "${aws_lb_listener.front_end.arn}" - - action { - type = "forward" - target_group_arn = "${aws_lb_target_group.test.arn}" - } - - condition { - field = "path-pattern" - values = ["/first/*"] +func testAccAWSLBListenerRuleConfig_conditionHostHeader(lbName string) string { + return testAccAWSLBListenerRuleConfig_condition_base(` +condition { + host_header { + values = ["example.com", "www.example.com"] } } +`, "HostHeader", lbName) +} -resource "aws_lb_listener_rule" "third" { - listener_arn = "${aws_lb_listener.front_end.arn}" - priority = 3 +func testAccAWSLBListenerRuleConfig_conditionHostHeader_deprecated(lbName string) string { + return testAccAWSLBListenerRuleConfig_condition_base(` +condition { + field = "host-header" + values = ["example.com"] +} +`, "HostHeaderDep", lbName) +} - action { - type = "forward" - target_group_arn = "${aws_lb_target_group.test.arn}" +func testAccAWSLBListenerRuleConfig_conditionHttpHeader(lbName string) string { + return testAccAWSLBListenerRuleConfig_condition_base(` +condition { + http_header { + http_header_name = "X-Forwarded-For" + values = ["192.168.1.*", "10.0.0.*"] } +} - condition { - field = "path-pattern" - values = ["/third/*"] +condition { + http_header { + http_header_name = "Zz9~|_^.-+*'&%$#!0aA" + values = ["RFC7230 Validity"] } - - depends_on = ["aws_lb_listener_rule.first"] } -`) +`, "HttpHeader", lbName) } -func testAccAWSLBListenerRuleConfig_priorityLast(lbName, targetGroupName string) string { - return testAccAWSLBListenerRuleConfig_priorityFirst(lbName, targetGroupName) + fmt.Sprintf(` -resource "aws_lb_listener_rule" "last" { - listener_arn = "${aws_lb_listener.front_end.arn}" +func testAccAWSLBListenerRuleConfig_conditionHttpHeader_invalid() string { + return ` +resource "aws_lb_listener_rule" "static" { + listener_arn = "arn:aws:elasticloadbalancing:us-west-2:111111111111:listener/app/test/xxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxx" + priority = 100 action { - type = "forward" - target_group_arn = "${aws_lb_target_group.test.arn}" + type = "fixed-response" + + fixed_response { + content_type = "text/plain" + message_body = "Static" + status_code = 200 + } } condition { - field = "path-pattern" - values = ["/last/*"] + http_header { + http_header_name = "Invalid@" + values = ["RFC7230 Validity"] + } } } -`) +` } -func testAccAWSLBListenerRuleConfig_priorityStatic(lbName, targetGroupName string) string { - return testAccAWSLBListenerRuleConfig_priorityFirst(lbName, targetGroupName) + fmt.Sprintf(` -resource "aws_lb_listener_rule" "last" { - listener_arn = "${aws_lb_listener.front_end.arn}" - priority = 7 - - action { - type = "forward" - target_group_arn = "${aws_lb_target_group.test.arn}" +func testAccAWSLBListenerRuleConfig_conditionHttpRequestMethod(lbName string) string { + return testAccAWSLBListenerRuleConfig_condition_base(` +condition { + http_request_method { + values = ["GET", "POST"] } +} +`, "HttpRequestMethod", lbName) +} - condition { - field = "path-pattern" - values = ["/last/*"] +func testAccAWSLBListenerRuleConfig_conditionPathPattern(lbName string) string { + return testAccAWSLBListenerRuleConfig_condition_base(` +condition { + path_pattern { + values = ["/public/*", "/cgi-bin/*"] } } -`) +`, "PathPattern", lbName) } -func testAccAWSLBListenerRuleConfig_priorityParallelism(lbName, targetGroupName string) string { - return testAccAWSLBListenerRuleConfig_priorityStatic(lbName, targetGroupName) + fmt.Sprintf(` -resource "aws_lb_listener_rule" "parallelism" { - count = 10 - - listener_arn = "${aws_lb_listener.front_end.arn}" +func testAccAWSLBListenerRuleConfig_conditionPathPattern_deprecated(lbName string) string { + return testAccAWSLBListenerRuleConfig_condition_base(` +condition { + field = "path-pattern" + values = ["/public/*"] +} +`, "PathPatternDep", lbName) +} - action { - type = "forward" - target_group_arn = "${aws_lb_target_group.test.arn}" +func testAccAWSLBListenerRuleConfig_conditionQueryString(lbName string) string { + return testAccAWSLBListenerRuleConfig_condition_base(` +condition { + query_string { + value = "surprise" } - - condition { - field = "path-pattern" - values = ["/${count.index}/*"] + query_string { + key = "" + value = "blank" } } -`) -} - -func testAccAWSLBListenerRuleConfig_priority50000(lbName, targetGroupName string) string { - return testAccAWSLBListenerRuleConfig_priorityBase(lbName, targetGroupName) + fmt.Sprintf(` -resource "aws_lb_listener_rule" "50000" { - listener_arn = "${aws_lb_listener.front_end.arn}" - priority = 50000 - action { - type = "forward" - target_group_arn = "${aws_lb_target_group.test.arn}" +condition { + query_string { + key = "foo" + value = "bar" } - - condition { - field = "path-pattern" - values = ["/50000/*"] + query_string { + key = "foo" + value = "baz" } } -`) +`, "QueryString", lbName) } -// priority out of range (1, 50000) -func testAccAWSLBListenerRuleConfig_priority50001(lbName, targetGroupName string) string { - return testAccAWSLBListenerRuleConfig_priority50000(lbName, targetGroupName) + fmt.Sprintf(` -resource "aws_lb_listener_rule" "50001" { - listener_arn = "${aws_lb_listener.front_end.arn}" - - action { - type = "forward" - target_group_arn = "${aws_lb_target_group.test.arn}" +func testAccAWSLBListenerRuleConfig_conditionSourceIp(lbName string) string { + return testAccAWSLBListenerRuleConfig_condition_base(` +condition { + source_ip { + values = [ + "192.168.0.0/16", + "dead:cafe::/64", + ] } +} +`, "SourceIp", lbName) +} - condition { - field = "path-pattern" - values = ["/50001/*"] +// Currently a maximum of 5 condition values per rule +func testAccAWSLBListenerRuleConfig_conditionMultiple(lbName string) string { + return testAccAWSLBListenerRuleConfig_condition_base(` +condition { + host_header { + values = ["example.com"] } } -`) + +condition { + http_header { + http_header_name = "X-Forwarded-For" + values = ["192.168.1.*"] + } } -func testAccAWSLBListenerRuleConfig_priorityInUse(lbName, targetGroupName string) string { - return testAccAWSLBListenerRuleConfig_priority50000(lbName, targetGroupName) + fmt.Sprintf(` -resource "aws_lb_listener_rule" "50000_in_use" { - listener_arn = "${aws_lb_listener.front_end.arn}" - priority = 50000 +condition { + http_request_method { + values = ["GET"] + } +} - action { - type = "forward" - target_group_arn = "${aws_lb_target_group.test.arn}" +condition { + path_pattern { + values = ["/public/*"] } +} - condition { - field = "path-pattern" - values = ["/50000_in_use/*"] +condition { + source_ip { + values = ["192.168.0.0/16"] } } -`) +`, "Multiple", lbName) } diff --git a/website/docs/guides/version-3-upgrade.html.md b/website/docs/guides/version-3-upgrade.html.md new file mode 100644 index 000000000000..bb91f6590287 --- /dev/null +++ b/website/docs/guides/version-3-upgrade.html.md @@ -0,0 +1,219 @@ +--- +subcategory: "" +layout: "aws" +page_title: "Terraform AWS Provider Version 3 Upgrade Guide" +description: |- + Terraform AWS Provider Version 3 Upgrade Guide +--- + +# Terraform AWS Provider Version 3 Upgrade Guide + +~> **NOTE:** This upgrade guide is a work in progress and will not be completed until the release of version 3.0.0 of the provider in the coming months. Many of the topics discussed, except for the actual provider upgrade, can be performed using the most recent 2.X version of the provider. + +Version 3.0.0 of the AWS provider for Terraform is a major release and includes some changes that you will need to consider when upgrading. This guide is intended to help with that process and focuses only on changes from version 1.X to version 3.0.0. + +Most of the changes outlined in this guide have been previously marked as deprecated in the Terraform plan/apply output throughout previous provider releases. These changes, such as deprecation notices, can always be found in the [Terraform AWS Provider CHANGELOG](https://github.com/terraform-providers/terraform-provider-aws/blob/master/CHANGELOG.md). + +Upgrade topics: + + + +- [Provider Version Configuration](#provider-version-configuration) +- [Resource: aws_emr_cluster](#resource-aws_emr_cluster) + + + +## Provider Version Configuration + +!> **WARNING:** This topic is placeholder documentation until version 3.0.0 is released in the coming months. + +-> Before upgrading to version 3.0.0, it is recommended to upgrade to the most recent 2.X version of the provider and ensure that your environment successfully runs [`terraform plan`](https://www.terraform.io/docs/commands/plan.html) without unexpected changes or deprecation notices. + +It is recommended to use [version constraints when configuring Terraform providers](https://www.terraform.io/docs/configuration/providers.html#provider-versions). If you are following that recommendation, update the version constraints in your Terraform configuration and run [`terraform init`](https://www.terraform.io/docs/commands/init.html) to download the new version. + +For example, given this previous configuration: + +```hcl +provider "aws" { + # ... other configuration ... + + version = "~> 2.8" +} +``` + +Update to latest 3.X version: + +```hcl +provider "aws" { + # ... other configuration ... + + version = "~> 3.0" +} +``` + +## Resource: aws_emr_cluster + +### core_instance_count Argument Removal + +Switch your Terraform configuration to the `core_instance_group` configuration block instead. + +For example, given this previous configuration: + +```hcl +resource "aws_emr_cluster" "example" { + # ... other configuration ... + + core_instance_count = 2 +} +``` + +An updated configuration: + +```hcl +resource "aws_emr_cluster" "example" { + # ... other configuration ... + + core_instance_group { + # ... other configuration ... + + instance_count = 2 + } +} +``` + +### core_instance_type Argument Removal + +Switch your Terraform configuration to the `core_instance_group` configuration block instead. + +For example, given this previous configuration: + +```hcl +resource "aws_emr_cluster" "example" { + # ... other configuration ... + + core_instance_type = "m4.large" +} +``` + +An updated configuration: + +```hcl +resource "aws_emr_cluster" "example" { + # ... other configuration ... + + core_instance_group { + instance_type = "m4.large" + } +} +``` + +### instance_group Configuration Block Removal + +Switch your Terraform configuration to the `master_instance_group` and `core_instance_group` configuration blocks instead. For any task instance groups, use the `aws_emr_instance_group` resource. + +For example, given this previous configuration: + +```hcl +resource "aws_emr_cluster" "example" { + # ... other configuration ... + + instance_group { + instance_role = "MASTER" + instance_type = "m4.large" + } + + instance_group { + instance_count = 1 + instance_role = "CORE" + instance_type = "c4.large" + } + + instance_group { + instance_count = 2 + instance_role = "TASK" + instance_type = "c4.xlarge" + } +} +``` + +An updated configuration: + +```hcl +resource "aws_emr_cluster" "example" { + # ... other configuration ... + + master_instance_group { + instance_type = "m4.large" + } + + core_instance_group { + instance_count = 1 + instance_type = "c4.large" + } +} + +resource "aws_emr_instance_group" "example" { + cluster_id = "${aws_emr_cluster.example.id}" + instance_count = 2 + instance_type = "c4.xlarge" +} +``` + +### master_instance_type Argument Removal + +Switch your Terraform configuration to the `master_instance_group` configuration block instead. + +For example, given this previous configuration: + +```hcl +resource "aws_emr_cluster" "example" { + # ... other configuration ... + + master_instance_type = "m4.large" +} +``` + +An updated configuration: + +```hcl +resource "aws_emr_cluster" "example" { + # ... other configuration ... + + master_instance_group { + instance_type = "m4.large" + } +} +``` + +## Resource: aws_lb_listener_rule + +### condition.field and condition.values Arguments Removal + +Switch your Terraform configuration to use the `host_header` or `path_pattern` configuration block instead. + +For example, given this previous configuration: + +```hcl +resource "aws_lb_listener_rule" "example" { + # ... other configuration ... + + condition { + field = "path-pattern" + values = ["/static/*"] + } +} +``` + +An updated configuration: + +```hcl +resource "aws_lb_listener_rule" "example" { + # ... other configuration ... + + condition { + path_pattern { + values = ["/static/*"] + } + } +} +``` diff --git a/website/docs/r/lb_listener_rule.html.markdown b/website/docs/r/lb_listener_rule.html.markdown index 7bf5a7953bb7..d1309deb0e6c 100644 --- a/website/docs/r/lb_listener_rule.html.markdown +++ b/website/docs/r/lb_listener_rule.html.markdown @@ -33,8 +33,15 @@ resource "aws_lb_listener_rule" "static" { } condition { - field = "path-pattern" - values = ["/static/*"] + path_pattern { + values = ["/static/*"] + } + } + + condition { + host_header { + values = ["example.com"] + } } } @@ -50,8 +57,9 @@ resource "aws_lb_listener_rule" "host_based_routing" { } condition { - field = "host-header" - values = ["my-service.*.terraform.io"] + host_header { + values = ["my-service.*.terraform.io"] + } } } @@ -70,8 +78,10 @@ resource "aws_lb_listener_rule" "redirect_http_to_https" { } condition { - field = "host-header" - values = ["my-service.*.terraform.io"] + http_header { + http_header_name = "X-Forwarded-For" + values = ["192.168.1.*"] + } } } @@ -90,8 +100,14 @@ resource "aws_lb_listener_rule" "health_check" { } condition { - field = "path-pattern" - values = ["/health"] + query_string { + key = "health" + value = "check" + } + + query_string { + value = "bar" + } } } @@ -104,7 +120,9 @@ The following arguments are supported: * `listener_arn` - (Required, Forces New Resource) The ARN of the listener to which to attach the rule. * `priority` - (Optional) The priority for the rule between `1` and `50000`. Leaving it unset will automatically set the rule with next available priority after currently existing highest rule. A listener can't have multiple rules with the same priority. * `action` - (Required) An Action block. Action blocks are documented below. -* `condition` - (Required) A Condition block. Condition blocks are documented below. +* `condition` - (Required) A Condition block. Multiple condition blocks of different types can be set and all must be satisfied for the rule to match. Condition blocks are documented below. + +### Action Blocks Action Blocks (for `action`) support the following: @@ -130,10 +148,71 @@ Fixed-response Blocks (for `fixed_response`) support the following: * `message_body` - (Optional) The message body. * `status_code` - (Optional) The HTTP response code. Valid values are `2XX`, `4XX`, or `5XX`. +Authenticate Cognito Blocks (for `authenticate_cognito`) supports the following: + +* `authentication_request_extra_params` - (Optional) The query parameters to include in the redirect request to the authorization endpoint. Max: 10. +* `on_unauthenticated_request` - (Optional) The behavior if the user is not authenticated. Valid values: `deny`, `allow` and `authenticate` +* `scope` - (Optional) The set of user claims to be requested from the IdP. +* `session_cookie_name` - (Optional) The name of the cookie used to maintain session information. +* `session_timeout` - (Optional) The maximum duration of the authentication session, in seconds. +* `user_pool_arn` - (Required) The ARN of the Cognito user pool. +* `user_pool_client_id` - (Required) The ID of the Cognito user pool client. +* `user_pool_domain` - (Required) The domain prefix or fully-qualified domain name of the Cognito user pool. + +Authenticate OIDC Blocks (for `authenticate_oidc`) supports the following: + +* `authentication_request_extra_params` - (Optional) The query parameters to include in the redirect request to the authorization endpoint. Max: 10. +* `authorization_endpoint` - (Required) The authorization endpoint of the IdP. +* `client_id` - (Required) The OAuth 2.0 client identifier. +* `client_secret` - (Required) The OAuth 2.0 client secret. +* `issuer` - (Required) The OIDC issuer identifier of the IdP. +* `on_unauthenticated_request` - (Optional) The behavior if the user is not authenticated. Valid values: `deny`, `allow` and `authenticate` +* `scope` - (Optional) The set of user claims to be requested from the IdP. +* `session_cookie_name` - (Optional) The name of the cookie used to maintain session information. +* `session_timeout` - (Optional) The maximum duration of the authentication session, in seconds. +* `token_endpoint` - (Required) The token endpoint of the IdP. +* `user_info_endpoint` - (Required) The user info endpoint of the IdP. + +Authentication Request Extra Params Blocks (for `authentication_request_extra_params`) supports the following: + +* `key` - (Required) The key of query parameter +* `value` - (Required) The value of query parameter + +### Condition Blocks + +One or more condition blocks can be set per rule. Most condition types can only be specified once per rule except for `http-header` and `query-string` which can be specified multiple times. + +>>>>>>> 923cc6ec1... Support ALB Advanced Routing rules (#8268) Condition Blocks (for `condition`) support the following: -* `field` - (Required) The name of the field. Must be one of `path-pattern` for path based routing or `host-header` for host based routing. -* `values` - (Required) The path patterns to match. A maximum of 1 can be defined. +* `field` - (Optional, **DEPRECATED**) The type of condition. Valid values are `host-header` or `path-pattern`. Must also set `values`. +* `values` - (Optional, **DEPRECATED**) List of exactly one pattern to match. Required when `field` is set. +* `host_header` - (Optional) Contains a single `value` item which is a list of host header patterns to match. The maximum size of each pattern is 128 characters. Comparison is case insensitive. Wildcard characters supported: * (matches 0 or more characters) and ? (matches exactly 1 character). Only one pattern needs to match for the condition to be satisfied. +* `http_header` - (Optional) HTTP headers to match. [HTTP Header block](#http-header-blocks) fields documented below. +* `http_request_method` - (Optional) Contains a single `value` item which is a list of HTTP request methods or verbs to match. Maximum size is 40 characters. Only allowed characters are A-Z, hyphen (-) and underscore (\_). Comparison is case sensitive. Wildcards are not supported. Only one needs to match for the condition to be satisfied. AWS recommends that GET and HEAD requests are routed in the same way because the response to a HEAD request may be cached. +* `path_pattern` - (Optional) Contains a single `value` item which is a list of path patterns to match against the request URL. Maximum size of each pattern is 128 characters. Comparison is case sensitive. Wildcard charaters supported: * (matches 0 or more characters) and ? (matches exactly 1 character). Only one pattern needs to match for the condition to be satisfied. Path pattern is compared only to the path of the URL, not to its query string. To compare against the query string, use a `query-string` condition. +* `query_string` - (Optional) Query strings to match. [Query String block](#query-string-blocks) fields documented below. +* `source_ip` - (Optional) Contains a single `value` item which is a list of source IP CIDR notations to match. You can use both IPv4 and IPv6 addresses. Wildcards are not supported. Condition is satisfied if the source IP address of the request matches one of the CIDR blocks. Condition is not satisfied by the addresses in the `X-Forwarded-For` header, use `http-header` condition instead. + +~> **NOTE::** Exactly one of `field`, `host_header`, `http_header`, `http_request_method`, `path_pattern`, `query_string` or `source_ip` must be set per condition. + +#### HTTP Header Blocks + +HTTP Header Blocks (for `http_header`) support the following: + +* `http_header_name` - (Required) Name of HTTP header to search. The maximum size is 40 characters. Comparison is case insensitive. Only RFC7240 characters are supported. Wildcards are not supported. You cannot use HTTP header condition to specify the host header, use a `host-header` condition instead. +* `values` - (Required) List of header value patterns to match. Maximum size of each pattern is 128 characters. Comparison is case insensitive. Wildcard characters supported: * (matches 0 or more characters) and ? (matches exactly 1 character). If the same header appears multiple times in the request they will be searched in order until a match is found. Only one pattern needs to match for the condition to be satisfied. To require that all of the strings are a match, create one condition block per string. + +#### Query String Blocks + +Query String Blocks (for `query_string`) support the following: + +* `values` - (Required) Query string pairs or values to match. Query String Value blocks documented below. Multiple `values` blocks can be specified, see example above. Maximum size of each string is 128 characters. Comparison is case insensitive. Wildcard characters supported: * (matches 0 or more characters) and ? (matches exactly 1 character). To search for a literal '\*' or '?' character in a query string, escape the character with a backslash (\\). Only one pair needs to match for the condition to be satisfied. + +Query String Value Blocks (for `query_string.values`) support the following: + +* `key` - (Optional) Query string key pattern to match. +* `value` - (Required) Query string value pattern to match. ## Attributes Reference