diff --git a/azurerm/resource_arm_application_gateway.go b/azurerm/resource_arm_application_gateway.go index bb820babc15e..5985a213479f 100644 --- a/azurerm/resource_arm_application_gateway.go +++ b/azurerm/resource_arm_application_gateway.go @@ -450,6 +450,12 @@ func resourceArmApplicationGateway() *schema.Resource { Optional: true, }, + "redirect_configuration_name": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.NoEmptyStrings, + }, + "backend_address_pool_id": { Type: schema.TypeString, Computed: true, @@ -474,6 +480,68 @@ func resourceArmApplicationGateway() *schema.Resource { Type: schema.TypeString, Computed: true, }, + + "redirect_configuration_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "redirect_configuration": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "redirect_type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(network.Permanent), + string(network.Temporary), + string(network.Found), + string(network.SeeOther), + }, false), + }, + + "target_listener_name": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "target_url": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "include_path": { + Type: schema.TypeBool, + Optional: true, + }, + + "include_query_string": { + Type: schema.TypeBool, + Optional: true, + }, + + "id": { + Type: schema.TypeString, + Computed: true, + }, + + "target_listener_id": { + Type: schema.TypeString, + Computed: true, + }, }, }, }, @@ -703,12 +771,18 @@ func resourceArmApplicationGateway() *schema.Resource { "default_backend_address_pool_name": { Type: schema.TypeString, - Required: true, + Optional: true, }, "default_backend_http_settings_name": { Type: schema.TypeString, - Required: true, + Optional: true, + }, + + "default_redirect_configuration_name": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.NoEmptyStrings, }, "path_rule": { @@ -731,12 +805,18 @@ func resourceArmApplicationGateway() *schema.Resource { "backend_address_pool_name": { Type: schema.TypeString, - Required: true, + Optional: true, }, "backend_http_settings_name": { Type: schema.TypeString, - Required: true, + Optional: true, + }, + + "redirect_configuration_name": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.NoEmptyStrings, }, "backend_address_pool_id": { @@ -749,6 +829,11 @@ func resourceArmApplicationGateway() *schema.Resource { Computed: true, }, + "redirect_configuration_id": { + Type: schema.TypeString, + Computed: true, + }, + "id": { Type: schema.TypeString, Computed: true, @@ -767,6 +852,11 @@ func resourceArmApplicationGateway() *schema.Resource { Computed: true, }, + "default_redirect_configuration_id": { + Type: schema.TypeString, + Computed: true, + }, + "id": { Type: schema.TypeString, Computed: true, @@ -903,6 +993,7 @@ func resourceArmApplicationGatewayCreateUpdate(d *schema.ResourceData, meta inte httpListeners := expandApplicationGatewayHTTPListeners(d, gatewayID) probes := expandApplicationGatewayProbes(d) requestRoutingRules := expandApplicationGatewayRequestRoutingRules(d, gatewayID) + redirectConfigurations := expandApplicationGatewayRedirectConfigurations(d, gatewayID) sku := expandApplicationGatewaySku(d) sslCertificates := expandApplicationGatewaySslCertificates(d) sslPolicy := expandApplicationGatewaySslPolicy(d) @@ -924,6 +1015,7 @@ func resourceArmApplicationGatewayCreateUpdate(d *schema.ResourceData, meta inte HTTPListeners: httpListeners, Probes: probes, RequestRoutingRules: requestRoutingRules, + RedirectConfigurations: redirectConfigurations, Sku: sku, SslCertificates: sslCertificates, SslPolicy: sslPolicy, @@ -1068,6 +1160,14 @@ func resourceArmApplicationGatewayRead(d *schema.ResourceData, meta interface{}) return fmt.Errorf("Error setting `request_routing_rule`: %+v", setErr) } + redirectConfigurations, err := flattenApplicationGatewayRedirectConfigurations(props.RedirectConfigurations) + if err != nil { + return fmt.Errorf("Error flattening `redirect configuration`: %+v", err) + } + if setErr := d.Set("redirect_configuration", redirectConfigurations); setErr != nil { + return fmt.Errorf("Error setting `redirect configuration`: %+v", setErr) + } + if setErr := d.Set("sku", flattenApplicationGatewaySku(props.Sku)); setErr != nil { return fmt.Errorf("Error setting `sku`: %+v", setErr) } @@ -1958,6 +2058,13 @@ func expandApplicationGatewayRequestRoutingRules(d *schema.ResourceData, gateway } } + if redirectConfigName := v["redirect_configuration_name"].(string); redirectConfigName != "" { + redirectConfigID := fmt.Sprintf("%s/redirectConfigurations/%s", gatewayID, redirectConfigName) + rule.ApplicationGatewayRequestRoutingRulePropertiesFormat.RedirectConfiguration = &network.SubResource{ + ID: utils.String(redirectConfigID), + } + } + results = append(results, rule) } @@ -1973,6 +2080,14 @@ func flattenApplicationGatewayRequestRoutingRules(input *[]network.ApplicationGa for _, config := range *input { if props := config.ApplicationGatewayRequestRoutingRulePropertiesFormat; props != nil { + if applicationGatewayHasSubResource(props.BackendAddressPool) && applicationGatewayHasSubResource(props.RedirectConfiguration) { + return nil, fmt.Errorf("[ERROR] Conflict between `backend_address_pool_name` and `redirect_configuration_name` (back-end pool not applicable when redirection specified)") + } + + if applicationGatewayHasSubResource(props.BackendHTTPSettings) && applicationGatewayHasSubResource(props.RedirectConfiguration) { + return nil, fmt.Errorf("[ERROR] Conflict between `backend_http_settings_name` and `redirect_configuration_name` (back-end settings not applicable when redirection specified)") + } + output := map[string]interface{}{ "rule_type": string(props.RuleType), } @@ -2033,6 +2148,128 @@ func flattenApplicationGatewayRequestRoutingRules(input *[]network.ApplicationGa } } + if redirect := props.RedirectConfiguration; redirect != nil { + if redirect.ID != nil { + redirectId, err := parseAzureResourceID(*redirect.ID) + if err != nil { + return nil, err + } + redirectName := redirectId.Path["redirectConfigurations"] + output["redirect_configuration_name"] = redirectName + output["redirect_configuration_id"] = *redirect.ID + } + } + + results = append(results, output) + } + } + + return results, nil +} + +func applicationGatewayHasSubResource(subResource *network.SubResource) bool { + return subResource != nil && subResource.ID != nil && *subResource.ID != "" +} + +func expandApplicationGatewayRedirectConfigurations(d *schema.ResourceData, gatewayID string) *[]network.ApplicationGatewayRedirectConfiguration { + + vs := d.Get("redirect_configuration").([]interface{}) + results := make([]network.ApplicationGatewayRedirectConfiguration, 0) + + for _, raw := range vs { + v := raw.(map[string]interface{}) + + name := v["name"].(string) + redirectType := v["redirect_type"].(string) + + output := network.ApplicationGatewayRedirectConfiguration{ + Name: utils.String(name), + ApplicationGatewayRedirectConfigurationPropertiesFormat: &network.ApplicationGatewayRedirectConfigurationPropertiesFormat{ + RedirectType: network.ApplicationGatewayRedirectType(redirectType), + }, + } + + if includePath := v["include_path"].(bool); includePath { + output.ApplicationGatewayRedirectConfigurationPropertiesFormat.IncludePath = utils.Bool(includePath) + } + + if includeQueryString := v["include_query_string"].(bool); includeQueryString { + output.ApplicationGatewayRedirectConfigurationPropertiesFormat.IncludeQueryString = utils.Bool(includeQueryString) + } + + if targetListenerName := v["target_listener_name"].(string); targetListenerName != "" { + targetListenerID := fmt.Sprintf("%s/httpListeners/%s", gatewayID, targetListenerName) + output.ApplicationGatewayRedirectConfigurationPropertiesFormat.TargetListener = &network.SubResource{ + ID: utils.String(targetListenerID), + } + } + + if targetUrl := v["target_url"].(string); targetUrl != "" { + output.ApplicationGatewayRedirectConfigurationPropertiesFormat.TargetURL = utils.String(targetUrl) + } + + results = append(results, output) + } + + return &results +} + +func flattenApplicationGatewayRedirectConfigurations(input *[]network.ApplicationGatewayRedirectConfiguration) ([]interface{}, error) { + results := make([]interface{}, 0) + if input == nil { + return results, nil + } + + for _, config := range *input { + if props := config.ApplicationGatewayRedirectConfigurationPropertiesFormat; props != nil { + + if !applicationGatewayHasSubResource(config.TargetListener) && (config.TargetURL == nil || *config.TargetURL == "") { + return nil, fmt.Errorf("[ERROR] Set either `target_listener_name` or `target_url`") + } + if applicationGatewayHasSubResource(config.TargetListener) && config.TargetURL != nil && *config.TargetURL != "" { + return nil, fmt.Errorf("[ERROR] Conflict between `target_listener_name` and `target_url` (redirection is either to URL or target listener)") + } + + if config.TargetURL != nil && *config.TargetURL != "" && config.IncludePath != nil { + return nil, fmt.Errorf("[ERROR] `include_path` is not a valid option when `target_url` is set") + } + + output := map[string]interface{}{ + "redirect_type": string(props.RedirectType), + } + + if config.ID != nil { + output["id"] = *config.ID + } + + if config.Name != nil { + output["name"] = *config.Name + } + + if listener := props.TargetListener; listener != nil { + if listener.ID != nil { + listenerId, err := parseAzureResourceID(*listener.ID) + if err != nil { + return nil, err + } + targetListenerName := listenerId.Path["httpListeners"] + output["target_listener_name"] = targetListenerName + output["target_listener_id"] = *listener.ID + } + } + + if config.TargetURL != nil { + output["target_url"] = *config.TargetURL + } + + if config.IncludePath != nil { + output["include_path"] = *config.IncludePath + } + + if config.IncludeQueryString != nil { + output["include_query_string"] = *config.IncludeQueryString + } + results = append(results, output) } } @@ -2155,11 +2392,6 @@ func expandApplicationGatewayURLPathMaps(d *schema.ResourceData, gatewayID strin v := raw.(map[string]interface{}) name := v["name"].(string) - defaultBackendAddressPoolName := v["default_backend_address_pool_name"].(string) - defaultBackendHTTPSettingsName := v["default_backend_http_settings_name"].(string) - - defaultBackendAddressPoolID := fmt.Sprintf("%s/backendAddressPools/%s", gatewayID, defaultBackendAddressPoolName) - defaultBackendHTTPSettingsID := fmt.Sprintf("%s/backendHttpSettingsCollection/%s", gatewayID, defaultBackendHTTPSettingsName) pathRules := make([]network.ApplicationGatewayPathRule, 0) for _, ruleConfig := range v["path_rule"].([]interface{}) { @@ -2193,22 +2425,48 @@ func expandApplicationGatewayURLPathMaps(d *schema.ResourceData, gatewayID strin } } + if redirectConfigurationName := ruleConfigMap["redirect_configuration_name"].(string); redirectConfigurationName != "" { + redirectConfigurationID := fmt.Sprintf("%s/redirectConfigurations/%s", gatewayID, redirectConfigurationName) + rule.ApplicationGatewayPathRulePropertiesFormat.RedirectConfiguration = &network.SubResource{ + ID: utils.String(redirectConfigurationID), + } + } + pathRules = append(pathRules, rule) } output := network.ApplicationGatewayURLPathMap{ Name: utils.String(name), ApplicationGatewayURLPathMapPropertiesFormat: &network.ApplicationGatewayURLPathMapPropertiesFormat{ - DefaultBackendAddressPool: &network.SubResource{ - ID: utils.String(defaultBackendAddressPoolID), - }, - DefaultBackendHTTPSettings: &network.SubResource{ - ID: utils.String(defaultBackendHTTPSettingsID), - }, PathRules: &pathRules, }, } + // treating these three as optional as seems necessary when redirection is also an alternative. Not explicit in the documentation, though + // see https://docs.microsoft.com/en-us/rest/api/application-gateway/applicationgateways/createorupdate#applicationgatewayurlpathmap + // see also az docs https://docs.microsoft.com/en-us/cli/azure/network/application-gateway/url-path-map?view=azure-cli-latest#az-network-application-gateway-url-path-map-create + + if defaultBackendAddressPoolName := v["default_backend_address_pool_name"].(string); defaultBackendAddressPoolName != "" { + defaultBackendAddressPoolID := fmt.Sprintf("%s/backendAddressPools/%s", gatewayID, defaultBackendAddressPoolName) + output.ApplicationGatewayURLPathMapPropertiesFormat.DefaultBackendAddressPool = &network.SubResource{ + ID: utils.String(defaultBackendAddressPoolID), + } + } + + if defaultBackendHTTPSettingsName := v["default_backend_http_settings_name"].(string); defaultBackendHTTPSettingsName != "" { + defaultBackendHTTPSettingsID := fmt.Sprintf("%s/backendHttpSettingsCollection/%s", gatewayID, defaultBackendHTTPSettingsName) + output.ApplicationGatewayURLPathMapPropertiesFormat.DefaultBackendHTTPSettings = &network.SubResource{ + ID: utils.String(defaultBackendHTTPSettingsID), + } + } + + if defaultRedirectConfigurationName := v["default_redirect_configuration_name"].(string); defaultRedirectConfigurationName != "" { + defaultRedirectConfigurationID := fmt.Sprintf("%s/redirectConfigurations/%s", gatewayID, defaultRedirectConfigurationName) + output.ApplicationGatewayURLPathMapPropertiesFormat.DefaultRedirectConfiguration = &network.SubResource{ + ID: utils.String(defaultRedirectConfigurationID), + } + } + results = append(results, output) } @@ -2253,6 +2511,16 @@ func flattenApplicationGatewayURLPathMaps(input *[]network.ApplicationGatewayURL output["default_backend_http_settings_id"] = *settings.ID } + if redirect := props.DefaultRedirectConfiguration; redirect != nil && redirect.ID != nil { + settingsId, err := parseAzureResourceID(*redirect.ID) + if err != nil { + return nil, err + } + redirectConfigurationName := settingsId.Path["redirectConfigurations"] + output["default_redirect_configuration_name"] = redirectConfigurationName + output["default_redirect_configuration_id"] = *redirect.ID + } + pathRules := make([]interface{}, 0) if rules := props.PathRules; rules != nil { for _, rule := range *rules { @@ -2267,6 +2535,22 @@ func flattenApplicationGatewayURLPathMaps(input *[]network.ApplicationGatewayURL } if ruleProps := rule.ApplicationGatewayPathRulePropertiesFormat; ruleProps != nil { + if applicationGatewayHasSubResource(props.DefaultBackendAddressPool) && applicationGatewayHasSubResource(ruleProps.RedirectConfiguration) { + return nil, fmt.Errorf("[ERROR] Conflict between `default_backend_address_pool_name` and `redirect_configuration_name` (default back-end pool not applicable when redirection specified)") + } + + if applicationGatewayHasSubResource(ruleProps.BackendAddressPool) && applicationGatewayHasSubResource(ruleProps.RedirectConfiguration) { + return nil, fmt.Errorf("[ERROR] Conflict between `backend_address_pool_name` and `redirect_configuration_name` (back-end pool not applicable when redirection specified)") + } + + if applicationGatewayHasSubResource(props.DefaultBackendHTTPSettings) && applicationGatewayHasSubResource(ruleProps.RedirectConfiguration) { + return nil, fmt.Errorf("[ERROR] Conflict between `default_backend_http_settings_name` and `redirect_configuration_name` (default back-end settings not applicable when redirection specified)") + } + + if applicationGatewayHasSubResource(ruleProps.BackendHTTPSettings) && applicationGatewayHasSubResource(ruleProps.RedirectConfiguration) { + return nil, fmt.Errorf("[ERROR] Conflict between `backend_http_settings_name` and `redirect_configuration_name` (back-end settings not applicable when redirection specified)") + } + if pool := ruleProps.BackendAddressPool; pool != nil && pool.ID != nil { poolId, err := parseAzureResourceID(*pool.ID) if err != nil { @@ -2287,6 +2571,16 @@ func flattenApplicationGatewayURLPathMaps(input *[]network.ApplicationGatewayURL ruleOutput["backend_http_settings_id"] = *backend.ID } + if redirect := ruleProps.RedirectConfiguration; redirect != nil && redirect.ID != nil { + redirectId, err := parseAzureResourceID(*redirect.ID) + if err != nil { + return nil, err + } + redirectConfigurationName2 := redirectId.Path["redirectConfigurations"] + ruleOutput["redirect_configuration_name"] = redirectConfigurationName2 + ruleOutput["redirect_configuration_id"] = *redirect.ID + } + pathOutputs := make([]interface{}, 0) if paths := ruleProps.Paths; paths != nil { for _, rulePath := range *paths { diff --git a/azurerm/resource_arm_application_gateway_test.go b/azurerm/resource_arm_application_gateway_test.go index 7e4fd8a43d42..fd04f95dbb86 100644 --- a/azurerm/resource_arm_application_gateway_test.go +++ b/azurerm/resource_arm_application_gateway_test.go @@ -188,6 +188,68 @@ func TestAccAzureRMApplicationGateway_pathBasedRouting(t *testing.T) { }) } +func TestAccAzureRMApplicationGateway_routingRedirect_httpListener(t *testing.T) { + resourceName := "azurerm_application_gateway.test" + ri := tf.AccRandTimeInt() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApplicationGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApplicationGateway_routingRedirect_httpListener(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApplicationGatewayExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "redirect_configuration.0.name"), + resource.TestCheckResourceAttr(resourceName, "redirect_configuration.0.redirect_type", "Temporary"), + resource.TestCheckResourceAttrSet(resourceName, "redirect_configuration.0.target_listener_name"), + resource.TestCheckResourceAttr(resourceName, "redirect_configuration.0.include_path", "true"), + resource.TestCheckResourceAttr(resourceName, "redirect_configuration.0.include_query_string", "false"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMApplicationGateway_routingRedirect_pathBased(t *testing.T) { + resourceName := "azurerm_application_gateway.test" + ri := tf.AccRandTimeInt() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApplicationGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApplicationGateway_routingRedirect_pathBased(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApplicationGatewayExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "redirect_configuration.0.name"), + resource.TestCheckResourceAttr(resourceName, "redirect_configuration.0.redirect_type", "Found"), + resource.TestCheckResourceAttr(resourceName, "redirect_configuration.0.target_url", "http://www.example.com"), + resource.TestCheckResourceAttr(resourceName, "redirect_configuration.0.include_query_string", "true"), + resource.TestCheckResourceAttrSet(resourceName, "redirect_configuration.1.name"), + resource.TestCheckResourceAttr(resourceName, "redirect_configuration.1.redirect_type", "Permanent"), + resource.TestCheckResourceAttrSet(resourceName, "redirect_configuration.1.target_listener_name"), + resource.TestCheckResourceAttr(resourceName, "redirect_configuration.1.include_path", "false"), + resource.TestCheckResourceAttr(resourceName, "redirect_configuration.1.include_query_string", "false"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAzureRMApplicationGateway_customErrorConfigurations(t *testing.T) { resourceName := "azurerm_application_gateway.test" ri := tf.AccRandTimeInt() @@ -1028,6 +1090,229 @@ resource "azurerm_application_gateway" "test" { `, template, rInt) } +func testAccAzureRMApplicationGateway_routingRedirect_httpListener(rInt int, location string) string { + template := testAccAzureRMApplicationGateway_template(rInt, location) + return fmt.Sprintf(` +%s + +# since these variables are re-used - a locals block makes this more maintainable +locals { + backend_address_pool_name = "${azurerm_virtual_network.test.name}-beap" + frontend_port_name = "${azurerm_virtual_network.test.name}-feport" + frontend_port_name2 = "${azurerm_virtual_network.test.name}-feport2" + frontend_ip_configuration_name = "${azurerm_virtual_network.test.name}-feip" + http_setting_name = "${azurerm_virtual_network.test.name}-be-htst" + listener_name = "${azurerm_virtual_network.test.name}-httplstn" + target_listener_name = "${azurerm_virtual_network.test.name}-trgthttplstn" + request_routing_rule_name = "${azurerm_virtual_network.test.name}-rqrt" + path_rule_name = "${azurerm_virtual_network.test.name}-pathrule1" + url_path_map_name = "${azurerm_virtual_network.test.name}-urlpath1" + redirect_configuration_name = "${azurerm_virtual_network.test.name}-Port80To8888Redirect" +} + +resource "azurerm_application_gateway" "test" { + name = "acctestag-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + + sku { + name = "Standard_Small" + tier = "Standard" + capacity = 2 + } + + gateway_ip_configuration { + name = "my-gateway-ip-configuration" + subnet_id = "${azurerm_subnet.test.id}" + } + + frontend_port { + name = "${local.frontend_port_name}" + port = 80 + } + + frontend_port { + name = "${local.frontend_port_name2}" + port = 8888 + } + + frontend_ip_configuration { + name = "${local.frontend_ip_configuration_name}" + public_ip_address_id = "${azurerm_public_ip.test.id}" + } + + backend_address_pool { + name = "${local.backend_address_pool_name}" + } + + backend_http_settings { + name = "${local.http_setting_name}" + cookie_based_affinity = "Disabled" + port = 80 + protocol = "Http" + request_timeout = 1 + } + + http_listener { + name = "${local.listener_name}" + frontend_ip_configuration_name = "${local.frontend_ip_configuration_name}" + frontend_port_name = "${local.frontend_port_name}" + protocol = "Http" + } + + http_listener { + name = "${local.target_listener_name}" + frontend_ip_configuration_name = "${local.frontend_ip_configuration_name}" + frontend_port_name = "${local.frontend_port_name2}" + protocol = "Http" + } + + request_routing_rule { + name = "${local.request_routing_rule_name}" + rule_type = "Basic" + http_listener_name = "${local.listener_name}" + redirect_configuration_name = "${local.redirect_configuration_name}" + } + + redirect_configuration { + name = "${local.redirect_configuration_name}" + redirect_type = "Temporary" + target_listener_name = "${local.target_listener_name}" + include_path = true + include_query_string = false + } +} +`, template, rInt) +} + +func testAccAzureRMApplicationGateway_routingRedirect_pathBased(rInt int, location string) string { + template := testAccAzureRMApplicationGateway_template(rInt, location) + return fmt.Sprintf(` +%s + +# since these variables are re-used - a locals block makes this more maintainable +locals { + backend_address_pool_name = "${azurerm_virtual_network.test.name}-beap" + frontend_port_name = "${azurerm_virtual_network.test.name}-feport" + frontend_port_name2 = "${azurerm_virtual_network.test.name}-feport2" + frontend_ip_configuration_name = "${azurerm_virtual_network.test.name}-feip" + http_setting_name = "${azurerm_virtual_network.test.name}-be-htst" + listener_name = "${azurerm_virtual_network.test.name}-httplstn" + target_listener_name = "${azurerm_virtual_network.test.name}-trgthttplstn" + request_routing_rule_name = "${azurerm_virtual_network.test.name}-rqrt" + path_rule_name = "${azurerm_virtual_network.test.name}-pathrule1" + path_rule_name2 = "${azurerm_virtual_network.test.name}-pathrule2" + url_path_map_name = "${azurerm_virtual_network.test.name}-urlpath1" + redirect_configuration_name = "${azurerm_virtual_network.test.name}-PathRedirect" + redirect_configuration_name2 = "${azurerm_virtual_network.test.name}-PathRedirect2" + target_url = "http://www.example.com" +} + +resource "azurerm_application_gateway" "test" { + name = "acctestag-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + + sku { + name = "Standard_Small" + tier = "Standard" + capacity = 2 + } + + gateway_ip_configuration { + name = "my-gateway-ip-configuration" + subnet_id = "${azurerm_subnet.test.id}" + } + + frontend_port { + name = "${local.frontend_port_name}" + port = 80 + } + + frontend_port { + name = "${local.frontend_port_name2}" + port = 8888 + } + + frontend_ip_configuration { + name = "${local.frontend_ip_configuration_name}" + public_ip_address_id = "${azurerm_public_ip.test.id}" + } + + backend_address_pool { + name = "${local.backend_address_pool_name}" + } + + backend_http_settings { + name = "${local.http_setting_name}" + cookie_based_affinity = "Disabled" + port = 80 + protocol = "Http" + request_timeout = 1 + } + + http_listener { + name = "${local.listener_name}" + frontend_ip_configuration_name = "${local.frontend_ip_configuration_name}" + frontend_port_name = "${local.frontend_port_name}" + protocol = "Http" + } + + http_listener { + name = "${local.target_listener_name}" + frontend_ip_configuration_name = "${local.frontend_ip_configuration_name}" + frontend_port_name = "${local.frontend_port_name2}" + protocol = "Http" + } + + request_routing_rule { + name = "${local.request_routing_rule_name}" + rule_type = "PathBasedRouting" + url_path_map_name = "${local.url_path_map_name}" + http_listener_name = "${local.listener_name}" + } + + url_path_map { + name = "${local.url_path_map_name}" + default_redirect_configuration_name = "${local.redirect_configuration_name}" + + path_rule { + name = "${local.path_rule_name}" + redirect_configuration_name = "${local.redirect_configuration_name}" + paths = [ + "/test", + ] + } + + path_rule { + name = "${local.path_rule_name2}" + redirect_configuration_name = "${local.redirect_configuration_name2}" + + paths = [ + "/test2", + ] + } + + } + + redirect_configuration { + name = "${local.redirect_configuration_name}" + redirect_type = "Found" + target_url = "${local.target_url}" + include_query_string = true + } + + redirect_configuration { + name = "${local.redirect_configuration_name2}" + redirect_type = "Permanent" + target_listener_name = "${local.target_listener_name}" + include_path = false + include_query_string = false + } +} +`, template, rInt) +} + func testAccAzureRMApplicationGateway_probes(rInt int, location string) string { template := testAccAzureRMApplicationGateway_template(rInt, location) return fmt.Sprintf(` diff --git a/website/docs/r/application_gateway.html.markdown b/website/docs/r/application_gateway.html.markdown index b38cdcf18f1b..cf405ba6086e 100644 --- a/website/docs/r/application_gateway.html.markdown +++ b/website/docs/r/application_gateway.html.markdown @@ -54,6 +54,7 @@ locals { http_setting_name = "${azurerm_virtual_network.test.name}-be-htst" listener_name = "${azurerm_virtual_network.test.name}-httplstn" request_routing_rule_name = "${azurerm_virtual_network.test.name}-rqrt" + redirect_configuration_name = "${azurerm_virtual_network.test.name}-rdrcfg" } resource "azurerm_application_gateway" "network" { @@ -103,11 +104,11 @@ resource "azurerm_application_gateway" "network" { } request_routing_rule { - name = "${local.request_routing_rule_name}" - rule_type = "Basic" - http_listener_name = "${local.listener_name}" - backend_address_pool_name = "${local.backend_address_pool_name}" - backend_http_settings_name = "${local.http_setting_name}" + name = "${local.request_routing_rule_name}" + rule_type = "Basic" + http_listener_name = "${local.listener_name}" + backend_address_pool_name = "${local.backend_address_pool_name}" + backend_http_settings_name = "${local.http_setting_name}" } } ``` @@ -158,6 +159,8 @@ The following arguments are supported: * `custom_error_configuration` - (Optional) One or more `custom_error_configuration` blocks as defined below. +* `redirect_configuration` - (Optional) A `redirect_configuration` block as defined below. + --- A `authentication_certificate` block supports the following: @@ -289,9 +292,11 @@ A `path_rule` block supports the following: * `paths` - (Required) A list of Paths used in this Path Rule. -* `backend_address_pool_name` - (Required) The Name of the Backend Address Pool to use for this Path Rule. +* `backend_address_pool_name` - (Optional) The Name of the Backend Address Pool to use for this Path Rule. Cannot be set if `redirect_configuration_name` is set. + +* `backend_http_settings_name` - (Optional) The Name of the Backend HTTP Settings Collection to use for this Path Rule. Cannot be set if `redirect_configuration_name` is set. -* `backend_http_settings_name` - (Required) The Name of the Backend HTTP Settings Collection to use for this Path Rule. +* `redirect_configuration_name` - (Optional) The Name of a Redirect Configuration to use for this Path Rule. Cannot be set if `backend_address_pool_name` or `backend_http_settings_name` is set. --- @@ -327,9 +332,11 @@ A `request_routing_rule` block supports the following: * `http_listener_name` - (Required) The Name of the HTTP Listener which should be used for this Routing Rule. -* `backend_address_pool_name` - (Optional) The Name of the Backend Address Pool which should be used for this Routing Rule. +* `backend_address_pool_name` - (Optional) The Name of the Backend Address Pool which should be used for this Routing Rule. Cannot be set if `redirect_configuration_name` is set. + +* `backend_http_settings_name` - (Optional) The Name of the Backend HTTP Settings Collection which should be used for this Routing Rule. Cannot be set if `redirect_configuration_name` is set. -* `backend_http_settings_name` - (Optional) The Name of the Backend HTTP Settings Collection which should be used for this Routing Rule. +* `redirect_configuration_name` - (Optional) The Name of the Redirect Configuration which should be used for this Routing Rule. Cannot be set if either `backend_address_pool_name` or `backend_http_settings_name` is set. * `url_path_map_name` - (Optional) The Name of the URL Path Map which should be associated with this Routing Rule. @@ -359,9 +366,11 @@ A `url_path_map` block supports the following: * `name` - (Required) The Name of the URL Path Map. -* `default_backend_address_pool_name` - (Required) The Name of the Default Backend Address Pool which should be used for this URL Path Map. +* `default_backend_address_pool_name` - (Optional) The Name of the Default Backend Address Pool which should be used for this URL Path Map. Cannot be set if there are path_rules with re-direct configurations set. -* `default_backend_http_settings_name` - (Required) The Name of the Default Backend HTTP Settings Collection which should be used for this URL Path Map. +* `default_backend_http_settings_name` - (Optional) The Name of the Default Backend HTTP Settings Collection which should be used for this URL Path Map. Cannot be set if there are path_rules with re-direct configurations set. + +* `default_redirect_configuration_name` - (Optional) The Name of the Default Redirect Configuration which should be used for this URL Path Map. Cannot be set if there are path_rules with Backend Address Pool or HTTP Settings set. * `path_rule` - (Required) One or more `path_rule` blocks as defined above. @@ -391,6 +400,22 @@ A `custom_error_configuration` block supports the following: * `custom_error_page_url` - (Required) Error page URL of the application gateway customer error. +--- + +A `redirect_configuration` block supports the following: + +* `name` - (Required) Unique name of the redirect configuration block + +* `redirect_type` - (Required) The type of redirect. Possible values are `Permanent`, `Temporary`, `Found` and `SeeOther` + +* `target_listener_name` - (Optional) The name of the listener to redirect to. Cannot be set if `target_url` is set. + +* `target_url` - (Optional) The Url to redirect the request to. Cannot be set if `target_listener_name` is set. + +* `include_path` - (Optional) Whether or not to include the path in the redirected Url. Defaults to `false` + +* `include_query_string` - (Optional) Whether or not to include the query string in the redirected Url. Default to `false` + ## Attributes Reference The following attributes are exported: @@ -423,6 +448,7 @@ The following attributes are exported: * `custom_error_configuration` - A list of `custom_error_configuration` blocks as defined below. +* `redirect_configuration` - A list of `redirect_configuration` blocks as defined below. --- A `authentication_certificate` block exports the following: @@ -489,6 +515,8 @@ A `path_rule` block exports the following: * `backend_http_settings_id` - The ID of the Backend HTTP Settings Collection used in this Path Rule. +* `redirect_configuration_id` - The ID of the Redirect Configuration used in this Path Rule. + --- A `probe` block exports the following: @@ -507,6 +535,8 @@ A `request_routing_rule` block exports the following: * `backend_http_settings_id` - The ID of the associated Backend HTTP Settings Configuration. +* `redirect_configuration_id` - The ID of the associated Redirect Configuration. + * `url_path_map_id` - The ID of the associated URL Path Map. --- @@ -527,6 +557,8 @@ A `url_path_map` block exports the following: * `default_backend_http_settings_id` - The ID of the Default Backend HTTP Settings Collection. +* `default_redirect_configuration_id` - The ID of the Default Redirect Configuration. + * `path_rule` - A list of `path_rule` blocks as defined above. --- @@ -535,6 +567,12 @@ A `custom_error_configuration` block exports the following: * `id` - The ID of the Custom Error Configuration. +--- + +A `redirect_configuration` block exports the following: + +* `id` - The ID of the Redirect Configuration. + ## Import Application Gateway's can be imported using the `resource id`, e.g.