diff --git a/azurerm/resource_arm_application_gateway.go b/azurerm/resource_arm_application_gateway.go index 7edfdb52db7a..ef093d4e4489 100644 --- a/azurerm/resource_arm_application_gateway.go +++ b/azurerm/resource_arm_application_gateway.go @@ -176,6 +176,26 @@ func resourceArmApplicationGateway() *schema.Resource { }, }, + "connection_draining": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Required: true, + }, + + "drain_timeout_sec": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 3600), + }, + }, + }, + }, + "probe_name": { Type: schema.TypeString, Optional: true, @@ -1247,6 +1267,7 @@ func expandApplicationGatewayBackendHTTPSettings(d *schema.ResourceData, gateway Port: utils.Int32(port), Protocol: network.ApplicationGatewayProtocol(protocol), RequestTimeout: utils.Int32(requestTimeout), + ConnectionDraining: expandApplicationGatewayConnectionDraining(v), }, } @@ -1305,13 +1326,18 @@ func flattenApplicationGatewayBackendHTTPSettings(input *[]network.ApplicationGa if path := props.Path; path != nil { output["path"] = *path } + output["connection_draining"] = flattenApplicationGatewayConnectionDraining(props.ConnectionDraining) + 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) } @@ -1357,6 +1383,37 @@ func flattenApplicationGatewayBackendHTTPSettings(input *[]network.ApplicationGa return results, nil } +func expandApplicationGatewayConnectionDraining(d map[string]interface{}) *network.ApplicationGatewayConnectionDraining { + connectionsRaw := d["connection_draining"].([]interface{}) + + if len(connectionsRaw) <= 0 { + return nil + } + + connectionRaw := connectionsRaw[0].(map[string]interface{}) + + return &network.ApplicationGatewayConnectionDraining{ + Enabled: utils.Bool(connectionRaw["enabled"].(bool)), + DrainTimeoutInSec: utils.Int32(int32(connectionRaw["drain_timeout_sec"].(int))), + } +} + +func flattenApplicationGatewayConnectionDraining(input *network.ApplicationGatewayConnectionDraining) []interface{} { + result := map[string]interface{}{} + if input == nil { + return []interface{}{} + } + + if v := input.Enabled; v != nil { + result["enabled"] = *v + } + if v := input.DrainTimeoutInSec; v != nil { + result["drain_timeout_sec"] = *v + } + + return []interface{}{result} +} + func expandApplicationGatewaySslPolicy(d *schema.ResourceData) *network.ApplicationGatewaySslPolicy { vs := d.Get("disabled_ssl_protocols").([]interface{}) results := make([]network.ApplicationGatewaySslProtocol, 0) diff --git a/azurerm/resource_arm_application_gateway_test.go b/azurerm/resource_arm_application_gateway_test.go index 1f1c16c56da7..9a1b2e0bdabb 100644 --- a/azurerm/resource_arm_application_gateway_test.go +++ b/azurerm/resource_arm_application_gateway_test.go @@ -357,6 +357,48 @@ func TestAccAzureRMApplicationGateway_webApplicationFirewall(t *testing.T) { }) } +func TestAccAzureRMApplicationGateway_connectionDraining(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_connectionDraining(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApplicationGatewayExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "backend_http_settings.0.connection_draining.0.enabled", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAzureRMApplicationGateway_basic(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApplicationGatewayExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "sku.0.name", "Standard_Small"), + resource.TestCheckResourceAttr(resourceName, "sku.0.tier", "Standard"), + resource.TestCheckResourceAttr(resourceName, "sku.0.capacity", "2"), + resource.TestCheckResourceAttr(resourceName, "waf_configuration.#", "0"), + resource.TestCheckNoResourceAttr(resourceName, "backend_http_settings.0.connection_draining.0.enabled"), + resource.TestCheckNoResourceAttr(resourceName, "backend_http_settings.0.connection_draining.0.drain_timeout_sec"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testCheckAzureRMApplicationGatewayExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] @@ -1441,6 +1483,83 @@ resource "azurerm_application_gateway" "test" { `, template, rInt) } +func testAccAzureRMApplicationGateway_connectionDraining(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}" + enable_http2 = true + + 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" + port = 80 + protocol = "Http" + request_timeout = 1 + + connection_draining { + enabled = true + drain_timeout_sec = 1984 + } + } + + 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_template(rInt int, location string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { diff --git a/website/docs/r/application_gateway.html.markdown b/website/docs/r/application_gateway.html.markdown index 10a54861d987..411d76cc0708 100644 --- a/website/docs/r/application_gateway.html.markdown +++ b/website/docs/r/application_gateway.html.markdown @@ -206,8 +206,19 @@ A `backend_http_settings` block supports the following: * `authentication_certificate` - (Optional) One or more `authentication_certificate` blocks. +* `connection_draining` - (Optional) A `connection_draining` block as defined below. + +--- + +A `connection_draining` block supports the following: + +* `enabled` - (Required) If connection draining is enabled or not. + +* `drain_timeout_sec` - (Required) The number of seconds connection draining is active. Acceptable values are from `1` second to `3600` seconds. + --- + A `frontend_ip_configuration` block supports the following: * `name` - (Required) The name of the Frontend IP Configuration.