diff --git a/internal/services/network/registration.go b/internal/services/network/registration.go index 059807062d9e1..dc57db582435e 100644 --- a/internal/services/network/registration.go +++ b/internal/services/network/registration.go @@ -103,6 +103,7 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { "azurerm_virtual_hub": resourceVirtualHub(), "azurerm_virtual_hub_bgp_connection": resourceVirtualHubBgpConnection(), "azurerm_virtual_hub_connection": resourceVirtualHubConnection(), + "azurerm_virtual_hub_connection_configuration": resourceVirtualHubConnectionConfiguration(), "azurerm_virtual_hub_ip": resourceVirtualHubIP(), "azurerm_virtual_hub_route_table": resourceVirtualHubRouteTable(), "azurerm_virtual_network_dns_servers": resourceVirtualNetworkDnsServers(), diff --git a/internal/services/network/virtual_hub_connection_configuration_resource.go b/internal/services/network/virtual_hub_connection_configuration_resource.go new file mode 100644 index 0000000000000..f705c973a64a1 --- /dev/null +++ b/internal/services/network/virtual_hub_connection_configuration_resource.go @@ -0,0 +1,350 @@ +package network + +import ( + "fmt" + "log" + "reflect" + "time" + + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-02-01/network" + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/locks" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +const virtualHubConnectionResourceName = "azurerm_virtual_hub_connection" + +func resourceVirtualHubConnectionConfiguration() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceVirtualHubConnectionConfigurationCreateOrUpdate, + Read: resourceVirtualHubConnectionConfigurationRead, + Update: resourceVirtualHubConnectionConfigurationCreateOrUpdate, + Delete: resourceVirtualHubConnectionConfigurationDelete, + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(60 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Update: pluginsdk.DefaultTimeout(60 * time.Minute), + Delete: pluginsdk.DefaultTimeout(60 * time.Minute), + }, + + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + _, err := parse.HubVirtualNetworkConnectionID(id) + return err + }), + + Schema: map[string]*pluginsdk.Schema{ + "virtual_hub_connection_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: azure.ValidateResourceID, + }, + + "associated_route_table_id": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validate.HubRouteTableID, + }, + + "propagated_route_table": { + Type: pluginsdk.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "labels": { + Type: pluginsdk.TypeSet, + Optional: true, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + AtLeastOneOf: []string{"propagated_route_table.0.labels", "propagated_route_table.0.route_table_ids"}, + }, + + "route_table_ids": { + Type: pluginsdk.TypeList, + Optional: true, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validate.HubRouteTableID, + }, + AtLeastOneOf: []string{"propagated_route_table.0.labels", "propagated_route_table.0.route_table_ids"}, + }, + }, + }, + }, + + //lintignore:XS003 + "static_vnet_route": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "address_prefixes": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.IsCIDR, + }, + }, + + "next_hop_ip_address": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.IsIPv4Address, + }, + }, + }, + }, + }, + } +} + +func resourceVirtualHubConnectionConfigurationCreateOrUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.HubVirtualNetworkConnectionClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + virtualHubConnectionId := d.Get("virtual_hub_connection_id").(string) + + id, err := parse.HubVirtualNetworkConnectionID(virtualHubConnectionId) + if err != nil { + return err + } + + locks.ByName(id.VirtualHubName, virtualHubResourceName) + defer locks.UnlockByName(id.VirtualHubName, virtualHubResourceName) + + locks.ByName(id.Name, virtualHubConnectionResourceName) + defer locks.UnlockByName(id.Name, virtualHubConnectionResourceName) + + virtualHubConnection, err := client.Get(ctx, id.ResourceGroup, id.VirtualHubName, id.Name) + if err != nil { + if utils.ResponseWasNotFound(virtualHubConnection.Response) { + return fmt.Errorf("virtual hub connection %q (Virtual Hub %q / Resource Group %q) was not found", id.Name, id.VirtualHubName, id.ResourceGroup) + } + + return fmt.Errorf("retrieving Virtual Hub Connection %q (Virtual Hub %q / Resource Group %q): %+v", id.Name, id.VirtualHubName, id.ResourceGroup, err) + } + + if d.IsNewResource() { + if err := hasImportError(id, virtualHubConnection); err != nil { + return err + } + } + + virtualHubConnection.HubVirtualNetworkConnectionProperties.RoutingConfiguration = expandVirtualHubConnectionConfigurationRouting(d) + + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.VirtualHubName, id.Name, virtualHubConnection) + if err != nil { + return fmt.Errorf("creating %s: %+v", virtualHubConnectionId, err) + } + + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for creation of %s: %+v", virtualHubConnectionId, err) + } + + timeout, _ := ctx.Deadline() + + vnetStateConf := &pluginsdk.StateChangeConf{ + Pending: []string{string(network.ProvisioningStateUpdating)}, + Target: []string{string(network.ProvisioningStateSucceeded)}, + Refresh: virtualHubConnectionProvisioningStateRefreshFunc(ctx, client, *id), + MinTimeout: 1 * time.Minute, + Timeout: time.Until(timeout), + } + if _, err = vnetStateConf.WaitForStateContext(ctx); err != nil { + return fmt.Errorf("waiting for provisioning state of %s: %+v", virtualHubConnectionId, err) + } + + d.SetId(virtualHubConnectionId) + + return resourceVirtualHubConnectionConfigurationRead(d, meta) +} + +func resourceVirtualHubConnectionConfigurationRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.HubVirtualNetworkConnectionClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.HubVirtualNetworkConnectionID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.VirtualHubName, id.Name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] %s does not exist - removing from state", *id) + d.SetId("") + return nil + } + return fmt.Errorf("reading %s: %+v", *id, err) + } + + if props := resp.HubVirtualNetworkConnectionProperties; props != nil { + if routing := props.RoutingConfiguration; routing != nil { + associatedRouteTableId := "" + if routing.AssociatedRouteTable != nil && routing.AssociatedRouteTable.ID != nil { + associatedRouteTableId = *routing.AssociatedRouteTable.ID + } + d.Set("associated_route_table_id", associatedRouteTableId) + + d.Set("propagated_route_table", flattenVirtualHubConnectionPropagatedRouteTable(routing.PropagatedRouteTables)) + d.Set("static_vnet_route", flattenVirtualHubConnectionVnetStaticRoute(routing.VnetRoutes)) + } + } + + return nil +} + +func resourceVirtualHubConnectionConfigurationDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.HubVirtualNetworkConnectionClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.HubVirtualNetworkConnectionID(d.Id()) + if err != nil { + return err + } + + // retrieve the connection + read, err := client.Get(ctx, id.ResourceGroup, id.VirtualHubName, id.Name) + if err != nil { + if utils.ResponseWasNotFound(read.Response) { + log.Printf("[DEBUG] Virtual Hub Connection %q (Virtual Hub %q / Resource Group %q) could not be found - removing from state!", id.Name, id.VirtualHubName, id.ResourceGroup) + return nil + } + + return fmt.Errorf("retrieving Virtual Hub Connection %q (Virtual Hub %q / Resource Group %q): %+v", id.Name, id.VirtualHubName, id.ResourceGroup, err) + } + + props := read.RoutingConfiguration + if props == nil { + return fmt.Errorf("`Properties` was nil for Virtual Hub Connection %q (Virtual Hub %q / Resource Group %q)", id.Name, id.VirtualHubName, id.ResourceGroup) + } + + locks.ByName(id.VirtualHubName, virtualHubResourceName) + defer locks.UnlockByName(id.VirtualHubName, virtualHubResourceName) + + locks.ByName(id.Name, virtualHubConnectionResourceName) + defer locks.UnlockByName(id.Name, virtualHubConnectionResourceName) + + // then re-retrieve it to ensure we've got the latest state + read, err = client.Get(ctx, id.ResourceGroup, id.VirtualHubName, id.Name) + if err != nil { + if utils.ResponseWasNotFound(read.Response) { + log.Printf("[DEBUG] Virtual Hub Connection %q (Virtual Hub %q / Resource Group %q) could not be found - removing from state!", id.Name, id.VirtualHubName, id.ResourceGroup) + return nil + } + + return fmt.Errorf("retrieving Virtual Hub Connection %q (Virtual Hub %q / Resource Group %q): %+v", id.Name, id.VirtualHubName, id.ResourceGroup, err) + } + + read.RoutingConfiguration.AssociatedRouteTable = nil + read.RoutingConfiguration.PropagatedRouteTables = nil + read.RoutingConfiguration.VnetRoutes = nil + + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.VirtualHubName, id.Name, read) + if err != nil { + return fmt.Errorf("removing Route Configuration from Virtual Hub Connection %q (Virtual Hub %q / Resource Group %q): %+v", id.Name, id.VirtualHubName, id.ResourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for removal of Route Configuration from Virtual Hub Connection %q (Virtual Hub %q / Resource Group %q): %+v", id.Name, id.VirtualHubName, id.ResourceGroup, err) + } + + return nil +} + +func expandVirtualHubConnectionConfigurationRouting(d *pluginsdk.ResourceData) *network.RoutingConfiguration { + result := network.RoutingConfiguration{} + + if v, ok := d.GetOk("associated_route_table_id"); ok && v != "" { + result.AssociatedRouteTable = &network.SubResource{ + ID: utils.String(v.(string)), + } + } + + if vnetStaticRoute := d.Get("static_vnet_route").([]interface{}); len(vnetStaticRoute) > 0 { + result.VnetRoutes = expandVirtualHubConnectionVnetStaticRoute(vnetStaticRoute) + } else { + result.VnetRoutes = nil + } + + if propagatedRouteTable := d.Get("propagated_route_table").([]interface{}); len(propagatedRouteTable) > 0 { + result.PropagatedRouteTables = expandVirtualHubConnectionPropagatedRouteTable(propagatedRouteTable) + } else { + result.PropagatedRouteTables = nil + } + + return &result +} + +func hasImportError(id *parse.HubVirtualNetworkConnectionId, connection network.HubVirtualNetworkConnection) error { + props := connection.RoutingConfiguration + if props == nil { + return nil + } + defaultRouteTableID := parse.NewHubRouteTableID(id.SubscriptionId, id.ResourceGroup, id.VirtualHubName, "defaultRouteTable").ID() + + if associatedRouteTable := props.AssociatedRouteTable; associatedRouteTable != nil { + if associatedRouteTable.ID != nil { + // do not raise an import error if the connection is associated to a defaultRouteTable + if *associatedRouteTable.ID != defaultRouteTableID { + return tf.ImportAsExistsError("azurerm_virtual_hub_connection_configuration", id.ID()) + } + } + } + + if propagatedRouteTables := props.PropagatedRouteTables; propagatedRouteTables != nil { + if propagatedRouteTables.Labels != nil { + // raise if the labels aren't default + if !reflect.DeepEqual(propagatedRouteTables.Labels, &[]string{"default"}) { + return tf.ImportAsExistsError("azurerm_virtual_hub_connection_configuration", id.ID()) + } + } + if propagatedRouteTables.Ids != nil { + + r := network.SubResource{ + ID: utils.String(defaultRouteTableID), + } + + // do not raise an import error if the connection is associated to a defaultRouteTable and nonRouteTable + if !reflect.DeepEqual(propagatedRouteTables.Ids, &[]network.SubResource{r}) { + return tf.ImportAsExistsError("azurerm_virtual_hub_connection_configuration", id.ID()) + } + } + } + + if vnetRoutes := props.VnetRoutes; vnetRoutes != nil { + if staticRoutes := vnetRoutes.StaticRoutes; staticRoutes != nil { + // raise an import error if the connection has existing static routes + if len(*staticRoutes) > 0 { + return tf.ImportAsExistsError("azurerm_virtual_hub_connection_configuration", id.ID()) + } + } + } + + return nil +} diff --git a/internal/services/network/virtual_hub_connection_configuration_resource_test.go b/internal/services/network/virtual_hub_connection_configuration_resource_test.go new file mode 100644 index 0000000000000..54d7d38b9ceb1 --- /dev/null +++ b/internal/services/network/virtual_hub_connection_configuration_resource_test.go @@ -0,0 +1,267 @@ +package network_test + +import ( + "context" + "fmt" + "reflect" + "testing" + + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-02-01/network" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type VirtualHubConnectionConfigurationResource struct { +} + +func TestAccVirtualHubRouteConnectionConfiguration_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_virtual_hub_connection_configuration", "test") + r := VirtualHubConnectionConfigurationResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("virtual_hub_connection_id"), + }) +} + +func TestAccVirtualHubRouteConnectionConfiguration_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_virtual_hub_connection_configuration", "test") + r := VirtualHubConnectionConfigurationResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccVirtualHubRouteConnectionConfiguration_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_virtual_hub_connection_configuration", "test") + r := VirtualHubConnectionConfigurationResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("virtual_hub_connection_id"), + }) +} + +func TestAccVirtualHubRouteConnectionConfiguration_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_virtual_hub_connection_configuration", "test") + r := VirtualHubConnectionConfigurationResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("virtual_hub_connection_id"), + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("virtual_hub_connection_id"), + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("virtual_hub_connection_id"), + }) +} + +func (t VirtualHubConnectionConfigurationResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := parse.HubVirtualNetworkConnectionID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.Network.HubVirtualNetworkConnectionClient.Get(ctx, id.ResourceGroup, id.VirtualHubName, id.Name) + if err != nil { + return nil, fmt.Errorf("reading Virtual Hub Connection (%s): %+v", id, err) + } + + // the associated route table is always a non-empty string + // it defaults to the defaultRouteTable + + routeTableID := parse.NewHubRouteTableID(id.SubscriptionId, id.ResourceGroup, id.VirtualHubName, "defaultRouteTable").ID() + + associatedRouteConfigured := *resp.RoutingConfiguration.AssociatedRouteTable.ID != routeTableID + propagatedLabelsConfigured := !reflect.DeepEqual(resp.RoutingConfiguration.PropagatedRouteTables.Labels, &[]string{"default"}) + r := network.SubResource{ + ID: utils.String(routeTableID), + } + propagatedIDsConfigured := !reflect.DeepEqual(resp.RoutingConfiguration.PropagatedRouteTables.Ids, &[]network.SubResource{r}) + staticRoutesConfigured := len(*resp.RoutingConfiguration.VnetRoutes.StaticRoutes) > 0 + + return utils.Bool(resp.ID != nil && (associatedRouteConfigured || propagatedLabelsConfigured || propagatedIDsConfigured || staticRoutesConfigured)), nil +} + +func (VirtualHubConnectionConfigurationResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +`) +} + +func (VirtualHubConnectionConfigurationResource) template_final(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-VHUB-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctest-VNET-%d" + address_space = ["10.5.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_network_security_group" "test" { + name = "acctest-NSG-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test" { + name = "acctest-SUBNET-%d" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.5.1.0/24"] +} + +resource "azurerm_subnet_network_security_group_association" "test" { + subnet_id = azurerm_subnet.test.id + network_security_group_id = azurerm_network_security_group.test.id +} + +resource "azurerm_virtual_wan" "test" { + name = "acctest-VWAN-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location +} + +resource "azurerm_virtual_hub" "test" { + name = "acctest-VHUB-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + virtual_wan_id = azurerm_virtual_wan.test.id + address_prefix = "10.0.2.0/24" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} + +func (r VirtualHubConnectionConfigurationResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s +resource "azurerm_virtual_hub_connection" "test" { + name = "example-vhubconn-%d" + virtual_hub_id = azurerm_virtual_hub.test.id + remote_virtual_network_id = azurerm_virtual_network.test.id +} + +resource "azurerm_virtual_hub_route_table" "test" { + name = "acctest-RouteTable-%d" + virtual_hub_id = azurerm_virtual_hub.test.id + labels = ["Label1"] + + route { + name = "example-route" + destinations_type = "CIDR" + destinations = ["10.0.0.0/16"] + next_hop_type = "ResourceId" + next_hop = azurerm_virtual_hub_connection.test.id + } +} + +resource "azurerm_virtual_hub_connection_configuration" "test" { + virtual_hub_connection_id = azurerm_virtual_hub_connection.test.id + associated_route_table_id = azurerm_virtual_hub_route_table.test.id +} +`, r.template(data), data.RandomInteger, data.RandomInteger) +} + +func (r VirtualHubConnectionConfigurationResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_virtual_hub_connection_configuration" "import" { + virtual_hub_connection_id = azurerm_virtual_hub_connection_configuration.test.virtual_hub_connection_id + associated_route_table_id = azurerm_virtual_hub_connection_configuration.test.associated_route_table_id +} +`, r.basic(data)) +} + +func (r VirtualHubConnectionConfigurationResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_virtual_hub_connection" "test" { + name = "example-vhubconn-%d" + virtual_hub_id = azurerm_virtual_hub.test.id + remote_virtual_network_id = azurerm_virtual_network.test.id +} + +resource "azurerm_virtual_hub_route_table" "test" { + name = "acctest-RouteTable-%d" + virtual_hub_id = azurerm_virtual_hub.test.id + labels = ["Label1", "Label2", "Label3"] + + route { + name = "example-route" + destinations_type = "CIDR" + destinations = ["10.0.0.0/16"] + next_hop_type = "ResourceId" + next_hop = azurerm_virtual_hub_connection.test.id + } +} + +resource "azurerm_virtual_hub_connection_configuration" "test" { + virtual_hub_connection_id = azurerm_virtual_hub_connection.test.id + associated_route_table_id = azurerm_virtual_hub_route_table.test.id + + propagated_route_table { + labels = ["Label3"] + route_table_ids = [ + azurerm_virtual_hub_route_table.test.id, + ] + } + + static_vnet_route { + name = "testvnetroute" + address_prefixes = ["10.0.3.0/24", "10.0.4.0/24"] + next_hop_ip_address = "10.0.3.5" + } + + static_vnet_route { + name = "testvnetroute2" + address_prefixes = ["10.0.5.0/24"] + next_hop_ip_address = "10.0.5.5" + } +} +`, r.template(data), data.RandomInteger, data.RandomInteger) +}