diff --git a/azurerm/data_source_express_route_circuit.go b/azurerm/data_source_express_route_circuit.go new file mode 100644 index 000000000000..d733e9d96dfe --- /dev/null +++ b/azurerm/data_source_express_route_circuit.go @@ -0,0 +1,226 @@ +package azurerm + +import ( + "fmt" + + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-12-01/network" + "github.com/hashicorp/terraform/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceArmExpressRouteCircuit() *schema.Resource { + return &schema.Resource{ + Read: dataSourceArmExpressRouteCircuitRead, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "resource_group_name": resourceGroupNameForDataSourceSchema(), + + "location": locationForDataSourceSchema(), + + "peerings": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "peering_type": { + Type: schema.TypeString, + Computed: true, + }, + "primary_peer_address_prefix": { + Type: schema.TypeString, + Computed: true, + }, + "secondary_peer_address_prefix": { + Type: schema.TypeString, + Computed: true, + }, + "azure_asn": { + Type: schema.TypeInt, + Computed: true, + }, + "peer_asn": { + Type: schema.TypeInt, + Computed: true, + }, + "vlan_id": { + Type: schema.TypeInt, + Computed: true, + }, + "shared_key": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "service_key": { + Type: schema.TypeString, + Computed: true, + }, + + "service_provider_properties": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service_provider_name": { + Type: schema.TypeString, + Computed: true, + }, + "peering_location": { + Type: schema.TypeString, + Computed: true, + }, + "bandwidth_in_mbps": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + + "service_provider_provisioning_state": { + Type: schema.TypeString, + Computed: true, + }, + + "sku": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "tier": { + Type: schema.TypeString, + Computed: true, + }, + + "family": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceArmExpressRouteCircuitRead(d *schema.ResourceData, meta interface{}) error { + ctx := meta.(*ArmClient).StopContext + client := meta.(*ArmClient).expressRouteCircuitClient + + 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: Express Route Circuit %q (Resource Group %q) was not found", name, resourceGroup) + } + return fmt.Errorf("Error making Read request on the Express Route Circuit %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + d.SetId(*resp.ID) + + if location := resp.Location; location != nil { + d.Set("location", azureRMNormalizeLocation(*location)) + } + + if properties := resp.ExpressRouteCircuitPropertiesFormat; properties != nil { + peerings := flattenExpressRouteCircuitPeerings(properties.Peerings) + if err := d.Set("peerings", peerings); err != nil { + return err + } + + d.Set("service_key", properties.ServiceKey) + d.Set("service_provider_provisioning_state", properties.ServiceProviderProvisioningState) + + if serviceProviderProperties := flattenExpressRouteCircuitServiceProviderProperties(properties.ServiceProviderProperties); serviceProviderProperties != nil { + if err := d.Set("service_provider_properties", serviceProviderProperties); err != nil { + return fmt.Errorf("Error setting `service_provider_properties`: %+v", err) + } + } + + } + + if resp.Sku != nil { + sku := flattenExpressRouteCircuitSku(resp.Sku) + if err := d.Set("sku", sku); err != nil { + return fmt.Errorf("Error setting `sku`: %+v", err) + } + } + + return nil +} + +func flattenExpressRouteCircuitPeerings(input *[]network.ExpressRouteCircuitPeering) []interface{} { + peerings := make([]interface{}, 0) + + if input != nil { + for _, peering := range *input { + props := peering.ExpressRouteCircuitPeeringPropertiesFormat + p := make(map[string]interface{}) + + p["peering_type"] = string(props.PeeringType) + + if primaryPeerAddressPrefix := props.PrimaryPeerAddressPrefix; primaryPeerAddressPrefix != nil { + p["primary_peer_address_prefix"] = *primaryPeerAddressPrefix + } + + if secondaryPeerAddressPrefix := props.SecondaryPeerAddressPrefix; secondaryPeerAddressPrefix != nil { + p["secondary_peer_address_prefix"] = *secondaryPeerAddressPrefix + } + + if azureAsn := props.AzureASN; azureAsn != nil { + p["azure_asn"] = *azureAsn + } + + if peerAsn := props.PeerASN; peerAsn != nil { + p["peer_asn"] = *peerAsn + } + + if vlanID := props.VlanID; vlanID != nil { + p["vlan_id"] = *vlanID + } + + if sharedKey := props.SharedKey; sharedKey != nil { + p["shared_key"] = *sharedKey + } + + peerings = append(peerings, p) + } + } + + return peerings +} + +func flattenExpressRouteCircuitServiceProviderProperties(input *network.ExpressRouteCircuitServiceProviderProperties) []interface{} { + serviceProviderProperties := make([]interface{}, 0) + + if input != nil { + p := make(map[string]interface{}) + + if serviceProviderName := input.ServiceProviderName; serviceProviderName != nil { + p["service_provider_name"] = *serviceProviderName + } + + if peeringLocation := input.PeeringLocation; peeringLocation != nil { + p["peering_location"] = *peeringLocation + } + + if bandwidthInMbps := input.BandwidthInMbps; bandwidthInMbps != nil { + p["bandwidth_in_mbps"] = *bandwidthInMbps + } + + serviceProviderProperties = append(serviceProviderProperties, p) + } + + return serviceProviderProperties +} diff --git a/azurerm/data_source_express_route_circuit_test.go b/azurerm/data_source_express_route_circuit_test.go new file mode 100644 index 000000000000..d2932c4816b3 --- /dev/null +++ b/azurerm/data_source_express_route_circuit_test.go @@ -0,0 +1,47 @@ +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" +) + +func testAccDataSourceAzureRMExpressRoute_basicMetered(t *testing.T) { + dataSourceName := "data.azurerm_express_route_circuit.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMExpressRouteCircuitDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAzureRMExpressRoute_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "service_provider_properties.0.service_provider_name", "Equinix"), + resource.TestCheckResourceAttr(dataSourceName, "service_provider_properties.0.peering_location", "Silicon Valley"), + resource.TestCheckResourceAttr(dataSourceName, "service_provider_properties.0.bandwidth_in_mbps", "50"), + resource.TestCheckResourceAttr(dataSourceName, "sku.0.tier", "Standard"), + resource.TestCheckResourceAttr(dataSourceName, "sku.0.family", "MeteredData"), + resource.TestCheckResourceAttr(dataSourceName, "service_provider_provisioning_state", "NotProvisioned"), + ), + }, + }, + }) +} + +func testAccDataSourceAzureRMExpressRoute_basic(rInt int, location string) string { + config := testAccAzureRMExpressRouteCircuit_basicMeteredConfig(rInt, location) + + return fmt.Sprintf(` + %s + + data "azurerm_express_route_circuit" test { + resource_group_name = "${azurerm_resource_group.test.name}" + name = "${azurerm_express_route_circuit.test.name}" + } + `, config) +} diff --git a/azurerm/provider.go b/azurerm/provider.go index 6d5afaa9d7a5..b3174d38fb16 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -122,6 +122,7 @@ func Provider() terraform.ResourceProvider { "azurerm_dev_test_lab": dataSourceArmDevTestLab(), "azurerm_dns_zone": dataSourceArmDnsZone(), "azurerm_eventhub_namespace": dataSourceEventHubNamespace(), + "azurerm_express_route_circuit": dataSourceArmExpressRouteCircuit(), "azurerm_firewall": dataSourceArmFirewall(), "azurerm_image": dataSourceArmImage(), "azurerm_hdinsight_cluster": dataSourceArmHDInsightSparkCluster(), diff --git a/azurerm/resource_arm_express_route_circuit_test.go b/azurerm/resource_arm_express_route_circuit_test.go index 218e77a53b2a..0e3a61596352 100644 --- a/azurerm/resource_arm_express_route_circuit_test.go +++ b/azurerm/resource_arm_express_route_circuit_test.go @@ -25,6 +25,7 @@ func TestAccAzureRMExpressRouteCircuit(t *testing.T) { "premiumUnlimited": testAccAzureRMExpressRouteCircuit_premiumUnlimited, "allowClassicOperationsUpdate": testAccAzureRMExpressRouteCircuit_allowClassicOperationsUpdate, "requiresImport": testAccAzureRMExpressRouteCircuit_requiresImport, + "data_basic": testAccDataSourceAzureRMExpressRoute_basicMetered, }, "PrivatePeering": { "azurePrivatePeering": testAccAzureRMExpressRouteCircuitPeering_azurePrivatePeering, diff --git a/azurerm/resource_arm_virtual_network_gateway_connection.go b/azurerm/resource_arm_virtual_network_gateway_connection.go index 8677e0430af7..ec76fa9b9c45 100644 --- a/azurerm/resource_arm_virtual_network_gateway_connection.go +++ b/azurerm/resource_arm_virtual_network_gateway_connection.go @@ -108,6 +108,12 @@ func resourceArmVirtualNetworkGatewayConnection() *schema.Resource { Sensitive: true, }, + "express_route_gateway_bypass": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + "ipsec_policy": { Type: schema.TypeList, Optional: true, @@ -350,6 +356,10 @@ func resourceArmVirtualNetworkGatewayConnectionRead(d *schema.ResourceData, meta d.Set("shared_key", conn.SharedKey) } + if conn.ExpressRouteGatewayBypass != nil { + d.Set("express_route_gateway_bypass", conn.ExpressRouteGatewayBypass) + } + if conn.IpsecPolicies != nil { ipsecPolicies := flattenArmVirtualNetworkGatewayConnectionIpsecPolicies(conn.IpsecPolicies) @@ -390,6 +400,7 @@ func getArmVirtualNetworkGatewayConnectionProperties(d *schema.ResourceData) (*n props := &network.VirtualNetworkGatewayConnectionPropertiesFormat{ ConnectionType: connectionType, EnableBgp: utils.Bool(d.Get("enable_bgp").(bool)), + ExpressRouteGatewayBypass: utils.Bool(d.Get("express_route_gateway_bypass").(bool)), UsePolicyBasedTrafficSelectors: utils.Bool(d.Get("use_policy_based_traffic_selectors").(bool)), } diff --git a/website/azurerm.erb b/website/azurerm.erb index 1d0dc2dc1cc0..caf5d8b9d081 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -155,6 +155,10 @@ azurerm_eventhub_namespace + > + azurerm_express_route_circuit + + > azurerm_firewall diff --git a/website/docs/d/express_route_circuit.html.markdown b/website/docs/d/express_route_circuit.html.markdown new file mode 100644 index 000000000000..bdaa225666e2 --- /dev/null +++ b/website/docs/d/express_route_circuit.html.markdown @@ -0,0 +1,73 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_express_route_circuit" +sidebar_current: "docs-azurerm-datasource-express-route-circuit" +description: |- + Gets information about an existing ExpressRoute circuit. +--- + +# Data Source: azurerm_express_route_circuit + +Use this data source to access information about an existing ExpressRoute circuit. + +## Example Usage + +```hcl +data "azurerm_express_route_circuit" test { + resource_group_name = "${azurerm_resource_group.test.name}" + name = "${azurerm_express_route_circuit.test.name}" +} + +output "express_route_circuit_id" { + value = "${data.azurerm_express_route_circuit.test.id}" +} + +output "service_key" { + value = "${data.azurerm_express_route_circuit.test.service_key}" +} +``` + +## Argument Reference + +* `name` - (Required) The name of the ExpressRoute circuit. +* `resource_group_name` - (Required) The Name of the Resource Group where the ExpressRoute circuit exists. + +## Attributes Reference + +* `id` - The ID of the ExpressRoute circuit. + +* `location` - The Azure location where the ExpressRoute circuit exists + +* `peerings` - A `peerings` block for the ExpressRoute circuit as documented below + +* `service_provider_provisioning_state` - The ExpressRoute circuit provisioning state from your chosen service provider. Possible values are "NotProvisioned", "Provisioning", "Provisioned", and "Deprovisioning". + +* `service_key` - The string needed by the service provider to provision the ExpressRoute circuit. + +* `service_provider_properties` - A `service_provider_properties` block for the ExpressRoute circuit as documented below + +* `sku` - A `sku` block for the ExpressRoute circuit as documented below. + +--- + +`service_provider_properties` supports the following: + +* `service_provider_name` - The name of the ExpressRoute Service Provider. +* `peering_location` - The name of the peering location and **not** the Azure resource location. +* `bandwidth_in_mbps` - The bandwidth in Mbps of the ExpressRoute circuit. + +`peerings` supports the following: + +* `peering_type` - The type of the ExpressRoute Circuit Peering. Acceptable values include `AzurePrivatePeering`, `AzurePublicPeering` and `MicrosoftPeering`. Changing this forces a new resource to be created. +~> **NOTE:** only one Peering of each Type can be created per ExpressRoute circuit. +* `primary_peer_address_prefix` - A `/30` subnet for the primary link. +* `secondary_peer_address_prefix` - A `/30` subnet for the secondary link. +* `vlan_id` - A valid VLAN ID to establish this peering on. +* `shared_key` - The shared key. Can be a maximum of 25 characters. +* `azure_asn` - The Either a 16-bit or a 32-bit ASN for Azure. +* `peer_asn` - The Either a 16-bit or a 32-bit ASN. Can either be public or private. + +`sku` supports the following: + +* `tier` - The service tier. Possible values are `Standard` or `Premium`. +* `family` - The billing mode for bandwidth. Possible values are `MeteredData` or `UnlimitedData`. \ No newline at end of file diff --git a/website/docs/r/virtual_network_gateway_connection.html.markdown b/website/docs/r/virtual_network_gateway_connection.html.markdown index 6291f947868b..bb4079b01af1 100644 --- a/website/docs/r/virtual_network_gateway_connection.html.markdown +++ b/website/docs/r/virtual_network_gateway_connection.html.markdown @@ -247,6 +247,8 @@ The following arguments are supported: * `enable_bgp` - (Optional) If `true`, BGP (Border Gateway Protocol) is enabled for this connection. Defaults to `false`. +* `express_route_gateway_bypass` - (Optional) If `true`, data packets will bypass ExpressRoute Gateway for data forwarding This is only valid for ExpressRoute connections. + * `use_policy_based_traffic_selectors` - (Optional) If `true`, policy-based traffic selectors are enabled for this connection. Enabling policy-based traffic selectors requires an `ipsec_policy` block. Defaults to `false`.