Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Bug Fix: azurerm_application_gateway - updatable gateway subnet #3437

Merged
merged 2 commits into from
May 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 55 additions & 3 deletions azurerm/resource_arm_application_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ func resourceArmApplicationGateway() *schema.Resource {
"gateway_ip_configuration": {
Type: schema.TypeList,
Required: true,
MaxItems: 2,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Expand Down Expand Up @@ -1094,7 +1095,7 @@ func resourceArmApplicationGatewayCreateUpdate(d *schema.ResourceData, meta inte
backendHTTPSettingsCollection := expandApplicationGatewayBackendHTTPSettings(d, gatewayID)
frontendIPConfigurations := expandApplicationGatewayFrontendIPConfigurations(d)
frontendPorts := expandApplicationGatewayFrontendPorts(d)
gatewayIPConfigurations := expandApplicationGatewayIPConfigurations(d)
gatewayIPConfigurations, stopApplicationGateway := expandApplicationGatewayIPConfigurations(d)
httpListeners := expandApplicationGatewayHTTPListeners(d, gatewayID)
probes := expandApplicationGatewayProbes(d)
sku := expandApplicationGatewaySku(d)
Expand Down Expand Up @@ -1175,6 +1176,17 @@ func resourceArmApplicationGatewayCreateUpdate(d *schema.ResourceData, meta inte
gateway.ApplicationGatewayPropertiesFormat.WebApplicationFirewallConfiguration = expandApplicationGatewayWafConfig(d)
}

if stopApplicationGateway {
future, err := client.Stop(ctx, resGroup, name)
if err != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What will happen here if it's already stopped? 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just checked by adding another stop section and it passed just fine. I think we're good!

return fmt.Errorf("Error Stopping Application Gateway %q (Resource Group %q): %+v", name, resGroup, err)
}

if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("Error waiting for the Application Gateway %q (Resource Group %q) to stop: %+v", name, resGroup, err)
}
}

future, err := client.CreateOrUpdate(ctx, resGroup, name, gateway)
if err != nil {
return fmt.Errorf("Error Creating/Updating Application Gateway %q (Resource Group %q): %+v", name, resGroup, err)
Expand All @@ -1184,6 +1196,17 @@ func resourceArmApplicationGatewayCreateUpdate(d *schema.ResourceData, meta inte
return fmt.Errorf("Error waiting for the create/update of Application Gateway %q (Resource Group %q): %+v", name, resGroup, err)
}

if stopApplicationGateway {
future, err := client.Start(ctx, resGroup, name)
if err != nil {
return fmt.Errorf("Error Starting Application Gateway %q (Resource Group %q): %+v", name, resGroup, err)
}

if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("Error waiting for the Application Gateway %q (Resource Group %q) to start: %+v", name, resGroup, err)
}
}

read, err := client.Get(ctx, resGroup, name)
if err != nil {
return fmt.Errorf("Error retrieving Application Gateway %q (Resource Group %q): %+v", name, resGroup, err)
Expand Down Expand Up @@ -1839,9 +1862,10 @@ func flattenApplicationGatewayHTTPListeners(input *[]network.ApplicationGatewayH
return results, nil
}

func expandApplicationGatewayIPConfigurations(d *schema.ResourceData) *[]network.ApplicationGatewayIPConfiguration {
func expandApplicationGatewayIPConfigurations(d *schema.ResourceData) (*[]network.ApplicationGatewayIPConfiguration, bool) {
vs := d.Get("gateway_ip_configuration").([]interface{})
results := make([]network.ApplicationGatewayIPConfiguration, 0)
stopApplicationGateway := false

for _, configRaw := range vs {
data := configRaw.(map[string]interface{})
Expand All @@ -1860,7 +1884,35 @@ func expandApplicationGatewayIPConfigurations(d *schema.ResourceData) *[]network
results = append(results, output)
}

return &results
if d.HasChange("gateway_ip_configuration") {
oldRaw, newRaw := d.GetChange("gateway_ip_configuration")
oldVS := oldRaw.([]interface{})
newVS := newRaw.([]interface{})

// If we're creating the application gateway return the current gateway ip configuration.
if len(oldVS) == 0 {
return &results, stopApplicationGateway
}

// The application gateway needs to be stopped if a gateway ip configuration is added or removed
if len(oldVS) != len(newVS) {
stopApplicationGateway = true
}

for i, configRaw := range newVS {
newData := configRaw.(map[string]interface{})
oldData := oldVS[i].(map[string]interface{})

newSubnetID := newData["subnet_id"].(string)
oldSubnetID := oldData["subnet_id"].(string)
// The application gateway needs to be shutdown if the subnet ids don't match
if newSubnetID != oldSubnetID {
stopApplicationGateway = true
}
}
}

return &results, stopApplicationGateway
}

func flattenApplicationGatewayIPConfigurations(input *[]network.ApplicationGatewayIPConfiguration) []interface{} {
Expand Down
114 changes: 114 additions & 0 deletions azurerm/resource_arm_application_gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,41 @@ func TestAccAzureRMApplicationGateway_cookieAffinity(t *testing.T) {
})
}

func TestAccAzureRMApplicationGateway_gatewayIP(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_basic(ri, testLocation()),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMApplicationGatewayExists(resourceName),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccAzureRMApplicationGateway_gatewayIPUpdated(ri, testLocation()),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMApplicationGatewayExists(resourceName),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testCheckAzureRMApplicationGatewayExists(resourceName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[resourceName]
Expand Down Expand Up @@ -3260,3 +3295,82 @@ resource "azurerm_application_gateway" "test" {
}
`, template, rInt)
}

func testAccAzureRMApplicationGateway_gatewayIPUpdated(rInt int, location string) string {
template := testAccAzureRMApplicationGateway_template(rInt, location)
return fmt.Sprintf(`
%s

resource "azurerm_subnet" "test1" {
name = "subnet1-%d"
resource_group_name = "${azurerm_resource_group.test.name}"
virtual_network_name = "${azurerm_virtual_network.test.name}"
address_prefix = "10.0.1.0/24"
}


# 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.test1.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
}

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, rInt)
}