diff --git a/azurerm/resource_arm_application_gateway.go b/azurerm/resource_arm_application_gateway.go index 8445629a0e38..0cab82f6c2b6 100644 --- a/azurerm/resource_arm_application_gateway.go +++ b/azurerm/resource_arm_application_gateway.go @@ -116,6 +116,12 @@ func resourceArmApplicationGateway() *schema.Resource { }, true), }, + "pick_host_name_from_backend_address": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "request_timeout": { Type: schema.TypeInt, Optional: true, @@ -499,7 +505,7 @@ func resourceArmApplicationGateway() *schema.Resource { "host": { Type: schema.TypeString, - Required: true, + Optional: true, }, "interval": { @@ -517,6 +523,12 @@ func resourceArmApplicationGateway() *schema.Resource { Required: true, }, + "pick_host_name_from_backend_http_settings": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "minimum_servers": { Type: schema.TypeInt, Optional: true, @@ -789,6 +801,20 @@ func resourceArmApplicationGatewayCreateUpdate(d *schema.ResourceData, meta inte }, } + for _, probe := range *probes { + probeProperties := *probe.ApplicationGatewayProbePropertiesFormat + host := *probeProperties.Host + pick := *probeProperties.PickHostNameFromBackendHTTPSettings + + if host == "" && !pick { + return fmt.Errorf("One of `host` or `pick_host_name_from_backend_http_settings` must be set") + } + + if host != "" && pick { + return fmt.Errorf("Only one of `host` or `pick_host_name_from_backend_http_settings` can be set") + } + } + if _, ok := d.GetOk("waf_configuration"); ok { gateway.ApplicationGatewayPropertiesFormat.WebApplicationFirewallConfiguration = expandApplicationGatewayWafConfig(d) } @@ -1092,15 +1118,17 @@ func expandApplicationGatewayBackendHTTPSettings(d *schema.ResourceData, gateway port := int32(v["port"].(int)) protocol := v["protocol"].(string) cookieBasedAffinity := v["cookie_based_affinity"].(string) + pickHostNameFromBackendAddress := v["pick_host_name_from_backend_address"].(bool) requestTimeout := int32(v["request_timeout"].(int)) setting := network.ApplicationGatewayBackendHTTPSettings{ Name: &name, ApplicationGatewayBackendHTTPSettingsPropertiesFormat: &network.ApplicationGatewayBackendHTTPSettingsPropertiesFormat{ - CookieBasedAffinity: network.ApplicationGatewayCookieBasedAffinity(cookieBasedAffinity), - Port: utils.Int32(port), - Protocol: network.ApplicationGatewayProtocol(protocol), - RequestTimeout: utils.Int32(requestTimeout), + CookieBasedAffinity: network.ApplicationGatewayCookieBasedAffinity(cookieBasedAffinity), + PickHostNameFromBackendAddress: utils.Bool(pickHostNameFromBackendAddress), + Port: utils.Int32(port), + Protocol: network.ApplicationGatewayProtocol(protocol), + RequestTimeout: utils.Int32(requestTimeout), }, } @@ -1158,6 +1186,9 @@ func flattenApplicationGatewayBackendHTTPSettings(input *[]network.ApplicationGa if port := props.Port; port != nil { output["port"] = int(*port) } + if pickHostNameFromBackendAddress := props.PickHostNameFromBackendAddress; pickHostNameFromBackendAddress != nil { + output["pick_host_name_from_backend_address"] = *pickHostNameFromBackendAddress + } output["protocol"] = string(props.Protocol) if timeout := props.RequestTimeout; timeout != nil { output["request_timeout"] = int(*timeout) @@ -1549,17 +1580,19 @@ func expandApplicationGatewayProbes(d *schema.ResourceData) *[]network.Applicati protocol := v["protocol"].(string) timeout := int32(v["timeout"].(int)) unhealthyThreshold := int32(v["unhealthy_threshold"].(int)) + pickHostNameFromBackendHTTPSettings := v["pick_host_name_from_backend_http_settings"].(bool) output := network.ApplicationGatewayProbe{ Name: utils.String(name), ApplicationGatewayProbePropertiesFormat: &network.ApplicationGatewayProbePropertiesFormat{ - Host: utils.String(host), - Interval: utils.Int32(interval), - MinServers: utils.Int32(minServers), - Path: utils.String(probePath), - Protocol: network.ApplicationGatewayProtocol(protocol), - Timeout: utils.Int32(timeout), - UnhealthyThreshold: utils.Int32(unhealthyThreshold), + Host: utils.String(host), + Interval: utils.Int32(interval), + MinServers: utils.Int32(minServers), + Path: utils.String(probePath), + Protocol: network.ApplicationGatewayProtocol(protocol), + Timeout: utils.Int32(timeout), + UnhealthyThreshold: utils.Int32(unhealthyThreshold), + PickHostNameFromBackendHTTPSettings: utils.Bool(pickHostNameFromBackendHTTPSettings), }, } @@ -1625,6 +1658,10 @@ func flattenApplicationGatewayProbes(input *[]network.ApplicationGatewayProbe) [ output["unhealthy_threshold"] = int(*threshold) } + if pickHostNameFromBackendHTTPSettings := props.PickHostNameFromBackendHTTPSettings; pickHostNameFromBackendHTTPSettings != nil { + output["pick_host_name_from_backend_http_settings"] = *pickHostNameFromBackendHTTPSettings + } + if minServers := props.MinServers; minServers != nil { output["minimum_servers"] = int(*minServers) } diff --git a/azurerm/resource_arm_application_gateway_test.go b/azurerm/resource_arm_application_gateway_test.go index 3bca35c59e64..d4fab5c169ca 100644 --- a/azurerm/resource_arm_application_gateway_test.go +++ b/azurerm/resource_arm_application_gateway_test.go @@ -222,6 +222,56 @@ func TestAccAzureRMApplicationGateway_probes(t *testing.T) { }) } +func TestAccAzureRMApplicationGateway_probesPickHostNameFromBackendHTTPSettings(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_probesPickHostNameFromBackendHTTPSettings(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApplicationGatewayExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "probe.0.pick_host_name_from_backend_http_settings", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMApplicationGateway_settingsPickHostNameFromBackendAddress(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_settingsPickHostNameFromBackendAddress(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApplicationGatewayExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "backend_http_settings.0.pick_host_name_from_backend_address", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAzureRMApplicationGateway_sslCertificate(t *testing.T) { resourceName := "azurerm_application_gateway.test" ri := tf.AccRandTimeInt() @@ -837,6 +887,162 @@ resource "azurerm_application_gateway" "test" { `, template, rInt) } +func testAccAzureRMApplicationGateway_probesPickHostNameFromBackendHTTPSettings(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_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" + probe_name = "${azurerm_virtual_network.test.name}-probe" + request_routing_rule_name = "${azurerm_virtual_network.test.name}-rqrt" +} + +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_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" + pick_host_name_from_backend_address = true + port = 80 + probe_name = "${local.probe_name}" + protocol = "Http" + request_timeout = 1 + } + + probe { + name = "${local.probe_name}" + protocol = "Http" + path = "/test" + timeout = 120 + interval = 300 + unhealthy_threshold = 8 + pick_host_name_from_backend_http_settings = true + } + + http_listener { + name = "${local.listener_name}" + frontend_ip_configuration_name = "${local.frontend_ip_configuration_name}" + frontend_port_name = "${local.frontend_port_name}" + protocol = "Http" + } + + 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}" + } +} +`, template, rInt) +} + +func testAccAzureRMApplicationGateway_settingsPickHostNameFromBackendAddress(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_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" + request_routing_rule_name = "${azurerm_virtual_network.test.name}-rqrt" +} + +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_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" + pick_host_name_from_backend_address = true + 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" + } + + 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}" + } +} +`, template, rInt) +} + func testAccAzureRMApplicationGateway_sslCertificate(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 a3aae71cf66c..98a23e7afc78 100644 --- a/website/docs/r/application_gateway.html.markdown +++ b/website/docs/r/application_gateway.html.markdown @@ -191,6 +191,8 @@ A `backend_http_settings` block supports the following: * `request_timeout` - (Required) The request timeout in seconds, which must be between 1 and 86400 seconds. +* `pick_host_name_from_backend_address` - (Optional) Whether host header should be picked from the host name of the backend server. Defaults to `false`. + * `authentication_certificate` - (Optional) One or more `authentication_certificate` blocks. --- @@ -267,7 +269,7 @@ A `path_rule` block supports the following: A `probe` block support the following: -* `host` - (Required) The Hostname used for this Probe. If the Application Gateway is configured for a single site, by default the Host name should be specified as ‘127.0.0.1’, unless otherwise configured in custom probe. +* `host` - (Optional) The Hostname used for this Probe. If the Application Gateway is configured for a single site, by default the Host name should be specified as ‘127.0.0.1’, unless otherwise configured in custom probe. Cannot be set if `pick_host_name_from_backend_http_settings` is set to `true`. * `interval` - (Required) The Interval between two consecutive probes in seconds. Possible values range from 1 second to a maximum of 86,400 seconds. @@ -281,6 +283,8 @@ A `probe` block support the following: * `unhealthy_threshold` - (Required) The Unhealthy Threshold for this Probe, which indicates the amount of retries which should be attempted before a node is deemed unhealthy. Possible values are from 1 - 20 seconds. +* `pick_host_name_from_backend_http_settings` - (Optional) Whether the host header should be picked from the backend http settings. Defaults to `false`. + * `match` - (Optional) A `match` block as defined above. * `minimum_servers` - (Optional) The minimum number of servers that are always marked as healthy. Defaults to `0`.