From 0771690751b1e8430141ed6a3347cc5a8b998ce0 Mon Sep 17 00:00:00 2001 From: magodo Date: Sat, 7 Nov 2020 00:55:44 +0800 Subject: [PATCH] azurerm_virtual_network: support for `bgp_community` and `vnet_protection_enabled` (#8979) Support for bgp_community and vnet_protection_enabled properties for vnet. --- .../tests/virtual_network_resource_test.go | 127 ++++++++++++++++++ .../network/validate/virtual_network.go | 37 +++++ .../network/virtual_network_resource.go | 33 ++++- website/docs/r/virtual_network.html.markdown | 6 + 4 files changed, 202 insertions(+), 1 deletion(-) diff --git a/azurerm/internal/services/network/tests/virtual_network_resource_test.go b/azurerm/internal/services/network/tests/virtual_network_resource_test.go index 8e27c365f4c7..635d1706ffa8 100644 --- a/azurerm/internal/services/network/tests/virtual_network_resource_test.go +++ b/azurerm/internal/services/network/tests/virtual_network_resource_test.go @@ -203,6 +203,79 @@ func TestAccAzureRMVirtualNetwork_deleteSubnet(t *testing.T) { }) } +func TestAccAzureRMVirtualNetwork_bgpCommunity(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_virtual_network", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMVirtualNetworkDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMVirtualNetwork_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualNetworkExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMVirtualNetwork_bgpCommunity(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualNetworkExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMVirtualNetwork_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualNetworkExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMVirtualNetwork_vmProtection(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_virtual_network", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMVirtualNetworkDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMVirtualNetwork_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualNetworkExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMVirtualNetwork_vmProtection(data, true), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualNetworkExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMVirtualNetwork_vmProtection(data, false), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualNetworkExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMVirtualNetwork_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualNetworkExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + func testCheckAzureRMVirtualNetworkExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { client := acceptance.AzureProvider.Meta().(*clients.Client).Network.VnetClient @@ -480,3 +553,57 @@ resource "azurerm_virtual_network" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } + +func testAccAzureRMVirtualNetwork_bgpCommunity(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvirtnet%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + subnet { + name = "subnet1" + address_prefix = "10.0.1.0/24" + } + + bgp_community = "12076:20000" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} + +func testAccAzureRMVirtualNetwork_vmProtection(data acceptance.TestData, enabled bool) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvirtnet%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + subnet { + name = "subnet1" + address_prefix = "10.0.1.0/24" + } + + vm_protection_enabled = %t +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, enabled) +} diff --git a/azurerm/internal/services/network/validate/virtual_network.go b/azurerm/internal/services/network/validate/virtual_network.go index 03b10e31f2ef..cc0151d3b47c 100644 --- a/azurerm/internal/services/network/validate/virtual_network.go +++ b/azurerm/internal/services/network/validate/virtual_network.go @@ -2,6 +2,8 @@ package validate import ( "fmt" + "strconv" + "strings" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" ) @@ -21,3 +23,38 @@ func VirtualNetworkID(i interface{}, k string) (warnings []string, errors []erro return warnings, errors } + +func VirtualNetworkBgpCommunity(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) + return + } + + segments := strings.Split(v, ":") + if len(segments) != 2 { + errors = append(errors, fmt.Errorf(`invalid notation of bgp community: expected "x:y"`)) + return + } + + asn, err := strconv.Atoi(segments[0]) + if err != nil { + errors = append(errors, fmt.Errorf(`converting asn %q: %v`, segments[0], err)) + return + } + if !(asn > 0 && asn < 65535) { + errors = append(errors, fmt.Errorf(`asn %d exceeds range: [0, 65535]`, asn)) + return + } + + comm, err := strconv.Atoi(segments[1]) + if err != nil { + errors = append(errors, fmt.Errorf(`converting community value %q: %v`, segments[1], err)) + return + } + if !(comm > 0 && comm < 65535) { + errors = append(errors, fmt.Errorf(`community value %d exceeds range: [0, 65535]`, comm)) + return + } + return warnings, errors +} diff --git a/azurerm/internal/services/network/virtual_network_resource.go b/azurerm/internal/services/network/virtual_network_resource.go index a99e807c94c5..27dcce2baa64 100644 --- a/azurerm/internal/services/network/virtual_network_resource.go +++ b/azurerm/internal/services/network/virtual_network_resource.go @@ -8,6 +8,8 @@ import ( "net/http" "time" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" @@ -63,6 +65,12 @@ func resourceArmVirtualNetwork() *schema.Resource { }, }, + "bgp_community": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.VirtualNetworkBgpCommunity, + }, + "ddos_protection_plan": { Type: schema.TypeList, Optional: true, @@ -92,6 +100,12 @@ func resourceArmVirtualNetwork() *schema.Resource { }, }, + "vm_protection_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "guid": { Type: schema.TypeString, Computed: true, @@ -260,6 +274,18 @@ func resourceArmVirtualNetworkRead(d *schema.ResourceData, meta interface{}) err if err := d.Set("dns_servers", flattenVirtualNetworkDNSServers(props.DhcpOptions)); err != nil { return fmt.Errorf("Error setting `dns_servers`: %+v", err) } + + bgpCommunity := "" + if p := props.BgpCommunities; p != nil { + if v := p.VirtualNetworkCommunity; v != nil { + bgpCommunity = *v + } + } + if err := d.Set("bgp_community", bgpCommunity); err != nil { + return fmt.Errorf("Error setting `bgp_community`: %+v", err) + } + + d.Set("vm_protection_enabled", props.EnableVMProtection) } return tags.FlattenAndSet(d, resp.Tags) @@ -345,7 +371,8 @@ func expandVirtualNetworkProperties(ctx context.Context, d *schema.ResourceData, DhcpOptions: &network.DhcpOptions{ DNSServers: utils.ExpandStringSlice(d.Get("dns_servers").([]interface{})), }, - Subnets: &subnets, + EnableVMProtection: utils.Bool(d.Get("vm_protection_enabled").(bool)), + Subnets: &subnets, } if v, ok := d.GetOk("ddos_protection_plan"); ok { @@ -369,6 +396,10 @@ func expandVirtualNetworkProperties(ctx context.Context, d *schema.ResourceData, } } + if v, ok := d.GetOk("bgp_community"); ok { + properties.BgpCommunities = &network.VirtualNetworkBgpCommunities{VirtualNetworkCommunity: utils.String(v.(string))} + } + return properties, nil } diff --git a/website/docs/r/virtual_network.html.markdown b/website/docs/r/virtual_network.html.markdown index 9df4397296d8..ebf6b0ec8ddc 100644 --- a/website/docs/r/virtual_network.html.markdown +++ b/website/docs/r/virtual_network.html.markdown @@ -81,6 +81,10 @@ The following arguments are supported: * `location` - (Required) The location/region where the virtual network is created. Changing this forces a new resource to be created. +* `bgp_community` - (Optional) The BGP community attribute in format `:`. + +-> **NOTE** The `as-number` segment is the Microsoft ASN, which is always `12076` for now. + * `ddos_protection_plan` - (Optional) A `ddos_protection_plan` block as documented below. * `dns_servers` - (Optional) List of IP addresses of DNS servers @@ -89,6 +93,8 @@ The following arguments are supported: -> **NOTE** Since `subnet` can be configured both inline and via the separate `azurerm_subnet` resource, we have to explicitly set it to empty slice (`[]`) to remove it. +* `vm_protection_enabled` - (Optional) Whether to enable VM protection for all the subnets in this Virtual Network. Defaults to `false`. + * `tags` - (Optional) A mapping of tags to assign to the resource. ---