diff --git a/backend/local/counthookaction_string.go b/backend/local/counthookaction_string.go index 92b2624a531b..574a8c6cb27c 100644 --- a/backend/local/counthookaction_string.go +++ b/backend/local/counthookaction_string.go @@ -1,4 +1,4 @@ -// Code generated by "stringer -type=countHookAction hook_count_action.go"; DO NOT EDIT. +// Code generated by "stringer -type=countHookAction hook_count_action.go"; DO NOT EDIT package local diff --git a/backend/operationtype_string.go b/backend/operationtype_string.go index 15fbba6eccef..6edadb919c0e 100644 --- a/backend/operationtype_string.go +++ b/backend/operationtype_string.go @@ -1,4 +1,4 @@ -// Code generated by "stringer -type=OperationType operation_type.go"; DO NOT EDIT. +// Code generated by "stringer -type=OperationType operation_type.go"; DO NOT EDIT package backend diff --git a/builtin/providers/azurerm/resource_arm_subnet_test.go b/builtin/providers/azurerm/resource_arm_subnet_test.go index 5f1f2bcbe4e5..56e740ac6398 100644 --- a/builtin/providers/azurerm/resource_arm_subnet_test.go +++ b/builtin/providers/azurerm/resource_arm_subnet_test.go @@ -2,7 +2,9 @@ package azurerm import ( "fmt" + "log" "net/http" + "strings" "testing" "github.com/hashicorp/terraform/helper/acctest" @@ -30,6 +32,55 @@ func TestAccAzureRMSubnet_basic(t *testing.T) { }) } +func TestAccAzureRMSubnet_routeTable(t *testing.T) { + + ri := acctest.RandInt() + initConfig := fmt.Sprintf(testAccAzureRMSubnet_routeTable, ri, ri, ri) + updatedConfig := fmt.Sprintf(testAccAzureRMSubnet_updatedRouteTable, ri, ri, ri) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMSubnetDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: initConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMSubnetExists("azurerm_subnet.rtTable2"), + ), + }, + + resource.TestStep{ + Config: updatedConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMSubnetRouteTableExists("azurerm_subnet.rtTable2", "rtTable2-RT"), + ), + }, + }, + }) +} + +func TestAccAzureRMSubnet_routeTable_subnetInline(t *testing.T) { + + ri := acctest.RandInt() + //initConfig := fmt.Sprintf(testAccAzureRMSubnet_routeTable_subnetInline, ri, ri, ri) + updatedConfig := fmt.Sprintf(testAccAzureRMSubnet_updatedRouteTable, ri, ri, ri) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMSubnetDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: updatedConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMSubnetRouteTableExists("azurerm_subnet.rtTable2", "rtTable2-RT"), + ), + }, + }, + }) +} + func TestAccAzureRMSubnet_disappears(t *testing.T) { ri := acctest.RandInt() @@ -60,6 +111,8 @@ func testCheckAzureRMSubnetExists(name string) resource.TestCheckFunc { return fmt.Errorf("Not found: %s", name) } + log.Printf("[INFO] Checking Subnet addition.") + name := rs.Primary.Attributes["name"] vnetName := rs.Primary.Attributes["virtual_network_name"] resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] @@ -78,6 +131,60 @@ func testCheckAzureRMSubnetExists(name string) resource.TestCheckFunc { return fmt.Errorf("Bad: Subnet %q (resource group: %q) does not exist", name, resourceGroup) } + if resp.RouteTable == nil { + return fmt.Errorf("Bad: Subnet %q (resource group: %q) does not contain route tables after add", name, resourceGroup) + } + + return nil + } +} + +func testCheckAzureRMSubnetRouteTableExists(subnetName string, routeTableId string) resource.TestCheckFunc { + return func(s *terraform.State) error { + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[subnetName] + if !ok { + return fmt.Errorf("Not found: %s", subnetName) + } + + log.Printf("[INFO] Checking Subnet update.") + + name := rs.Primary.Attributes["name"] + vnetName := rs.Primary.Attributes["virtual_network_name"] + resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] + if !hasResourceGroup { + return fmt.Errorf("Bad: no resource group found in state for subnet: %s", name) + } + + vnetConn := testAccProvider.Meta().(*ArmClient).vnetClient + vnetResp, vnetErr := vnetConn.Get(resourceGroup, vnetName, "") + if vnetErr != nil { + return fmt.Errorf("Bad: Get on vnetClient: %s", vnetErr) + } + + if vnetResp.Subnets == nil { + return fmt.Errorf("Bad: Vnet %q (resource group: %q) does not have subnets after update", vnetName, resourceGroup) + } + + conn := testAccProvider.Meta().(*ArmClient).subnetClient + + resp, err := conn.Get(resourceGroup, vnetName, name, "") + if err != nil { + return fmt.Errorf("Bad: Get on subnetClient: %s", err) + } + + if resp.StatusCode == http.StatusNotFound { + return fmt.Errorf("Bad: Subnet %q (resource group: %q) does not exist", subnetName, resourceGroup) + } + + if resp.RouteTable == nil { + return fmt.Errorf("Bad: Subnet %q (resource group: %q) does not contain route tables after update", subnetName, resourceGroup) + } + + if !strings.Contains(*resp.RouteTable.ID, routeTableId) { + return fmt.Errorf("Bad: Subnet %q (resource group: %q) does not have route table %q", subnetName, resourceGroup, routeTableId) + } + return nil } } @@ -154,3 +261,145 @@ resource "azurerm_subnet" "test" { address_prefix = "10.0.2.0/24" } ` + +var testAccAzureRMSubnet_routeTable = ` +resource "azurerm_resource_group" "rtTable2" { + name = "acctestRG-%d" + location = "West US" +} + +resource "azurerm_virtual_network" "rtTable2" { + name = "acctestvirtnet%d" + address_space = ["10.0.0.0/16"] + location = "West US" + resource_group_name = "${azurerm_resource_group.rtTable2.name}" +} + +resource "azurerm_subnet" "rtTable2" { + name = "acctestsubnet%d" + resource_group_name = "${azurerm_resource_group.rtTable2.name}" + virtual_network_name = "${azurerm_virtual_network.rtTable2.name}" + address_prefix = "10.0.2.0/24" + route_table_id = "${azurerm_route_table.rtTable2.id}" +} + +resource "azurerm_route_table" "rtTable2" { + name = "rtTable2-RT" + location = "West US" + resource_group_name = "${azurerm_resource_group.rtTable2.name}" +} + +resource "azurerm_route" "route_a" { + name = "TestRouteA" + resource_group_name = "${azurerm_resource_group.rtTable2.name}" + route_table_name = "${azurerm_route_table.rtTable2.name}" + + address_prefix = "10.100.0.0/14" + next_hop_type = "VirtualAppliance" + next_hop_in_ip_address = "10.10.1.1" +}` + +var testAccAzureRMSubnet_routeTable_subnetInline = ` +resource "azurerm_resource_group" "rtTable2" { + name = "acctestRG-%d" + location = "West US" +} + +resource "azurerm_virtual_network" "rtTable2" { + name = "acctestvirtnet%d" + address_space = ["10.0.0.0/16"] + location = "West US" + resource_group_name = "${azurerm_resource_group.rtTable2.name}" + subnet { + name = "rtTable2" + address_prefix = "10.0.3.0/24" + route_table = "${azurerm_route_table.rtTable2.id}" + } + tags { + environment = "Testing" + } +} + +resource "azurerm_route_table" "rtTable2" { + name = "rtTable2-RT" + location = "West US" + resource_group_name = "${azurerm_resource_group.rtTable2.name}" +} + +resource "azurerm_route" "route_a" { + name = "TestRouteA" + resource_group_name = "${azurerm_resource_group.rtTable2.name}" + route_table_name = "${azurerm_route_table.rtTable2.name}" + + address_prefix = "10.100.0.0/14" + next_hop_type = "VirtualAppliance" + next_hop_in_ip_address = "10.10.1.1" +}` + +var testAccAzureRMSubnet_updatedRouteTable = ` +resource "azurerm_resource_group" "rtTable2" { + name = "acctestRG-%d" + location = "West US" + tags { + environment = "Testing" + } +} + +resource "azurerm_network_security_group" "rtTable2_secgroup" { + name = "acceptanceTestSecurityGroup1" + location = "West US" + resource_group_name = "${azurerm_resource_group.rtTable2.name}" + + security_rule { + name = "test123" + priority = 100 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "*" + source_address_prefix = "*" + destination_address_prefix = "*" + } + + tags { + environment = "Testing" + } +} + +resource "azurerm_virtual_network" "rtTable2" { + name = "acctestvirtnet%d" + address_space = ["10.0.0.0/16"] + location = "West US" + resource_group_name = "${azurerm_resource_group.rtTable2.name}" + tags { + environment = "Testing" + } +} + +resource "azurerm_subnet" "rtTable2" { + name = "acctestsubnet%d" + resource_group_name = "${azurerm_resource_group.rtTable2.name}" + virtual_network_name = "${azurerm_virtual_network.rtTable2.name}" + address_prefix = "10.0.2.0/24" + route_table_id = "${azurerm_route_table.rtTable2.id}" +} + +resource "azurerm_route_table" "rtTable2" { + name = "rtTable2-RT" + location = "West US" + resource_group_name = "${azurerm_resource_group.rtTable2.name}" + tags { + environment = "Testing" + } +} + +resource "azurerm_route" "route_a" { + name = "TestRouteA" + resource_group_name = "${azurerm_resource_group.rtTable2.name}" + route_table_name = "${azurerm_route_table.rtTable2.name}" + + address_prefix = "10.100.0.0/14" + next_hop_type = "VirtualAppliance" + next_hop_in_ip_address = "10.10.1.1" +}` diff --git a/builtin/providers/azurerm/resource_arm_virtual_network.go b/builtin/providers/azurerm/resource_arm_virtual_network.go index 5d4ba9a297cc..2a279da21223 100644 --- a/builtin/providers/azurerm/resource_arm_virtual_network.go +++ b/builtin/providers/azurerm/resource_arm_virtual_network.go @@ -61,6 +61,10 @@ func resourceArmVirtualNetwork() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "route_table": { + Type: schema.TypeString, + Optional: true, + }, }, }, Set: resourceAzureSubnetHash, @@ -93,7 +97,7 @@ func resourceArmVirtualNetworkCreate(d *schema.ResourceData, meta interface{}) e vnet := network.VirtualNetwork{ Name: &name, Location: &location, - VirtualNetworkPropertiesFormat: getVirtualNetworkProperties(d), + VirtualNetworkPropertiesFormat: getVirtualNetworkProperties(d, meta), Tags: expandTags(tags), } @@ -187,7 +191,7 @@ func resourceArmVirtualNetworkDelete(d *schema.ResourceData, meta interface{}) e return err } -func getVirtualNetworkProperties(d *schema.ResourceData) *network.VirtualNetworkPropertiesFormat { +func getVirtualNetworkProperties(d *schema.ResourceData, meta interface{}) *network.VirtualNetworkPropertiesFormat { // first; get address space prefixes: prefixes := []string{} for _, prefix := range d.Get("address_space").([]interface{}) { @@ -207,13 +211,28 @@ func getVirtualNetworkProperties(d *schema.ResourceData) *network.VirtualNetwork subnet := subnet.(map[string]interface{}) name := subnet["name"].(string) + log.Printf("[INFO] setting subnets inside vNet, processing %q", name) + //since subnets can also be created outside of vNet definition (as root objects) + // do a GET on subnet properties from the server before setting them + resGroup := d.Get("resource_group_name").(string) + vnetName := d.Get("name").(string) + subnetObj := getExistingSubnet(resGroup, vnetName, name, meta) + log.Printf("[INFO] Completer GET of Subnet props ") + prefix := subnet["address_prefix"].(string) secGroup := subnet["security_group"].(string) + routeTable := subnet["route_table"].(string) - var subnetObj network.Subnet - subnetObj.Name = &name - subnetObj.SubnetPropertiesFormat = &network.SubnetPropertiesFormat{} - subnetObj.SubnetPropertiesFormat.AddressPrefix = &prefix + if name != "" { + log.Printf("[INFO] setting SUBNETNAME TO %q", name) + subnetObj.Name = &name + } + if subnetObj.SubnetPropertiesFormat == nil { + subnetObj.SubnetPropertiesFormat = &network.SubnetPropertiesFormat{} + } + if subnetObj.SubnetPropertiesFormat.AddressPrefix == nil { + subnetObj.SubnetPropertiesFormat.AddressPrefix = &prefix + } if secGroup != "" { subnetObj.SubnetPropertiesFormat.NetworkSecurityGroup = &network.SecurityGroup{ @@ -221,6 +240,12 @@ func getVirtualNetworkProperties(d *schema.ResourceData) *network.VirtualNetwork } } + if routeTable != "" { + subnetObj.SubnetPropertiesFormat.RouteTable = &network.RouteTable{ + ID: &routeTable, + } + } + subnets = append(subnets, subnetObj) } } @@ -245,3 +270,38 @@ func resourceAzureSubnetHash(v interface{}) int { } return hashcode.String(subnet) } + +func getExistingSubnet(resGroup string, vnetName string, subnetName string, meta interface{}) network.Subnet { + //attempt to retrieve existing subnet from the server + existingSubnet := network.Subnet{} + subnetClient := meta.(*ArmClient).subnetClient + resp, err := subnetClient.Get(resGroup, vnetName, subnetName, "") + + if err != nil { + if resp.StatusCode == http.StatusNotFound { + return existingSubnet + } + } + + existingSubnet.SubnetPropertiesFormat = &network.SubnetPropertiesFormat{} + existingSubnet.SubnetPropertiesFormat.AddressPrefix = resp.SubnetPropertiesFormat.AddressPrefix + + if resp.SubnetPropertiesFormat.NetworkSecurityGroup != nil { + existingSubnet.SubnetPropertiesFormat.NetworkSecurityGroup = resp.SubnetPropertiesFormat.NetworkSecurityGroup + } + + if resp.SubnetPropertiesFormat.RouteTable != nil { + existingSubnet.SubnetPropertiesFormat.RouteTable = resp.SubnetPropertiesFormat.RouteTable + } + + if resp.SubnetPropertiesFormat.IPConfigurations != nil { + ips := make([]string, 0, len(*resp.SubnetPropertiesFormat.IPConfigurations)) + for _, ip := range *resp.SubnetPropertiesFormat.IPConfigurations { + ips = append(ips, *ip.ID) + } + + existingSubnet.SubnetPropertiesFormat.IPConfigurations = resp.SubnetPropertiesFormat.IPConfigurations + } + + return existingSubnet +} diff --git a/command/counthookaction_string.go b/command/counthookaction_string.go index 423cae07ee29..c0c40d0de606 100644 --- a/command/counthookaction_string.go +++ b/command/counthookaction_string.go @@ -1,4 +1,4 @@ -// Code generated by "stringer -type=countHookAction hook_count_action.go"; DO NOT EDIT. +// Code generated by "stringer -type=countHookAction hook_count_action.go"; DO NOT EDIT package command diff --git a/config/resource_mode_string.go b/config/resource_mode_string.go index ea68b4fcdb2e..930645fa87fe 100644 --- a/config/resource_mode_string.go +++ b/config/resource_mode_string.go @@ -1,4 +1,4 @@ -// Code generated by "stringer -type=ResourceMode -output=resource_mode_string.go resource_mode.go"; DO NOT EDIT. +// Code generated by "stringer -type=ResourceMode -output=resource_mode_string.go resource_mode.go"; DO NOT EDIT package config diff --git a/helper/schema/getsource_string.go b/helper/schema/getsource_string.go index 3a976293941a..790dbff919eb 100644 --- a/helper/schema/getsource_string.go +++ b/helper/schema/getsource_string.go @@ -1,4 +1,4 @@ -// Code generated by "stringer -type=getSource resource_data_get_source.go"; DO NOT EDIT. +// Code generated by "stringer -type=getSource resource_data_get_source.go"; DO NOT EDIT package schema diff --git a/helper/schema/valuetype_string.go b/helper/schema/valuetype_string.go index 1610cec2d326..08f008450feb 100644 --- a/helper/schema/valuetype_string.go +++ b/helper/schema/valuetype_string.go @@ -1,4 +1,4 @@ -// Code generated by "stringer -type=ValueType valuetype.go"; DO NOT EDIT. +// Code generated by "stringer -type=ValueType valuetype.go"; DO NOT EDIT package schema diff --git a/terraform/graphtype_string.go b/terraform/graphtype_string.go index e97b4855a97e..88ecad4f6b43 100644 --- a/terraform/graphtype_string.go +++ b/terraform/graphtype_string.go @@ -1,4 +1,4 @@ -// Code generated by "stringer -type=GraphType context_graph_type.go"; DO NOT EDIT. +// Code generated by "stringer -type=GraphType context_graph_type.go"; DO NOT EDIT package terraform diff --git a/terraform/instancetype_string.go b/terraform/instancetype_string.go index f69267cd52cb..f65414b347e9 100644 --- a/terraform/instancetype_string.go +++ b/terraform/instancetype_string.go @@ -1,4 +1,4 @@ -// Code generated by "stringer -type=InstanceType instancetype.go"; DO NOT EDIT. +// Code generated by "stringer -type=InstanceType instancetype.go"; DO NOT EDIT package terraform diff --git a/terraform/walkoperation_string.go b/terraform/walkoperation_string.go index cbd78dd93f0d..8fb33d7b5a80 100644 --- a/terraform/walkoperation_string.go +++ b/terraform/walkoperation_string.go @@ -1,4 +1,4 @@ -// Code generated by "stringer -type=walkOperation graph_walk_operation.go"; DO NOT EDIT. +// Code generated by "stringer -type=walkOperation graph_walk_operation.go"; DO NOT EDIT package terraform