From dd2389dce88bbd094417374e3d28c563526f1488 Mon Sep 17 00:00:00 2001 From: Josh Barker Date: Fri, 15 Oct 2021 16:04:11 +1100 Subject: [PATCH] feat: create virtual hub route resource --- internal/services/network/registration.go | 1 + .../network/virtual_hub_route_resource.go | 312 ++++++++++++++++++ .../virtual_hub_route_resource_test.go | 238 +++++++++++++ .../virtual_hub_route_table_resource.go | 1 + .../docs/r/virtual_hub_route.html.markdown | 126 +++++++ .../r/virtual_hub_route_table.html.markdown | 2 + 6 files changed, 680 insertions(+) create mode 100644 internal/services/network/virtual_hub_route_resource.go create mode 100644 internal/services/network/virtual_hub_route_resource_test.go create mode 100644 website/docs/r/virtual_hub_route.html.markdown diff --git a/internal/services/network/registration.go b/internal/services/network/registration.go index 059807062d9e1..8ac459bcce3fd 100644 --- a/internal/services/network/registration.go +++ b/internal/services/network/registration.go @@ -104,6 +104,7 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { "azurerm_virtual_hub_bgp_connection": resourceVirtualHubBgpConnection(), "azurerm_virtual_hub_connection": resourceVirtualHubConnection(), "azurerm_virtual_hub_ip": resourceVirtualHubIP(), + "azurerm_virtual_hub_route": resourceVirtualHubRoute(), "azurerm_virtual_hub_route_table": resourceVirtualHubRouteTable(), "azurerm_virtual_network_dns_servers": resourceVirtualNetworkDnsServers(), "azurerm_virtual_network_gateway_connection": resourceVirtualNetworkGatewayConnection(), diff --git a/internal/services/network/virtual_hub_route_resource.go b/internal/services/network/virtual_hub_route_resource.go new file mode 100644 index 0000000000000..0017bdce96eea --- /dev/null +++ b/internal/services/network/virtual_hub_route_resource.go @@ -0,0 +1,312 @@ +package network + +import ( + "fmt" + "log" + "strings" + "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" + networkValidate "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" +) + +func resourceVirtualHubRoute() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceVirtualHubRouteCreateUpdate, + Read: resourceVirtualHubRouteRead, + Update: resourceVirtualHubRouteCreateUpdate, + Delete: resourceVirtualHubRouteDelete, + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(30 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Update: pluginsdk.DefaultTimeout(30 * time.Minute), + Delete: pluginsdk.DefaultTimeout(30 * time.Minute), + }, + + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + _, name, err := ParseHubRouteId(id) + + if err != nil { + return err + } + + if len(name) == 0 { + return fmt.Errorf("route name is empty") + } + + return nil + }), + + Schema: map[string]*pluginsdk.Schema{ + "route_table_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: networkValidate.HubRouteTableID, + }, + + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "destinations": { + Type: pluginsdk.TypeSet, + Required: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + + "destinations_type": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "CIDR", + "ResourceId", + "Service", + }, false), + }, + + "next_hop": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: azure.ValidateResourceID, + }, + + "next_hop_type": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "ResourceId", + ValidateFunc: validation.StringInSlice([]string{ + "ResourceId", + }, false), + }, + }, + } +} + +func resourceVirtualHubRouteCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.HubRouteTableClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + routeTableId, err := parse.HubRouteTableID(d.Get("route_table_id").(string)) + + if err != nil { + return err + } + + locks.ByName(routeTableId.VirtualHubName, virtualHubResourceName) + defer locks.UnlockByName(routeTableId.VirtualHubName, virtualHubResourceName) + + routeTable, err := client.Get(ctx, routeTableId.ResourceGroup, routeTableId.VirtualHubName, routeTableId.Name) + if err != nil { + if !utils.ResponseWasNotFound(routeTable.Response) { + return fmt.Errorf("checking for present of existing HubRouteTable %q (Resource Group %q / Virtual Hub %q): %+v", routeTableId.Name, routeTableId.ResourceGroup, routeTableId.VirtualHubName, err) + } + } + + name := d.Get("name").(string) + id := HubRouteID(routeTable, name) + + if d.IsNewResource() { + for _, r := range *routeTable.Routes { + if *r.Name == name { + return tf.ImportAsExistsError("azurerm_virtual_hub_route", id) + } + } + + routes := *routeTable.Routes + result := network.HubRoute{ + Name: utils.String(d.Get("name").(string)), + DestinationType: utils.String(d.Get("destinations_type").(string)), + Destinations: utils.ExpandStringSlice(d.Get("destinations").(*pluginsdk.Set).List()), + NextHopType: utils.String(d.Get("next_hop_type").(string)), + NextHop: utils.String(d.Get("next_hop").(string)), + } + + routes = append(routes, result) + routeTable.Routes = &routes + } else { + for _, r := range *routeTable.Routes { + if *r.Name == name { + r.DestinationType = utils.String(d.Get("destinations_type").(string)) + r.Destinations = utils.ExpandStringSlice(d.Get("destinations").(*pluginsdk.Set).List()) + r.NextHopType = utils.String(d.Get("next_hop_type").(string)) + r.NextHop = utils.String(d.Get("next_hop").(string)) + break + } + } + } + + future, err := client.CreateOrUpdate(ctx, routeTableId.ResourceGroup, routeTableId.VirtualHubName, routeTableId.Name, routeTable) + if err != nil { + return fmt.Errorf("creating/updating Route %q in HubRouteTable %q (Resource Group %q / Virtual Hub %q): %+v", name, routeTableId.Name, routeTableId.ResourceGroup, routeTableId.Name, err) + } + + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting on creating/updating future for Route %q in HubRouteTable %q (Resource Group %q / Virtual Hub %q): %+v", name, routeTableId.Name, routeTableId.ResourceGroup, routeTableId.Name, err) + } + + resp, err := client.Get(ctx, routeTableId.ResourceGroup, routeTableId.VirtualHubName, routeTableId.Name) + if err != nil { + return fmt.Errorf("retrieving HubRouteTable %q (Resource Group %q / Virtual Hub %q): %+v", name, routeTableId.ResourceGroup, routeTableId.Name, err) + } + + if resp.ID == nil || *resp.ID == "" { + return fmt.Errorf("empty or nil ID returned for HubRouteTable %q (Resource Group %q / Virtual Hub %q) ID", name, routeTableId.ResourceGroup, routeTableId.Name) + } + + d.SetId(id) + + return resourceVirtualHubRouteRead(d, meta) +} + +func resourceVirtualHubRouteRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.HubRouteTableClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + routeTableId, name, err := ParseHubRouteId(d.Id()) + + if err != nil { + return err + } + + resp, err := client.Get(ctx, routeTableId.ResourceGroup, routeTableId.VirtualHubName, routeTableId.Name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] Virtual Hub Route Table %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + + return fmt.Errorf("retrieving HubRouteTable %q (Resource Group %q / Virtual Hub %q): %+v", routeTableId.Name, routeTableId.ResourceGroup, routeTableId.VirtualHubName, err) + } + + if props := resp.HubRouteTableProperties; props != nil { + found := false + for _, r := range *props.Routes { + if *r.Name == name { + found = true + + d.Set("destinations_type", r.DestinationType) + d.Set("destinations", utils.FlattenStringSlice(r.Destinations)) + d.Set("next_hop_type", r.NextHopType) + d.Set("next_hop", r.NextHop) + + break + } + } + + if !found { + // could not find existing route by name + d.SetId("") + return nil + } + } + + d.Set("name", name) + d.Set("route_table_id", routeTableId.ID()) + + return nil +} + +func resourceVirtualHubRouteDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.HubRouteTableClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + routeTableId, name, err := ParseHubRouteId(d.Id()) + + if err != nil { + return err + } + + locks.ByName(routeTableId.VirtualHubName, virtualHubResourceName) + defer locks.UnlockByName(routeTableId.VirtualHubName, virtualHubResourceName) + + // get latest list of routes + routeTable, err := client.Get(ctx, routeTableId.ResourceGroup, routeTableId.VirtualHubName, routeTableId.Name) + if err != nil { + if !utils.ResponseWasNotFound(routeTable.Response) { + return fmt.Errorf("checking for present of existing HubRouteTable %q (Resource Group %q / Virtual Hub %q): %+v", routeTableId.Name, routeTableId.ResourceGroup, routeTableId.VirtualHubName, err) + } + } + + if props := routeTable.HubRouteTableProperties; props != nil { + if props.Routes != nil { + routes := *props.Routes + removeIndex := -1 + + for i, r := range routes { + if *r.Name == name { + removeIndex = i + break + } + } + + if removeIndex > -1 { + if len(routes) == 1 && removeIndex == 0 { + routes = nil + } else { + routes[removeIndex] = routes[len(routes)-1] + routes = routes[:len(routes)-1] + } + } + + props.Routes = &routes + } + } + + future, err := client.CreateOrUpdate(ctx, routeTableId.ResourceGroup, routeTableId.VirtualHubName, routeTableId.Name, routeTable) + if err != nil { + return fmt.Errorf("removing Route %q from HubRouteTable %q (Resource Group %q / Virtual Hub %q): %+v", name, routeTableId.Name, routeTableId.ResourceGroup, routeTableId.Name, err) + } + + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting on removing Route %q from future for HubRouteTable %q (Resource Group %q / Virtual Hub %q): %+v", name, routeTableId.Name, routeTableId.ResourceGroup, routeTableId.Name, err) + } + + return nil +} + +// As we are making a "virtual" sub-resource, the id stored in state needs to contain the name +// This ensures that terraform import works +// Note: This resource id DOES NOT exist in Azure. +// ID format: / +// For example: +// Route Table ID: /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Network/virtualHubs/virtualHub1/hubRouteTables/routeTable1 +// Route Name: route1 +// Resulting ID: /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Network/virtualHubs/virtualHub1/hubRouteTables/routeTable1/route1 + +func HubRouteID(hub network.HubRouteTable, routeName string) string { + return fmt.Sprintf("%s/%s", *hub.ID, routeName) +} + +func ParseHubRouteId(input string) (*parse.HubRouteTableId, string, error) { + i := strings.LastIndex(input, "/") + routeTableID := input[:i] + name := input[i+1:] + + routeTable, err := parse.HubRouteTableID(routeTableID) + if err != nil { + return nil, "", err + } + + return routeTable, name, nil +} diff --git a/internal/services/network/virtual_hub_route_resource_test.go b/internal/services/network/virtual_hub_route_resource_test.go new file mode 100644 index 0000000000000..89c96be81a651 --- /dev/null +++ b/internal/services/network/virtual_hub_route_resource_test.go @@ -0,0 +1,238 @@ +package network_test + +import ( + "context" + "fmt" + "testing" + + "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" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type VirtualHubRouteResource struct { +} + +func TestAccVirtualHubRoute_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_virtual_hub_route", "test") + r := VirtualHubRouteResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccVirtualHubRoute_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_virtual_hub_route", "test") + r := VirtualHubRouteResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccVirtualHubRoute_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_virtual_hub_route", "test") + r := VirtualHubRouteResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That("azurerm_virtual_hub_route.test_2").ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccVirtualHubRoute_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_virtual_hub_route", "test") + r := VirtualHubRouteResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That("azurerm_virtual_hub_route.test_2").ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (t VirtualHubRouteResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + routeTableId, name, err := network.ParseHubRouteId(state.ID) + + if err != nil { + return nil, err + } + + resp, err := clients.Network.HubRouteTableClient.Get(ctx, routeTableId.ResourceGroup, routeTableId.VirtualHubName, routeTableId.Name) + if err != nil { + return nil, fmt.Errorf("reading Virtual Hub Route Table (%s): %+v", routeTableId, err) + } + + if props := resp.HubRouteTableProperties; props != nil { + if routes := props.Routes; routes != nil { + for _, r := range *routes { + if *r.Name == name { + return utils.Bool(true), nil + } + } + } + } + + return utils.Bool(false), nil +} + +func (VirtualHubRouteResource) template(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" +} + +resource "azurerm_virtual_hub_connection" "test" { + name = "acctest-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"] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} + +func (r VirtualHubRouteResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_virtual_hub_route" "test" { + route_table_id = azurerm_virtual_hub_route_table.test.id + + name = "acctest-Route-%d" + + destinations_type = "CIDR" + destinations = ["10.0.0.0/16"] + next_hop_type = "ResourceId" + next_hop = azurerm_virtual_hub_connection.test.id +} +`, r.template(data), data.RandomInteger) +} + +func (r VirtualHubRouteResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s +resource "azurerm_virtual_hub_route" "import" { + route_table_id = azurerm_virtual_hub_route.test.route_table_id + + name = azurerm_virtual_hub_route.test.name + destinations_type = azurerm_virtual_hub_route.test.destinations_type + destinations = azurerm_virtual_hub_route.test.destinations + next_hop_type = azurerm_virtual_hub_route.test.next_hop_type + next_hop = azurerm_virtual_hub_route.test.next_hop +} +`, r.basic(data)) +} + +func (r VirtualHubRouteResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_virtual_hub_route" "test" { + route_table_id = azurerm_virtual_hub_route_table.test.id + + name = "acctest-Route-%d-renamed" + + destinations_type = "CIDR" + destinations = ["10.1.0.0/16"] + next_hop_type = "ResourceId" + next_hop = azurerm_virtual_hub_connection.test.id +} + +resource "azurerm_virtual_hub_route" "test_2" { + route_table_id = azurerm_virtual_hub_route_table.test.id + + name = "acctest-Route-%d" + + destinations_type = "CIDR" + destinations = ["10.2.0.0/16"] + next_hop_type = "ResourceId" + next_hop = azurerm_virtual_hub_connection.test.id +} +`, r.template(data), data.RandomInteger, data.RandomInteger) +} diff --git a/internal/services/network/virtual_hub_route_table_resource.go b/internal/services/network/virtual_hub_route_table_resource.go index c7aa595699cd0..5d1dc368e3d8f 100644 --- a/internal/services/network/virtual_hub_route_table_resource.go +++ b/internal/services/network/virtual_hub_route_table_resource.go @@ -63,6 +63,7 @@ func resourceVirtualHubRouteTable() *pluginsdk.Resource { "route": { Type: pluginsdk.TypeSet, Optional: true, + Computed: true, Elem: &pluginsdk.Resource{ Schema: map[string]*pluginsdk.Schema{ "name": { diff --git a/website/docs/r/virtual_hub_route.html.markdown b/website/docs/r/virtual_hub_route.html.markdown new file mode 100644 index 0000000000000..475366d245a42 --- /dev/null +++ b/website/docs/r/virtual_hub_route.html.markdown @@ -0,0 +1,126 @@ +--- +subcategory: "Network" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_virtual_hub_route" +description: |- + Manages a Virtual Hub Route. +--- + +# azurerm_virtual_hub_route + +Manages a Virtual Hub Route. + +~> **Note:** The Route can be created, as well as with the [virtual_hub_route_table resource](virtual_hub_route_table.html) resource. You can only use one or the other and using both will cause a conflict. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West Europe" +} + +resource "azurerm_virtual_network" "example" { + name = "example-vnet" + address_space = ["10.5.0.0/16"] + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name +} + +resource "azurerm_network_security_group" "example" { + name = "example-nsg" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name +} + +resource "azurerm_subnet" "example" { + name = "examplesubnet" + resource_group_name = azurerm_resource_group.example.name + virtual_network_name = azurerm_virtual_network.example.name + address_prefixes = ["10.5.1.0/24"] +} + +resource "azurerm_subnet_network_security_group_association" "example" { + subnet_id = azurerm_subnet.example.id + network_security_group_id = azurerm_network_security_group.example.id +} + +resource "azurerm_virtual_wan" "example" { + name = "example-vwan" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location +} + +resource "azurerm_virtual_hub" "example" { + name = "example-vhub" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + virtual_wan_id = azurerm_virtual_wan.example.id + address_prefix = "10.0.2.0/24" +} + +resource "azurerm_virtual_hub_connection" "example" { + name = "example-vhubconn" + virtual_hub_id = azurerm_virtual_hub.example.id + remote_virtual_network_id = azurerm_virtual_network.example.id + + routing { + associated_route_table_id = azurerm_virtual_hub_route_table.example.id + } +} + +resource "azurerm_virtual_hub_route_table" "example" { + name = "example-vhubroutetable" + virtual_hub_id = azurerm_virtual_hub.example.id + labels = ["label1"] +} + +resource "azurerm_virtual_hub_route" "example" { + route_table_id = azurerm_virtual_hub_route_table.example.id + + name = "example-route" + destinations_type = "CIDR" + destinations = ["10.0.0.0/16"] + next_hop_type = "ResourceId" + next_hop = azurerm_virtual_hub_connection.example.id +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `route_table_id` - (Required) The ID of the Virtual Hub Route Table to link this route to. Changing this forces a new resource to be created. + +* `name` - (Required) The name which should be used for this route. Changing this forces a new resource to be created. + +* `destinations` - (Required) A list of destination addresses for this route. + +* `destinations_type` - (Required) The type of destinations. Possible values are `CIDR`, `ResourceId` and `Service`. + +* `next_hop` - (Required) The next hop's resource ID. + +* `next_hop_type` - (Optional) The type of next hop. Currently the only possible value is `ResourceId`. Defaults to `ResourceId`. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the Virtual Hub Route Table. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Virtual Hub Route Table. +* `read` - (Defaults to 5 minutes) Used when retrieving the Virtual Hub Route Table. +* `update` - (Defaults to 30 minutes) Used when updating the Virtual Hub Route Table. +* `delete` - (Defaults to 30 minutes) Used when deleting the Virtual Hub Route Table. + +## Import + +Virtual Hub Route Tables can be imported using `/`, e.g. + +```shell +terraform import azurerm_virtual_hub_route_table.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Network/virtualHubs/virtualHub1/hubRouteTables/routeTable1/routeName +``` diff --git a/website/docs/r/virtual_hub_route_table.html.markdown b/website/docs/r/virtual_hub_route_table.html.markdown index 23b48591250ca..56eddddb9ac2a 100644 --- a/website/docs/r/virtual_hub_route_table.html.markdown +++ b/website/docs/r/virtual_hub_route_table.html.markdown @@ -10,6 +10,8 @@ description: |- Manages a Virtual Hub Route Table. +~> **Note:** The Routes can be set inline here, as well as with the [virtual_hub_route resource](virtual_hub_route.html) resource. You can only use one or the other and using both will cause a conflict. + ## Example Usage ```hcl