From 5b2f65a9509946245b3830176125d576f2ef434a Mon Sep 17 00:00:00 2001 From: v-cheye Date: Tue, 19 Nov 2019 22:32:50 +0800 Subject: [PATCH 1/5] Add new resource & data source: azurerm_virtual_hub --- azurerm/data_source_virtual_hub.go | 166 +++++++ azurerm/data_source_virtual_hub_test.go | 41 ++ azurerm/internal/services/network/client.go | 5 + azurerm/provider.go | 2 + azurerm/resource_arm_virtual_hub.go | 410 ++++++++++++++++++ azurerm/resource_arm_virtual_hub_test.go | 294 +++++++++++++ examples/virtual-networks/virtual-hub/main.tf | 18 + .../virtual-networks/virtual-hub/variables.tf | 7 + website/azurerm.erb | 8 + website/docs/d/virtual_hub.html.markdown | 79 ++++ website/docs/r/virtual_hub.html.markdown | 98 +++++ 11 files changed, 1128 insertions(+) create mode 100644 azurerm/data_source_virtual_hub.go create mode 100644 azurerm/data_source_virtual_hub_test.go create mode 100644 azurerm/resource_arm_virtual_hub.go create mode 100644 azurerm/resource_arm_virtual_hub_test.go create mode 100644 examples/virtual-networks/virtual-hub/main.tf create mode 100644 examples/virtual-networks/virtual-hub/variables.tf create mode 100644 website/docs/d/virtual_hub.html.markdown create mode 100644 website/docs/r/virtual_hub.html.markdown diff --git a/azurerm/data_source_virtual_hub.go b/azurerm/data_source_virtual_hub.go new file mode 100644 index 000000000000..e6ddf0bd2674 --- /dev/null +++ b/azurerm/data_source_virtual_hub.go @@ -0,0 +1,166 @@ +package azurerm + +import ( + "fmt" + "regexp" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceArmVirtualHub() *schema.Resource { + return &schema.Resource{ + Read: dataSourceArmVirtualHubRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringMatch( + regexp.MustCompile(`^.{1,256}$`), + `The name must be between 1 and 256 characters in length.`, + ), + }, + + "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), + + "location": azure.SchemaLocationForDataSource(), + + "address_prefix": { + Type: schema.TypeString, + Computed: true, + }, + + "virtual_wan_id": { + Type: schema.TypeString, + Computed: true, + }, + + "s2s_vpn_gateway_id": { + Type: schema.TypeString, + Computed: true, + }, + + "p2s_vpn_gateway_id": { + Type: schema.TypeString, + Computed: true, + }, + + "express_route_gateway_id": { + Type: schema.TypeString, + Computed: true, + }, + + "virtual_network_connection": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "remote_virtual_network_id": { + Type: schema.TypeString, + Computed: true, + }, + "allow_hub_to_remote_vnet_transit": { + Type: schema.TypeBool, + Computed: true, + }, + "allow_remote_vnet_to_use_hub_vnet_gateways": { + Type: schema.TypeBool, + Computed: true, + }, + "enable_internet_security": { + Type: schema.TypeBool, + Computed: true, + }, + }, + }, + }, + + "route": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address_prefixes": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "next_hop_ip_address": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "tags": tags.SchemaDataSource(), + }, + } +} + +func dataSourceArmVirtualHubRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).Network.VirtualHubClient + ctx := meta.(*ArmClient).StopContext + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Error: Virtual Hub %q (Resource Group %q) was not found", name, resourceGroup) + } + return fmt.Errorf("Error reading Virtual Hub %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + d.SetId(*resp.ID) + + d.Set("name", resp.Name) + d.Set("resource_group_name", resourceGroup) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + if props := resp.VirtualHubProperties; props != nil { + d.Set("address_prefix", props.AddressPrefix) + if props.VirtualWan != nil { + if err := d.Set("virtual_wan_id", props.VirtualWan.ID); err != nil { + return fmt.Errorf("Error setting `virtual_wan_id`: %+v", err) + } + } + if props.VpnGateway != nil { + if err := d.Set("s2s_vpn_gateway_id", props.VpnGateway.ID); err != nil { + return fmt.Errorf("Error setting `s2s_vpn_gateway_id`: %+v", err) + } + } + if props.P2SVpnGateway != nil { + if err := d.Set("p2s_vpn_gateway_id", props.P2SVpnGateway.ID); err != nil { + return fmt.Errorf("Error setting `p2s_vpn_gateway_id`: %+v", err) + } + } + if props.ExpressRouteGateway != nil { + if err := d.Set("express_route_gateway_id", props.ExpressRouteGateway.ID); err != nil { + return fmt.Errorf("Error setting `express_route_gateway_id`: %+v", err) + } + } + if err := d.Set("virtual_network_connection", flattenArmVirtualHubVirtualNetworkConnection(props.VirtualNetworkConnections)); err != nil { + return fmt.Errorf("Error setting `virtual_network_connection`: %+v", err) + } + if props.RouteTable != nil { + if err := d.Set("route", flattenArmVirtualHubRoute(props.RouteTable.Routes)); err != nil { + return fmt.Errorf("Error setting `route`: %+v", err) + } + } + } + + return tags.FlattenAndSet(d, resp.Tags) +} diff --git a/azurerm/data_source_virtual_hub_test.go b/azurerm/data_source_virtual_hub_test.go new file mode 100644 index 000000000000..3910697624c9 --- /dev/null +++ b/azurerm/data_source_virtual_hub_test.go @@ -0,0 +1,41 @@ +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" +) + +func TestAccDataSourceAzureRMVirtualHub_basic(t *testing.T) { + dataSourceName := "data.azurerm_virtual_hub.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceVirtualHub_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(dataSourceName, "address_prefix"), + resource.TestCheckResourceAttrSet(dataSourceName, "virtual_wan_id"), + ), + }, + }, + }) +} + +func testAccDataSourceVirtualHub_basic(rInt int, location string) string { + config := testAccAzureRMVirtualHub_basic(rInt, location) + return fmt.Sprintf(` +%s + +data "azurerm_virtual_hub" "test" { + name = "${azurerm_virtual_hub.test.name}" + resource_group_name = "${azurerm_virtual_hub.test.resource_group_name}" +} +`, config) +} diff --git a/azurerm/internal/services/network/client.go b/azurerm/internal/services/network/client.go index 08009bf37426..19272ea445e6 100644 --- a/azurerm/internal/services/network/client.go +++ b/azurerm/internal/services/network/client.go @@ -32,6 +32,7 @@ type Client struct { VnetClient *network.VirtualNetworksClient VnetPeeringsClient *network.VirtualNetworkPeeringsClient VirtualWanClient *network.VirtualWansClient + VirtualHubClient *network.VirtualHubsClient WatcherClient *network.WatchersClient WebApplicationFirewallPoliciesClient *network.WebApplicationFirewallPoliciesClient } @@ -115,6 +116,9 @@ func BuildClient(o *common.ClientOptions) *Client { VirtualWanClient := network.NewVirtualWansClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&VirtualWanClient.Client, o.ResourceManagerAuthorizer) + VirtualHubClient := network.NewVirtualHubsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&VirtualHubClient.Client, o.ResourceManagerAuthorizer) + WatcherClient := network.NewWatchersClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&WatcherClient.Client, o.ResourceManagerAuthorizer) @@ -148,6 +152,7 @@ func BuildClient(o *common.ClientOptions) *Client { VnetClient: &VnetClient, VnetPeeringsClient: &VnetPeeringsClient, VirtualWanClient: &VirtualWanClient, + VirtualHubClient: &VirtualHubClient, WatcherClient: &WatcherClient, WebApplicationFirewallPoliciesClient: &WebApplicationFirewallPoliciesClient, } diff --git a/azurerm/provider.go b/azurerm/provider.go index cce59c274481..65819e0e98d2 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -147,6 +147,7 @@ func Provider() terraform.ResourceProvider { "azurerm_subscriptions": dataSourceArmSubscriptions(), "azurerm_traffic_manager_geographical_location": dataSourceArmTrafficManagerGeographicalLocation(), "azurerm_user_assigned_identity": dataSourceArmUserAssignedIdentity(), + "azurerm_virtual_hub": dataSourceArmVirtualHub(), "azurerm_virtual_machine": dataSourceArmVirtualMachine(), "azurerm_virtual_network_gateway": dataSourceArmVirtualNetworkGateway(), "azurerm_virtual_network_gateway_connection": dataSourceArmVirtualNetworkGatewayConnection(), @@ -469,6 +470,7 @@ func Provider() terraform.ResourceProvider { "azurerm_virtual_network_peering": resourceArmVirtualNetworkPeering(), "azurerm_virtual_network": resourceArmVirtualNetwork(), "azurerm_virtual_wan": resourceArmVirtualWan(), + "azurerm_virtual_hub": resourceArmVirtualHub(), "azurerm_web_application_firewall_policy": resourceArmWebApplicationFirewallPolicy(), } diff --git a/azurerm/resource_arm_virtual_hub.go b/azurerm/resource_arm_virtual_hub.go new file mode 100644 index 000000000000..b3ca319f584a --- /dev/null +++ b/azurerm/resource_arm_virtual_hub.go @@ -0,0 +1,410 @@ +package azurerm + +import ( + "fmt" + "log" + "regexp" + + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-06-01/network" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/response" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmVirtualHub() *schema.Resource { + return &schema.Resource{ + Create: resourceArmVirtualHubCreateUpdate, + Read: resourceArmVirtualHubRead, + Update: resourceArmVirtualHubCreateUpdate, + Delete: resourceArmVirtualHubDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringMatch( + regexp.MustCompile(`^.{1,256}$`), + `The name must be between 1 and 256 characters in length.`, + ), + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + + "location": azure.SchemaLocation(), + + "address_prefix": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.CIDR, + }, + + "virtual_wan_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: azure.ValidateResourceID, + }, + + "s2s_vpn_gateway_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: azure.ValidateResourceID, + }, + + "p2s_vpn_gateway_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: azure.ValidateResourceID, + }, + + "express_route_gateway_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: azure.ValidateResourceID, + }, + + "virtual_network_connection": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringMatch( + regexp.MustCompile(`^[\da-zA-Z][-_.\da-zA-Z]{0,78}[_\da-zA-Z]$`), + `The name must be between 1 and 80 characters and begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens.`, + ), + }, + "remote_virtual_network_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: azure.ValidateResourceID, + }, + "allow_hub_to_remote_vnet_transit": { + Type: schema.TypeBool, + Optional: true, + }, + "allow_remote_vnet_to_use_hub_vnet_gateways": { + Type: schema.TypeBool, + Optional: true, + }, + "enable_internet_security": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, + + "route": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address_prefixes": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validate.CIDR, + }, + }, + "next_hop_ip_address": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.IPv4Address, + }, + }, + }, + }, + + "tags": tags.Schema(), + }, + } +} + +func resourceArmVirtualHubCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).Network.VirtualHubClient + ctx := meta.(*ArmClient).StopContext + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + + if features.ShouldResourcesBeImported() && d.IsNewResource() { + existing, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("Error checking for present of existing Virtual Hub %q (Resource Group %q): %+v", name, resourceGroup, err) + } + } + if existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_virtual_hub", *existing.ID) + } + } + + location := azure.NormalizeLocation(d.Get("location").(string)) + addressPrefix := d.Get("address_prefix").(string) + virtualWanId := d.Get("virtual_wan_id").(string) + virtualNetworkConnection := d.Get("virtual_network_connection").([]interface{}) + route := d.Get("route").([]interface{}) + t := d.Get("tags").(map[string]interface{}) + + parameters := network.VirtualHub{ + Location: utils.String(location), + VirtualHubProperties: &network.VirtualHubProperties{ + AddressPrefix: utils.String(addressPrefix), + VirtualWan: &network.SubResource{ + ID: &virtualWanId, + }, + VirtualNetworkConnections: expandArmVirtualHubVirtualNetworkConnection(virtualNetworkConnection), + RouteTable: expandArmVirtualHubRoute(route), + }, + Tags: tags.Expand(t), + } + + if v, ok := d.GetOk("s2s_vpn_gateway_id"); ok { + s2sVpnGatewayId := v.(string) + parameters.VirtualHubProperties.VpnGateway = &network.SubResource{ + ID: &s2sVpnGatewayId, + } + } + if v, ok := d.GetOk("p2s_vpn_gateway_id"); ok { + p2sVpnGatewayId := v.(string) + parameters.VirtualHubProperties.P2SVpnGateway = &network.SubResource{ + ID: &p2sVpnGatewayId, + } + } + if v, ok := d.GetOk("express_route_gateway_id"); ok { + expressRouteGatewayId := v.(string) + parameters.VirtualHubProperties.ExpressRouteGateway = &network.SubResource{ + ID: &expressRouteGatewayId, + } + } + + future, err := client.CreateOrUpdate(ctx, resourceGroup, name, parameters) + if err != nil { + return fmt.Errorf("Error creating Virtual Hub %q (Resource Group %q): %+v", name, resourceGroup, err) + } + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for creation of Virtual Hub %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + return fmt.Errorf("Error retrieving Virtual Hub %q (Resource Group %q): %+v", name, resourceGroup, err) + } + if resp.ID == nil { + return fmt.Errorf("Cannot read Virtual Hub %q (Resource Group %q) ID", name, resourceGroup) + } + d.SetId(*resp.ID) + + return resourceArmVirtualHubRead(d, meta) +} + +func resourceArmVirtualHubRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).Network.VirtualHubClient + ctx := meta.(*ArmClient).StopContext + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + name := id.Path["virtualHubs"] + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] Virtual Hub %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("Error reading Virtual Hub %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + d.Set("name", resp.Name) + d.Set("resource_group_name", resourceGroup) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + if props := resp.VirtualHubProperties; props != nil { + d.Set("address_prefix", props.AddressPrefix) + if props.VirtualWan != nil { + if err := d.Set("virtual_wan_id", props.VirtualWan.ID); err != nil { + return fmt.Errorf("Error setting `virtual_wan_id`: %+v", err) + } + } + if props.VpnGateway != nil { + if err := d.Set("s2s_vpn_gateway_id", props.VpnGateway.ID); err != nil { + return fmt.Errorf("Error setting `s2s_vpn_gateway_id`: %+v", err) + } + } + if props.P2SVpnGateway != nil { + if err := d.Set("p2s_vpn_gateway_id", props.P2SVpnGateway.ID); err != nil { + return fmt.Errorf("Error setting `p2s_vpn_gateway_id`: %+v", err) + } + } + if props.ExpressRouteGateway != nil { + if err := d.Set("express_route_gateway_id", props.ExpressRouteGateway.ID); err != nil { + return fmt.Errorf("Error setting `express_route_gateway_id`: %+v", err) + } + } + if err := d.Set("virtual_network_connection", flattenArmVirtualHubVirtualNetworkConnection(props.VirtualNetworkConnections)); err != nil { + return fmt.Errorf("Error setting `virtual_network_connection`: %+v", err) + } + if props.RouteTable != nil { + if err := d.Set("route", flattenArmVirtualHubRoute(props.RouteTable.Routes)); err != nil { + return fmt.Errorf("Error setting `route`: %+v", err) + } + } + } + + return tags.FlattenAndSet(d, resp.Tags) +} + +func resourceArmVirtualHubDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).Network.VirtualHubClient + ctx := meta.(*ArmClient).StopContext + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + name := id.Path["virtualHubs"] + + future, err := client.Delete(ctx, resourceGroup, name) + if err != nil { + return fmt.Errorf("Error deleting Virtual Hub %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + if !response.WasNotFound(future.Response()) { + return fmt.Errorf("Error waiting for deleting Virtual Hub %q (Resource Group %q): %+v", name, resourceGroup, err) + } + } + + return nil +} + +func expandArmVirtualHubVirtualNetworkConnection(input []interface{}) *[]network.HubVirtualNetworkConnection { + if len(input) == 0 { + return nil + } + + results := make([]network.HubVirtualNetworkConnection, 0) + + for _, item := range input { + v := item.(map[string]interface{}) + name := v["name"].(string) + remoteVirtualNetworkId := v["remote_virtual_network_id"].(string) + allowHubToRemoteVnetTransit := v["allow_hub_to_remote_vnet_transit"].(bool) + allowRemoteVnetToUseHubVnetGateways := v["allow_remote_vnet_to_use_hub_vnet_gateways"].(bool) + enableInternetSecurity := v["enable_internet_security"].(bool) + + result := network.HubVirtualNetworkConnection{ + Name: utils.String(name), + HubVirtualNetworkConnectionProperties: &network.HubVirtualNetworkConnectionProperties{ + RemoteVirtualNetwork: &network.SubResource{ + ID: utils.String(remoteVirtualNetworkId), + }, + AllowHubToRemoteVnetTransit: utils.Bool(allowHubToRemoteVnetTransit), + AllowRemoteVnetToUseHubVnetGateways: utils.Bool(allowRemoteVnetToUseHubVnetGateways), + EnableInternetSecurity: utils.Bool(enableInternetSecurity), + }, + } + + results = append(results, result) + } + return &results +} + +func expandArmVirtualHubRoute(input []interface{}) *network.VirtualHubRouteTable { + if len(input) == 0 { + return nil + } + + results := make([]network.VirtualHubRoute, 0) + for _, item := range input { + v := item.(map[string]interface{}) + addressPrefixes := v["address_prefixes"].([]interface{}) + nextHopIpAddress := v["next_hop_ip_address"].(string) + + result := network.VirtualHubRoute{ + AddressPrefixes: utils.ExpandStringSlice(addressPrefixes), + NextHopIPAddress: utils.String(nextHopIpAddress), + } + + results = append(results, result) + } + + result := network.VirtualHubRouteTable{ + Routes: &results, + } + + return &result +} + +func flattenArmVirtualHubVirtualNetworkConnection(input *[]network.HubVirtualNetworkConnection) []interface{} { + results := make([]interface{}, 0) + if input == nil { + return results + } + + for _, item := range *input { + c := make(map[string]interface{}) + + if name := item.Name; name != nil { + c["name"] = *name + } + if props := item.HubVirtualNetworkConnectionProperties; props != nil { + if v := props.RemoteVirtualNetwork; v != nil { + c["remote_virtual_network_id"] = *v.ID + } + if v := props.AllowHubToRemoteVnetTransit; v != nil { + c["allow_hub_to_remote_vnet_transit"] = *v + } + if v := props.AllowRemoteVnetToUseHubVnetGateways; v != nil { + c["allow_remote_vnet_to_use_hub_vnet_gateways"] = *v + } + if v := props.EnableInternetSecurity; v != nil { + c["enable_internet_security"] = *v + } + } + + results = append(results, c) + } + + return results +} + +func flattenArmVirtualHubRoute(input *[]network.VirtualHubRoute) []interface{} { + results := make([]interface{}, 0) + if input == nil { + return results + } + + for _, item := range *input { + c := make(map[string]interface{}) + + c["address_prefixes"] = utils.FlattenStringSlice(item.AddressPrefixes) + if v := item.NextHopIPAddress; v != nil { + c["next_hop_ip_address"] = *v + } + + results = append(results, c) + } + + return results +} diff --git a/azurerm/resource_arm_virtual_hub_test.go b/azurerm/resource_arm_virtual_hub_test.go new file mode 100644 index 000000000000..1e1d64575523 --- /dev/null +++ b/azurerm/resource_arm_virtual_hub_test.go @@ -0,0 +1,294 @@ +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccAzureRMVirtualHub_basic(t *testing.T) { + resourceName := "azurerm_virtual_hub.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMVirtualHubDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMVirtualHub_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualHubExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMVirtualHub_requiresImport(t *testing.T) { + if !features.ShouldResourcesBeImported() { + t.Skip("Skipping since resources aren't required to be imported") + return + } + + resourceName := "azurerm_virtual_hub.test" + ri := tf.AccRandTimeInt() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMVirtualHubDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMVirtualHub_basic(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualHubExists(resourceName), + ), + }, + { + Config: testAccAzureRMVirtualHub_requiresImport(ri, testLocation()), + ExpectError: testRequiresImportError("azurerm_virtual_hub"), + }, + }, + }) +} + +func TestAccAzureRMVirtualHub_complete(t *testing.T) { + resourceName := "azurerm_virtual_hub.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMVirtualHubDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMVirtualHub_complete(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualHubExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "address_prefix", "10.0.2.0/24"), + resource.TestCheckResourceAttr(resourceName, "virtual_network_connection.#", "1"), + resource.TestCheckResourceAttr(resourceName, "virtual_network_connection.0.name", "testConnection"), + resource.TestCheckResourceAttr(resourceName, "virtual_network_connection.0.allow_hub_to_remote_vnet_transit", "false"), + resource.TestCheckResourceAttr(resourceName, "virtual_network_connection.0.allow_remote_vnet_to_use_hub_vnet_gateways", "false"), + resource.TestCheckResourceAttr(resourceName, "virtual_network_connection.0.enable_internet_security", "false"), + resource.TestCheckResourceAttr(resourceName, "route.#", "1"), + resource.TestCheckResourceAttr(resourceName, "route.0.address_prefixes.#", "1"), + resource.TestCheckResourceAttr(resourceName, "route.0.address_prefixes.0", "10.0.3.0/24"), + resource.TestCheckResourceAttr(resourceName, "route.0.next_hop_ip_address", "10.0.5.6"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.ENV", "prod"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMVirtualHub_update(t *testing.T) { + resourceName := "azurerm_virtual_hub.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMVirtualHubDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMVirtualHub_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualHubExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "address_prefix", "10.0.1.0/24"), + resource.TestCheckResourceAttr(resourceName, "virtual_network_connection.#", "0"), + resource.TestCheckResourceAttr(resourceName, "route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAzureRMVirtualHub_complete(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualHubExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "address_prefix", "10.0.2.0/24"), + resource.TestCheckResourceAttr(resourceName, "virtual_network_connection.#", "1"), + resource.TestCheckResourceAttr(resourceName, "route.#", "1"), + resource.TestCheckResourceAttr(resourceName, "route.0.address_prefixes.#", "1"), + resource.TestCheckResourceAttr(resourceName, "route.0.address_prefixes.0", "10.0.3.0/24"), + resource.TestCheckResourceAttr(resourceName, "route.0.next_hop_ip_address", "10.0.5.6"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testCheckAzureRMVirtualHubExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Virtual Hub not found: %s", resourceName) + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + client := testAccProvider.Meta().(*ArmClient).Network.VirtualHubClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + if resp, err := client.Get(ctx, resourceGroup, name); err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Virtual Hub %q (Resource Group %q) does not exist", name, resourceGroup) + } + return fmt.Errorf("Bad: Get on network.VirtualHubClient: %+v", err) + } + + return nil + } +} + +func testCheckAzureRMVirtualHubDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*ArmClient).Network.VirtualHubClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_virtual_hub" { + continue + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + if resp, err := client.Get(ctx, resourceGroup, name); err != nil { + if !utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Get on network.VirtualHubClient: %+v", err) + } + } + + return nil + } + + return nil +} + +func testAccAzureRMVirtualHub_basic(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-network-%d" + location = "%s" +} + +resource "azurerm_virtual_wan" "test" { + name = "acctest-VirtualWan-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" +} + +resource "azurerm_virtual_hub" "test" { + name = "acctest-VirtualHub-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + address_prefix = "10.0.1.0/24" + virtual_wan_id = "${azurerm_virtual_wan.test.id}" +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMVirtualHub_requiresImport(rInt int, location string) string { + return fmt.Sprintf(` +%s +resource "azurerm_virtual_hub" "import" { + name = "${azurerm_virtual_hub.test.name}" + location = "${azurerm_virtual_hub.test.location}" + resource_group_name = "${azurerm_virtual_hub.test.name}" +} +} +`, testAccAzureRMVirtualHub_basic(rInt, location)) +} + +func testAccAzureRMVirtualHub_complete(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-network-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctest-VirtualNetwork-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + address_space = ["10.5.0.0/16"] +} + +resource "azurerm_network_security_group" "test" { + name = "acctest-NetworkSecurityGroup-%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_prefix = "10.5.1.0/24" + network_security_group_id = "${azurerm_network_security_group.test.id}" +} + +resource "azurerm_virtual_wan" "test" { + name = "acctest-VirtualWan-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" +} + +resource "azurerm_virtual_hub" "test" { + name = "acctest-VirtualHub-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + address_prefix = "10.0.2.0/24" + + virtual_wan_id = "${azurerm_virtual_wan.test.id}" + + virtual_network_connection { + name = "testConnection" + remote_virtual_network_id = "${azurerm_virtual_network.test.id}" + allow_hub_to_remote_vnet_transit = "false" + allow_remote_vnet_to_use_hub_vnet_gateways = "false" + enable_internet_security = "false" + } + + route { + address_prefixes = ["10.0.3.0/24"] + next_hop_ip_address = "10.0.5.6" + } + + tags = { + ENV = "prod" + } +} +`, rInt, location, rInt, rInt, rInt, rInt, rInt) +} diff --git a/examples/virtual-networks/virtual-hub/main.tf b/examples/virtual-networks/virtual-hub/main.tf new file mode 100644 index 000000000000..85fc9b7eae10 --- /dev/null +++ b/examples/virtual-networks/virtual-hub/main.tf @@ -0,0 +1,18 @@ +resource "azurerm_resource_group" "example" { + name = "${var.prefix}-resources" + location = "${var.location}" +} + +resource "azurerm_virtual_wan" "example" { + name = "${var.prefix}-virtualwan" + resource_group_name = "${azurerm_resource_group.example.name}" + location = "${azurerm_resource_group.example.location}" +} + +resource "azurerm_virtual_hub" "example" { + name = "${var.prefix}-virtualhub" + resource_group_name = "${azurerm_resource_group.example.name}" + location = "${azurerm_resource_group.example.location}" + address_prefix = "10.0.1.0/24" + virtual_wan_id = "${azurerm_virtual_wan.example.id}" +} diff --git a/examples/virtual-networks/virtual-hub/variables.tf b/examples/virtual-networks/virtual-hub/variables.tf new file mode 100644 index 000000000000..fb46f53f1d38 --- /dev/null +++ b/examples/virtual-networks/virtual-hub/variables.tf @@ -0,0 +1,7 @@ +variable "location" { + description = "The Azure location where all resources in this example should be created." +} + +variable "prefix" { + description = "The prefix used for all resources used by this Virtual Hub" +} diff --git a/website/azurerm.erb b/website/azurerm.erb index daf50ad76b4d..887975612522 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -445,6 +445,10 @@ > azurerm_virtual_network_gateway_connection + + > + azurerm_virtual_hub + @@ -1670,6 +1674,10 @@ > azurerm_virtual_wan + + > + azurerm_virtual_hub + diff --git a/website/docs/d/virtual_hub.html.markdown b/website/docs/d/virtual_hub.html.markdown new file mode 100644 index 000000000000..5ea0b05438bd --- /dev/null +++ b/website/docs/d/virtual_hub.html.markdown @@ -0,0 +1,79 @@ +--- +subcategory: "Network" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_virtual_hub" +sidebar_current: "docs-azurerm-datasource-virtual-hub" +description: |- + Gets information about an existing Virtual Hub +--- + +# Data Source: azurerm_virtual_hub + +Uses this data source to access information about an existing Virtual Hub. + + +## Virtual Hub Usage + +```hcl +data "azurerm_virtual_hub" "example" { + resource_group = "acctestRG" + name = "acctestvirtualhub" +} +output "virtual_hub_id" { + value = "${data.azurerm_virtual_hub.example.id}" +} +``` + + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the Virtual Hub. + +* `resource_group_name` - (Required) The Name of the Resource Group where the Virtual Hub exists. + + +## Attributes Reference + +The following attributes are exported: + +* `location` - The Azure Region where the Virtual Hub exists. + +* `address_prefix` - Address-prefix for this Virtual Hub. + +* `virtual_wan_id` - The resource id of virtual wan. + +* `s2s_vpn_gateway_id` - The resource id of s2s vpn gateway. + +* `p2s_vpn_gateway_id` - The resource id of p2s vpn gateway. + +* `express_route_gateway_id` - The resource id of express route gateway. + +* `route` - One `route` block defined below. + +* `virtual_network_connection` - One or more `virtual_network_connection` block defined below. + +* `tags` - Resource tags. + +--- + +The `route` block contains the following: + +* `address_prefixes` - List of all addressPrefixes. + +* `next_hop_ip_address` - NextHop ip address. + +--- + +The `virtual_network_connection` block contains the following: + +* `name` - The name of the resource that is unique within a resource group. This name can be used to access the resource. + +* `remote_virtual_network_id` - The resource id of remote virtual network. + +* `allow_hub_to_remote_vnet_transit` - VirtualHub to RemoteVnet transit to enabled or not. + +* `allow_remote_vnet_to_use_hub_vnet_gateways` - Allow RemoteVnet to use Virtual Hub's gateways. + +* `enable_internet_security` - Enable internet security. diff --git a/website/docs/r/virtual_hub.html.markdown b/website/docs/r/virtual_hub.html.markdown new file mode 100644 index 000000000000..793a44835a47 --- /dev/null +++ b/website/docs/r/virtual_hub.html.markdown @@ -0,0 +1,98 @@ +--- +subcategory: "Network" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_virtual_hub" +sidebar_current: "docs-azurerm-resource-virtual-hub" +description: |- + Manages a Virtual Hub. +--- + +# azurerm_virtual_hub + +Manages a Virtual Hub. + + +## Virtual Hub Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West Europe" +} +resource "azurerm_virtual_wan" "example" { + name = "example-virtualwan" + resource_group_name = "${azurerm_resource_group.example.name}" + location = "${azurerm_resource_group.example.location}" +} +resource "azurerm_virtual_hub" "example" { + name = "example-virtualhub" + resource_group_name = "${azurerm_resource_group.example.name}" + location = "${azurerm_resource_group.example.location}" + address_prefix = "10.0.1.0/24" + virtual_wan_id = "${azurerm_virtual_wan.example.id}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the Virtual Hub. Changing this forces a new resource to be created. + +* `resource_group_name` - (Required) The name of the resource group where the Virtual Hub should be created. Changing this forces a new resource to be created. + +* `location` - (Required) Specifies the supported Azure location where the resource exists. Changing this forces a new resource to be created. + +* `address_prefix` - (Required) Address-prefix for this Virtual Hub. + +* `virtual_wan_id` - (Required) The resource id of virtual wan. + +* `s2s_vpn_gateway_id` - (Optional) The resource id of s2s vpn gateway. + +* `p2s_vpn_gateway_id` - (Optional) The resource id of p2s vpn gateway. + +* `express_route_gateway_id` - (Optional) The resource id of express route gateway. + +* `virtual_network_connection` - (Optional) One or more `virtual_network_connection` block defined below. + +* `route` - (Optional) One `route` block defined below. + +* `tags` - (Optional) Resource tags. Changing this forces a new resource to be created. + +--- + +The `route` block supports the following: + +* `address_prefixes` - (Required) List of all addressPrefixes. + +* `next_hop_ip_address` - (Required) NextHop ip address. + +--- + +The `virtual_network_connection` block supports the following: + +* `name` - (Required) The name of the resource that is unique within a resource group. This name can be used to access the resource. + +* `remote_virtual_network_id` - (Required) The resource id of remote virtual network. + +* `allow_hub_to_remote_vnet_transit` - (Optional) VirtualHub to RemoteVnet transit to enabled or not. + +* `allow_remote_vnet_to_use_hub_vnet_gateways` - (Optional) Allow RemoteVnet to use Virtual Hub's gateways. + +* `enable_internet_security` - (Optional) Enable internet security. + +--- + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the Virtual Hub. + +## Import + +Virtual Hub can be imported using the `resource id`, e.g. + +```shell +$ terraform import azurerm_virtual_hub.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Network/virtualHubs/vhub1 +``` \ No newline at end of file From f941a681cfbe4a349aef4fa025327d9238d6822f Mon Sep 17 00:00:00 2001 From: v-cheye Date: Tue, 19 Nov 2019 23:51:41 +0800 Subject: [PATCH 2/5] Update code --- azurerm/resource_arm_virtual_hub.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/resource_arm_virtual_hub.go b/azurerm/resource_arm_virtual_hub.go index b3ca319f584a..17a2192477de 100644 --- a/azurerm/resource_arm_virtual_hub.go +++ b/azurerm/resource_arm_virtual_hub.go @@ -5,7 +5,7 @@ import ( "log" "regexp" - "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-06-01/network" + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-07-01/network" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" From ca1331f2de44c1d19166334380f324645094dee4 Mon Sep 17 00:00:00 2001 From: v-cheye Date: Wed, 20 Nov 2019 09:41:04 +0800 Subject: [PATCH 3/5] Update code by comment --- azurerm/data_source_virtual_hub.go | 12 ++-- azurerm/internal/services/network/validate.go | 16 +++++ azurerm/resource_arm_virtual_hub.go | 69 ++++++++++--------- azurerm/resource_arm_virtual_hub_test.go | 4 +- website/azurerm.erb | 12 ++-- 5 files changed, 64 insertions(+), 49 deletions(-) create mode 100644 azurerm/internal/services/network/validate.go diff --git a/azurerm/data_source_virtual_hub.go b/azurerm/data_source_virtual_hub.go index e6ddf0bd2674..a50e653a2518 100644 --- a/azurerm/data_source_virtual_hub.go +++ b/azurerm/data_source_virtual_hub.go @@ -2,11 +2,10 @@ package azurerm import ( "fmt" - "regexp" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + aznetwork "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -17,12 +16,9 @@ func dataSourceArmVirtualHub() *schema.Resource { Schema: map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringMatch( - regexp.MustCompile(`^.{1,256}$`), - `The name must be between 1 and 256 characters in length.`, - ), + Type: schema.TypeString, + Required: true, + ValidateFunc: aznetwork.ValidateVirtualHubName, }, "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), diff --git a/azurerm/internal/services/network/validate.go b/azurerm/internal/services/network/validate.go new file mode 100644 index 000000000000..3accbecee501 --- /dev/null +++ b/azurerm/internal/services/network/validate.go @@ -0,0 +1,16 @@ +package network + +import ( + "fmt" + "regexp" +) + +func ValidateVirtualHubName(v interface{}, k string) (warnings []string, errors []error) { + value := v.(string) + + if !regexp.MustCompile(`^.{1,256}$`).MatchString(value) { + errors = append(errors, fmt.Errorf("%q must be between 1 and 256 characters in length.", k)) + } + + return warnings, errors +} diff --git a/azurerm/resource_arm_virtual_hub.go b/azurerm/resource_arm_virtual_hub.go index 17a2192477de..0687fa8e3128 100644 --- a/azurerm/resource_arm_virtual_hub.go +++ b/azurerm/resource_arm_virtual_hub.go @@ -13,6 +13,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" + aznetwork "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -30,13 +31,10 @@ func resourceArmVirtualHub() *schema.Resource { Schema: map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringMatch( - regexp.MustCompile(`^.{1,256}$`), - `The name must be between 1 and 256 characters in length.`, - ), + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: aznetwork.ValidateVirtualHubName, }, "resource_group_name": azure.SchemaResourceGroupName(), @@ -306,27 +304,30 @@ func expandArmVirtualHubVirtualNetworkConnection(input []interface{}) *[]network results := make([]network.HubVirtualNetworkConnection, 0) for _, item := range input { - v := item.(map[string]interface{}) - name := v["name"].(string) - remoteVirtualNetworkId := v["remote_virtual_network_id"].(string) - allowHubToRemoteVnetTransit := v["allow_hub_to_remote_vnet_transit"].(bool) - allowRemoteVnetToUseHubVnetGateways := v["allow_remote_vnet_to_use_hub_vnet_gateways"].(bool) - enableInternetSecurity := v["enable_internet_security"].(bool) - - result := network.HubVirtualNetworkConnection{ - Name: utils.String(name), - HubVirtualNetworkConnectionProperties: &network.HubVirtualNetworkConnectionProperties{ - RemoteVirtualNetwork: &network.SubResource{ - ID: utils.String(remoteVirtualNetworkId), + if item != nil { + v := item.(map[string]interface{}) + name := v["name"].(string) + remoteVirtualNetworkId := v["remote_virtual_network_id"].(string) + allowHubToRemoteVnetTransit := v["allow_hub_to_remote_vnet_transit"].(bool) + allowRemoteVnetToUseHubVnetGateways := v["allow_remote_vnet_to_use_hub_vnet_gateways"].(bool) + enableInternetSecurity := v["enable_internet_security"].(bool) + + result := network.HubVirtualNetworkConnection{ + Name: utils.String(name), + HubVirtualNetworkConnectionProperties: &network.HubVirtualNetworkConnectionProperties{ + RemoteVirtualNetwork: &network.SubResource{ + ID: utils.String(remoteVirtualNetworkId), + }, + AllowHubToRemoteVnetTransit: utils.Bool(allowHubToRemoteVnetTransit), + AllowRemoteVnetToUseHubVnetGateways: utils.Bool(allowRemoteVnetToUseHubVnetGateways), + EnableInternetSecurity: utils.Bool(enableInternetSecurity), }, - AllowHubToRemoteVnetTransit: utils.Bool(allowHubToRemoteVnetTransit), - AllowRemoteVnetToUseHubVnetGateways: utils.Bool(allowRemoteVnetToUseHubVnetGateways), - EnableInternetSecurity: utils.Bool(enableInternetSecurity), - }, - } + } - results = append(results, result) + results = append(results, result) + } } + return &results } @@ -337,16 +338,18 @@ func expandArmVirtualHubRoute(input []interface{}) *network.VirtualHubRouteTable results := make([]network.VirtualHubRoute, 0) for _, item := range input { - v := item.(map[string]interface{}) - addressPrefixes := v["address_prefixes"].([]interface{}) - nextHopIpAddress := v["next_hop_ip_address"].(string) + if item != nil { + v := item.(map[string]interface{}) + addressPrefixes := v["address_prefixes"].([]interface{}) + nextHopIpAddress := v["next_hop_ip_address"].(string) + + result := network.VirtualHubRoute{ + AddressPrefixes: utils.ExpandStringSlice(addressPrefixes), + NextHopIPAddress: utils.String(nextHopIpAddress), + } - result := network.VirtualHubRoute{ - AddressPrefixes: utils.ExpandStringSlice(addressPrefixes), - NextHopIPAddress: utils.String(nextHopIpAddress), + results = append(results, result) } - - results = append(results, result) } result := network.VirtualHubRouteTable{ diff --git a/azurerm/resource_arm_virtual_hub_test.go b/azurerm/resource_arm_virtual_hub_test.go index 1e1d64575523..7da60935a548 100644 --- a/azurerm/resource_arm_virtual_hub_test.go +++ b/azurerm/resource_arm_virtual_hub_test.go @@ -274,7 +274,7 @@ resource "azurerm_virtual_hub" "test" { virtual_wan_id = "${azurerm_virtual_wan.test.id}" virtual_network_connection { - name = "testConnection" + name = "testConnection" remote_virtual_network_id = "${azurerm_virtual_network.test.id}" allow_hub_to_remote_vnet_transit = "false" allow_remote_vnet_to_use_hub_vnet_gateways = "false" @@ -283,7 +283,7 @@ resource "azurerm_virtual_hub" "test" { route { address_prefixes = ["10.0.3.0/24"] - next_hop_ip_address = "10.0.5.6" + next_hop_ip_address = "10.0.5.6" } tags = { diff --git a/website/azurerm.erb b/website/azurerm.erb index 5d37a112d717..490c49c17cdc 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -442,11 +442,11 @@ azurerm_virtual_network_gateway - > - azurerm_virtual_network_gateway_connection - + > + azurerm_virtual_network_gateway_connection + - > + > azurerm_virtual_hub @@ -1688,11 +1688,11 @@ > - azurerm_virtual_wan + azurerm_virtual_wan > - azurerm_virtual_hub + azurerm_virtual_hub From 091caf923d526c7a023e368252e5971968434d10 Mon Sep 17 00:00:00 2001 From: v-cheye Date: Wed, 20 Nov 2019 09:45:49 +0800 Subject: [PATCH 4/5] Update formatting --- website/azurerm.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/azurerm.erb b/website/azurerm.erb index 490c49c17cdc..1ad5e38b4337 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -1688,11 +1688,11 @@ > - azurerm_virtual_wan + azurerm_virtual_wan > - azurerm_virtual_hub + azurerm_virtual_hub From bfc83da9c2fdde3c7ffd4e64d7598e461d99d40a Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Wed, 20 Nov 2019 15:58:53 +0800 Subject: [PATCH 5/5] update code --- azurerm/resource_arm_virtual_hub_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/resource_arm_virtual_hub_test.go b/azurerm/resource_arm_virtual_hub_test.go index 7da60935a548..325939903b3d 100644 --- a/azurerm/resource_arm_virtual_hub_test.go +++ b/azurerm/resource_arm_virtual_hub_test.go @@ -222,12 +222,12 @@ resource "azurerm_virtual_hub" "test" { func testAccAzureRMVirtualHub_requiresImport(rInt int, location string) string { return fmt.Sprintf(` %s + resource "azurerm_virtual_hub" "import" { name = "${azurerm_virtual_hub.test.name}" location = "${azurerm_virtual_hub.test.location}" resource_group_name = "${azurerm_virtual_hub.test.name}" } -} `, testAccAzureRMVirtualHub_basic(rInt, location)) }