From c85c7f7904802b8d0a317ca485b21a4658c23578 Mon Sep 17 00:00:00 2001 From: xuzhang3 Date: Mon, 22 Mar 2021 13:48:45 +0800 Subject: [PATCH 01/28] new resource express route circuit connection --- .../services/network/client/client.go | 5 + ...s_route_circuit_connections_data_source.go | 78 ++++++ ...te_circuit_connections_data_source_test.go | 61 +++++ ...ress_route_circuit_connections_resource.go | 251 ++++++++++++++++++ ...route_circuit_connections_resource_test.go | 214 +++++++++++++++ ...etwork_express_route_circuit_connection.go | 56 ++++ ...k_express_route_circuit_connection_test.go | 128 +++++++++ .../internal/services/network/registration.go | 2 + ...ss_route_circuit_connections.html.markdown | 50 ++++ ...ss_route_circuit_connections.html.markdown | 97 +++++++ 10 files changed, 942 insertions(+) create mode 100644 azurerm/internal/services/network/express_route_circuit_connections_data_source.go create mode 100644 azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go create mode 100644 azurerm/internal/services/network/express_route_circuit_connections_resource.go create mode 100644 azurerm/internal/services/network/express_route_circuit_connections_resource_test.go create mode 100644 azurerm/internal/services/network/parse/network_express_route_circuit_connection.go create mode 100644 azurerm/internal/services/network/parse/network_express_route_circuit_connection_test.go create mode 100644 website/docs/d/network_express_route_circuit_connections.html.markdown create mode 100644 website/docs/r/network_express_route_circuit_connections.html.markdown diff --git a/azurerm/internal/services/network/client/client.go b/azurerm/internal/services/network/client/client.go index 6e53c978b3d3..ac58e089aad3 100644 --- a/azurerm/internal/services/network/client/client.go +++ b/azurerm/internal/services/network/client/client.go @@ -13,6 +13,7 @@ type Client struct { DDOSProtectionPlansClient *network.DdosProtectionPlansClient ExpressRouteAuthsClient *network.ExpressRouteCircuitAuthorizationsClient ExpressRouteCircuitsClient *network.ExpressRouteCircuitsClient + ExpressRouteCircuitConnectionClient *network.ExpressRouteCircuitConnectionsClient ExpressRouteGatewaysClient *network.ExpressRouteGatewaysClient ExpressRoutePeeringsClient *network.ExpressRouteCircuitPeeringsClient HubRouteTableClient *network.HubRouteTablesClient @@ -79,6 +80,9 @@ func NewClient(o *common.ClientOptions) *Client { ExpressRouteCircuitsClient := network.NewExpressRouteCircuitsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&ExpressRouteCircuitsClient.Client, o.ResourceManagerAuthorizer) + ExpressRouteCircuitConnectionClient := network.NewExpressRouteCircuitConnectionsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&ExpressRouteCircuitConnectionClient.Client, o.ResourceManagerAuthorizer) + ExpressRouteGatewaysClient := network.NewExpressRouteGatewaysClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&ExpressRouteGatewaysClient.Client, o.ResourceManagerAuthorizer) @@ -213,6 +217,7 @@ func NewClient(o *common.ClientOptions) *Client { DDOSProtectionPlansClient: &DDOSProtectionPlansClient, ExpressRouteAuthsClient: &ExpressRouteAuthsClient, ExpressRouteCircuitsClient: &ExpressRouteCircuitsClient, + ExpressRouteCircuitConnectionClient: &ExpressRouteCircuitConnectionClient, ExpressRouteGatewaysClient: &ExpressRouteGatewaysClient, ExpressRoutePeeringsClient: &ExpressRoutePeeringsClient, HubRouteTableClient: &HubRouteTableClient, diff --git a/azurerm/internal/services/network/express_route_circuit_connections_data_source.go b/azurerm/internal/services/network/express_route_circuit_connections_data_source.go new file mode 100644 index 000000000000..ad69586cdba1 --- /dev/null +++ b/azurerm/internal/services/network/express_route_circuit_connections_data_source.go @@ -0,0 +1,78 @@ +package network + +import ( + "fmt" + "time" + + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-05-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/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) +func dataSourceExpressRouteCircuitConnection() *schema.Resource { + return &schema.Resource{ + Read: dataSourceExpressRouteCircuitConnectionRead, + + Timeouts: &schema.ResourceTimeout{ + Read: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), + + "circuit_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "peering_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(network.AzurePrivatePeering), + string(network.AzurePublicPeering), + string(network.MicrosoftPeering), + }, false), + }, + }, + } +} + +func dataSourceExpressRouteCircuitConnectionRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + circuitName := d.Get("circuit_name").(string) + peeringName := d.Get("peering_name").(string) + + resp, err :=client.Get(ctx, resourceGroup, circuitName, peeringName, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf(" ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q) does not exist", name, resourceGroup, circuitName, peeringName) + } + return fmt.Errorf("retrieving ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", name, resourceGroup, circuitName, peeringName, err) + } + if resp.ID == nil || *resp.ID== "" { + return fmt.Errorf("empty or nil ID returned for ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q) ID", name, resourceGroup, circuitName, peeringName) + } + + d.SetId(*resp.ID) + d.Set("name", name) + d.Set("resource_group_name", resourceGroup) + d.Set("circuit_name", circuitName) + d.Set("peering_name", peeringName) + return nil +} diff --git a/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go b/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go new file mode 100644 index 000000000000..6fb707931faf --- /dev/null +++ b/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go @@ -0,0 +1,61 @@ +package network_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" +) + +type ExpressRouteCircuitConnectionDataSource struct{} + +var config = ` +provider "azurerm" { + features {} +} + +data "azurerm_express_route_circuit_connection" "example" { + name = "xz-test-conn" + resource_group_name = "xz3-test" + circuit_name = "tf-er" + peering_name = "AzurePrivatePeering" +} +` +func TestAccExpressRouteCircuitConnectionDataSource_ddd(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_express_route_circuit_connection", "test") + + data.DataSourceTest(t, []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + + ), + }, + }) +} + +func TestAccExpressRouteCircuitConnectionDataSource_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_express_route_circuit_connection", "test") + r := ExpressRouteCircuitConnectionDataSource{} + data.DataSourceTest(t, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + + ), + }, + }) +} +func(ExpressRouteCircuitConnectionDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_express_route_circuit_connection" "test" { + name = azurerm_express_route_circuit_connection.test.name + resource_group_name = azurerm_express_route_circuit_connection.test.resource_group_name + circuit_name = azurerm_express_route_circuit_connection.test.circuit_name + peering_name = azurerm_express_route_circuit_connection.test.peering_name +} +`, ExpressRouteCircuitConnectionResource{}.basic(data)) +} diff --git a/azurerm/internal/services/network/express_route_circuit_connections_resource.go b/azurerm/internal/services/network/express_route_circuit_connections_resource.go new file mode 100644 index 000000000000..a7e21ea4f08a --- /dev/null +++ b/azurerm/internal/services/network/express_route_circuit_connections_resource.go @@ -0,0 +1,251 @@ +package network + +import ( + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-05-01/network" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "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" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" + azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceExpressRouteCircuitConnection() *schema.Resource { + return &schema.Resource{ + Create: resourceExpressRouteCircuitConnectionCreateUpdate, + Read: resourceExpressRouteCircuitConnectionRead, + Update: resourceExpressRouteCircuitConnectionCreateUpdate, + Delete: resourceExpressRouteCircuitConnectionDelete, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + _, err := parse.ExpressRouteCircuitConnectionID(id) + return err + }), + + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + + "circuit_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "peering_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + string(network.AzurePrivatePeering), + string(network.AzurePublicPeering), + string(network.MicrosoftPeering), + }, false), + }, + + "peering_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: azure.ValidateResourceID, + }, + + "peer_peering_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: azure.ValidateResourceID, + }, + + "address_prefix": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsCIDR, + }, + + "authorization_key": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + }, + + "ipv6circuit_connection_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address_prefix": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsCIDR, + }, + + "circuit_connection_status": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} +func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, meta interface{}) error { + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + circuitName := d.Get("circuit_name").(string) + peeringName := d.Get("peering_name").(string) + + id := parse.NewExpressRouteCircuitConnectionID(subscriptionId, resourceGroup, circuitName, peeringName, name).ID() + + if d.IsNewResource() { + existing, err := client.Get(ctx, resourceGroup, circuitName, peeringName, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for existing ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", name, resourceGroup, circuitName, peeringName, err) + } + } + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_express_route_circuit_connection", id) + } + } + + expressRouteCircuitConnectionParameters := network.ExpressRouteCircuitConnection{ + Name: utils.String(d.Get("name").(string)), + ExpressRouteCircuitConnectionPropertiesFormat: &network.ExpressRouteCircuitConnectionPropertiesFormat{ + AddressPrefix: utils.String(d.Get("address_prefix").(string)), + AuthorizationKey: utils.String(d.Get("authorization_key").(string)), + ExpressRouteCircuitPeering: &network.SubResource{ + ID: utils.String(d.Get("peering_id").(string)), + }, + PeerExpressRouteCircuitPeering: &network.SubResource{ + ID: utils.String(d.Get("peer_peering_id").(string)), + }, + Ipv6CircuitConnectionConfig: expandExpressRouteCircuitConnectionIpv6CircuitConnectionConfig(d.Get("ipv6circuit_connection_config").([]interface{})), + }, + } + future, err := client.CreateOrUpdate(ctx, resourceGroup, circuitName, peeringName, name, expressRouteCircuitConnectionParameters) + if err != nil { + return fmt.Errorf("creating/updating ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", name, resourceGroup, circuitName, peeringName, err) + } + + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for creation/update of the ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", name, resourceGroup, circuitName, peeringName, err) + } + + d.SetId(id) + return resourceExpressRouteCircuitConnectionRead(d, meta) +} + +func resourceExpressRouteCircuitConnectionRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ExpressRouteCircuitConnectionID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.CircuitName, id.PeeringName, id.Name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] express route circuit connection %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("retrieving ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", id.Name, id.ResourceGroup, id.CircuitName, id.PeeringName, err) + } + d.Set("name", id.Name) + d.Set("resource_group_name", id.ResourceGroup) + d.Set("circuit_name", id.CircuitName) + d.Set("peering_name", id.PeeringName) + d.Set("peering_id", resp.ExpressRouteCircuitPeering.ID) + d.Set("peer_peering_id", resp.PeerExpressRouteCircuitPeering.ID) + if props := resp.ExpressRouteCircuitConnectionPropertiesFormat; props != nil { + d.Set("address_prefix", props.AddressPrefix) + d.Set("authorization_key", props.AuthorizationKey) + if err := d.Set("ipv6circuit_connection_config", flattenExpressRouteCircuitConnectionIpv6CircuitConnectionConfig(props.Ipv6CircuitConnectionConfig)); err != nil { + return fmt.Errorf("setting `ipv6circuit_connection_config`: %+v", err) + } + } + return nil +} + +func resourceExpressRouteCircuitConnectionDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ExpressRouteCircuitConnectionID(d.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.ResourceGroup, id.CircuitName, id.PeeringName, id.Name) + if err != nil { + return fmt.Errorf("deleting ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", id.Name, id.ResourceGroup, id.CircuitName, id.PeeringName, err) + } + + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for deletion of the ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", id.Name, id.ResourceGroup, id.CircuitName, id.PeeringName, err) + } + return nil +} + +func expandExpressRouteCircuitConnectionIpv6CircuitConnectionConfig(input []interface{}) *network.Ipv6CircuitConnectionConfig { + if len(input) == 0 { + return nil + } + v := input[0].(map[string]interface{}) + return &network.Ipv6CircuitConnectionConfig{ + AddressPrefix: utils.String(v["address_prefix"].(string)), + } +} + +func flattenExpressRouteCircuitConnectionIpv6CircuitConnectionConfig(input *network.Ipv6CircuitConnectionConfig) []interface{} { + if input == nil { + return make([]interface{}, 0) + } + + var addressPrefix string + if input.AddressPrefix != nil { + addressPrefix = *input.AddressPrefix + } + var circuitConnectionStatus network.CircuitConnectionStatus + if input.CircuitConnectionStatus != "" { + circuitConnectionStatus = input.CircuitConnectionStatus + } + return []interface{}{ + map[string]interface{}{ + "address_prefix": addressPrefix, + "circuit_connection_status": circuitConnectionStatus, + }, + } +} diff --git a/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go b/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go new file mode 100644 index 000000000000..7918ab0196ff --- /dev/null +++ b/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go @@ -0,0 +1,214 @@ +package network_test + +import ( + "context" + "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/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +type ExpressRouteCircuitConnectionResource struct{} + +func TestAccExpressRouteCircuitConnection_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") + r := ExpressRouteCircuitConnectionResource{} + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccExpressRouteCircuitConnection_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") + r := ExpressRouteCircuitConnectionResource{} + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccExpressRouteCircuitConnection_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") + r := ExpressRouteCircuitConnectionResource{} + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.complete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccExpressRouteCircuitConnection_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") + r := ExpressRouteCircuitConnectionResource{} + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.complete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccExpressRouteCircuitConnection_updateIpv6CircuitConnectionConfig(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") + r := ExpressRouteCircuitConnectionResource{} + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.complete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.updateIpv6CircuitConnectionConfig(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (r ExpressRouteCircuitConnectionResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) { + id, err := parse.ExpressRouteCircuitConnectionID(state.ID) + if err != nil { + return nil, err + } + resp, err := client.Network.ExpressRouteCircuitConnectionClient.Get(ctx, id.ResourceGroup, id.CircuitName, id.PeeringName, id.Name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", id.Name, id.ResourceGroup, id.CircuitName, id.PeeringName, err) + } + return utils.Bool(true), nil +} + +func (r ExpressRouteCircuitConnectionResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctest-network-%d" + location = "%s" +} + +resource "azurerm_express_route_circuit" "test" { + name = "acctest-nerc-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location +} + +resource "azurerm_express_route_circuit_peering" "test" { + name = "acctest-nercp-%d" + resource_group_name = azurerm_resource_group.test.name + circuit_name = azurerm_express_route_circuit.test.name +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func (r ExpressRouteCircuitConnectionResource) basic(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_express_route_circuit_connection" "test" { + name = "acctest-nercc-%d" + resource_group_name = azurerm_resource_group.test.name + circuit_name = azurerm_express_route_circuit.test.name + peering_name = azurerm_express_route_circuit_peering.test.name +} +`, template, data.RandomInteger) +} + +func (r ExpressRouteCircuitConnectionResource) requiresImport(data acceptance.TestData) string { + config := r.basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_express_route_circuit_connection" "import" { + name = azurerm_express_route_circuit_connection.test.name + resource_group_name = azurerm_express_route_circuit_connection.test.resource_group_name + circuit_name = azurerm_express_route_circuit_connection.test.circuit_name + peering_name = azurerm_express_route_circuit_connection.test.peering_name +} +`, config) +} + +func (r ExpressRouteCircuitConnectionResource) complete(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_express_route_circuit_connection" "test" { + name = "acctest-nercc-%d" + resource_group_name = azurerm_resource_group.test.name + circuit_name = azurerm_express_route_circuit.test.name + peering_name = azurerm_express_route_circuit_peering.test.name + address_prefix = "10.0.0.0/29" + authorization_key = "946a1918-b7a2-4917-b43c-8c4cdaee006a" + ipv6circuit_connection_config { + address_prefix = "aa:bb::/125" + } +} +`, template, data.RandomInteger) +} + +func (r ExpressRouteCircuitConnectionResource) updateIpv6CircuitConnectionConfig(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_express_route_circuit_connection" "test" { + name = "acctest-nercc-%d" + resource_group_name = azurerm_resource_group.test.name + circuit_name = azurerm_express_route_circuit.test.name + peering_name = azurerm_express_route_circuit_peering.test.name + address_prefix = "10.0.0.0/29" + authorization_key = "946a1918-b7a2-4917-b43c-8c4cdaee006a" + ipv6circuit_connection_config { + address_prefix = "aa:bb::/125" + } +} +`, template, data.RandomInteger) +} diff --git a/azurerm/internal/services/network/parse/network_express_route_circuit_connection.go b/azurerm/internal/services/network/parse/network_express_route_circuit_connection.go new file mode 100644 index 000000000000..02536e9598dc --- /dev/null +++ b/azurerm/internal/services/network/parse/network_express_route_circuit_connection.go @@ -0,0 +1,56 @@ +package parse + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type NetworkExpressRouteCircuitConnectionId struct { + SubscriptionId string + ResourceGroup string + CircuitName string + PeeringName string + Name string +} + +func NewExpressRouteCircuitConnectionID(subscriptionId string, resourcegroup string, circuitname string, peeringname string, name string) NetworkExpressRouteCircuitConnectionId { + return NetworkExpressRouteCircuitConnectionId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourcegroup, + CircuitName: circuitname, + PeeringName: peeringname, + Name: name, + } +} + +func (id NetworkExpressRouteCircuitConnectionId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/expressRouteCircuits/%s/peerings/%s/connections/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.CircuitName, id.PeeringName, id.Name) +} + +func ExpressRouteCircuitConnectionID(input string) (*NetworkExpressRouteCircuitConnectionId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, fmt.Errorf("parsing networkExpressRouteCircuitConnection ID %q: %+v", input, err) + } + + networkExpressRouteCircuitConnection := NetworkExpressRouteCircuitConnectionId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + if networkExpressRouteCircuitConnection.CircuitName, err = id.PopSegment("expressRouteCircuits"); err != nil { + return nil, err + } + if networkExpressRouteCircuitConnection.PeeringName, err = id.PopSegment("peerings"); err != nil { + return nil, err + } + if networkExpressRouteCircuitConnection.Name, err = id.PopSegment("connections"); err != nil { + return nil, err + } + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &networkExpressRouteCircuitConnection, nil +} diff --git a/azurerm/internal/services/network/parse/network_express_route_circuit_connection_test.go b/azurerm/internal/services/network/parse/network_express_route_circuit_connection_test.go new file mode 100644 index 000000000000..49feaae22613 --- /dev/null +++ b/azurerm/internal/services/network/parse/network_express_route_circuit_connection_test.go @@ -0,0 +1,128 @@ +package parse + +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) + +var _ resourceid.Formatter = NetworkExpressRouteCircuitConnectionId{} +func TestNetworkExpressRouteCircuitConnectionIDFormatter(t *testing.T) { + actual := NewExpressRouteCircuitConnectionID("12345678-1234-9876-4563-123456789012", "resourceGroup1", "circuit1", "peering1", "connection1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/connection1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestNetworkExpressRouteCircuitConnectionID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *NetworkExpressRouteCircuitConnectionId + }{ + { + // empty + Input: "", + Error: true, + }, + { + // missing subscriptions + Input: "/", + Error: true, + }, + { + // missing value for subscriptions + Input: "/subscriptions/", + Error: true, + }, + { + // missing resourceGroups + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + { + // missing value for resourceGroups + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + { + // missing expressRouteCircuits + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/", + Error: true, + }, + { + // missing value for expressRouteCircuits + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/", + Error: true, + }, + { + // missing peerings + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/", + Error: true, + }, + { + // missing value for peerings + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/", + Error: true, + }, + { + // missing connections + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/", + Error: true, + }, + { + // missing value for connections + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/", + Error: true, + }, + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/connection1", + Expected: &NetworkExpressRouteCircuitConnectionId{ + SubscriptionId:"12345678-1234-9876-4563-123456789012", + ResourceGroup:"resourceGroup1", + CircuitName:"circuit1", + PeeringName:"peering1", + Name:"connection1", + }, + }, + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.NETWORK/EXPRESSROUTECIRCUITS/CIRCUIT1/PEERINGS/PEERING1/CONNECTIONS/CONNECTION1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := ExpressRouteCircuitConnectionID(v.Input) + if err != nil { + if v.Error { + continue + } + t.Fatalf("Expected a value but got an error: %s", err) + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + + if actual.CircuitName != v.Expected.CircuitName { + t.Fatalf("Expected %q but got %q for CircuitName", v.Expected.CircuitName, actual.CircuitName) + } + + if actual.PeeringName != v.Expected.PeeringName { + t.Fatalf("Expected %q but got %q for PeeringName", v.Expected.PeeringName, actual.PeeringName) + } + + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + } +} diff --git a/azurerm/internal/services/network/registration.go b/azurerm/internal/services/network/registration.go index aeb443d9a9ee..3d15483c6feb 100644 --- a/azurerm/internal/services/network/registration.go +++ b/azurerm/internal/services/network/registration.go @@ -24,6 +24,7 @@ func (r Registration) SupportedDataSources() map[string]*schema.Resource { "azurerm_application_gateway": dataSourceApplicationGateway(), "azurerm_application_security_group": dataSourceApplicationSecurityGroup(), "azurerm_express_route_circuit": dataSourceExpressRouteCircuit(), + "azurerm_express_route_circuit_connection": dataSourceExpressRouteCircuitConnection(), "azurerm_ip_group": dataSourceIpGroup(), "azurerm_nat_gateway": dataSourceNatGateway(), "azurerm_network_ddos_protection_plan": dataSourceNetworkDDoSProtectionPlan(), @@ -55,6 +56,7 @@ func (r Registration) SupportedResources() map[string]*schema.Resource { "azurerm_application_gateway": resourceApplicationGateway(), "azurerm_application_security_group": resourceApplicationSecurityGroup(), "azurerm_bastion_host": resourceBastionHost(), + "azurerm_express_route_circuit_connection": resourceExpressRouteCircuitConnection(), "azurerm_express_route_circuit_authorization": resourceExpressRouteCircuitAuthorization(), "azurerm_express_route_circuit_peering": resourceExpressRouteCircuitPeering(), "azurerm_express_route_circuit": resourceExpressRouteCircuit(), diff --git a/website/docs/d/network_express_route_circuit_connections.html.markdown b/website/docs/d/network_express_route_circuit_connections.html.markdown new file mode 100644 index 000000000000..64b9e3bc61fc --- /dev/null +++ b/website/docs/d/network_express_route_circuit_connections.html.markdown @@ -0,0 +1,50 @@ +--- +subcategory: "Network" +layout: "azurerm" +page_title: "Azure Resource Manager: Data Source: azurerm_express_route_circuit_connection" +description: |- + Gets information about an existing network ExpressRouteCircuitConnection. +--- + +# Data Source: azurerm_express_route_circuit_connection + +Use this data source to access information about an existing network ExpressRouteCircuitConnection. + +## Example Usage + +```hcl +data "azurerm_express_route_circuit_connection" "example" { + name = "example-expressroutecircuitconnection" + resource_group_name = "existing" + circuit_name = "existing" + peering_name = "existing" +} + +output "id" { + value = data.azurerm_express_route_circuit_connection.example.id +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) The name of this network ExpressRouteCircuitConnection. + +* `resource_group_name` - (Required) The name of the Resource Group where the network ExpressRouteCircuitConnection exists. + +* `circuit_name` - (Required) The name of the express route circuit. + +* `peering_name` - (Required) The name of the peering. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the network ExpressRouteCircuitConnection. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `read` - (Defaults to 5 minutes) Used when retrieving the network ExpressRouteCircuitConnection. \ No newline at end of file diff --git a/website/docs/r/network_express_route_circuit_connections.html.markdown b/website/docs/r/network_express_route_circuit_connections.html.markdown new file mode 100644 index 000000000000..0deb60120cc1 --- /dev/null +++ b/website/docs/r/network_express_route_circuit_connections.html.markdown @@ -0,0 +1,97 @@ +--- +subcategory: "Network" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_express_route_circuit_connection" +description: |- + Manages a network ExpressRouteCircuitConnection. +--- + +# azurerm_express_route_circuit_connection + +Manages a network ExpressRouteCircuitConnection. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-network" + location = "West Europe" +} + +resource "azurerm_express_route_port" "example" { + name = "example-expressrouteport" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location +} + +resource "azurerm_express_route_circuit" "example" { + name = "example-expressroutecircuit" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location +} + +resource "azurerm_express_route_circuit_peering" "example" { + name = "example-expressroutecircuitpeering" + resource_group_name = azurerm_resource_group.example.name + circuit_name = azurerm_express_route_circuit.example.name +} + +resource "azurerm_express_route_circuit_connection" "example" { + name = "example-expressroutecircuitconnection" + resource_group_name = azurerm_resource_group.example.name + circuit_name = azurerm_express_route_circuit.example.name + peering_name = azurerm_express_route_circuit_peering.example.name +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) The name which should be used for this network ExpressRouteCircuitConnection. Changing this forces a new network ExpressRouteCircuitConnection to be created. + +* `resource_group_name` - (Required) The name of the Resource Group where the network ExpressRouteCircuitConnection should exist. Changing this forces a new network ExpressRouteCircuitConnection to be created. + +* `circuit_name` - (Required) The name of the express route circuit. Changing this forces a new network ExpressRouteCircuitConnection to be created. + +* `peering_name` - (Required) The name of the peering. Changing this forces a new network ExpressRouteCircuitConnection to be created. + +--- + +* `address_prefix` - (Optional) /29 IP address space to carve out Customer addresses for tunnels. + +* `authorization_key` - (Optional) The authorization key. + +* `ipv6circuit_connection_config` - (Optional) A `ipv6circuit_connection_config` block as defined below. + +--- + +An `ipv6circuit_connection_config` block exports the following: + +* `address_prefix` - (Optional) /125 IP address space to carve out customer addresses for global reach. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the network ExpressRouteCircuitConnection. + +* `circuit_connection_status` - Express Route Circuit connection state. + +* `type` - Type of the resource. + +## 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 network ExpressRouteCircuitConnection. +* `read` - (Defaults to 5 minutes) Used when retrieving the network ExpressRouteCircuitConnection. +* `delete` - (Defaults to 30 minutes) Used when deleting the network ExpressRouteCircuitConnection. + +## Import + +network ExpressRouteCircuitConnections can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_express_route_circuit_connection.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/connection1 +``` \ No newline at end of file From f18a7014bf7ed59009c9265137b28593df47e447 Mon Sep 17 00:00:00 2001 From: xuzhang3 Date: Mon, 12 Apr 2021 16:55:58 +0800 Subject: [PATCH 02/28] new resource express route circuit connection --- ...s_route_circuit_connections_data_source.go | 121 +++---- ...te_circuit_connections_data_source_test.go | 62 ++-- ...ress_route_circuit_connections_resource.go | 9 +- ...route_circuit_connections_resource_test.go | 330 ++++++++++-------- ...ess_route_circuit_peering_resource_test.go | 4 +- .../parse/express_route_circuit_connection.go | 56 +++ .../express_route_circuit_connection_test.go | 129 +++++++ ...etwork_express_route_circuit_connection.go | 56 --- ...k_express_route_circuit_connection_test.go | 128 ------- ...s_route_circuit_connections.html.markdown} | 0 ...s_route_circuit_connections.html.markdown} | 98 +++++- 11 files changed, 553 insertions(+), 440 deletions(-) create mode 100644 azurerm/internal/services/network/parse/express_route_circuit_connection.go create mode 100644 azurerm/internal/services/network/parse/express_route_circuit_connection_test.go delete mode 100644 azurerm/internal/services/network/parse/network_express_route_circuit_connection.go delete mode 100644 azurerm/internal/services/network/parse/network_express_route_circuit_connection_test.go rename website/docs/d/{network_express_route_circuit_connections.html.markdown => express_route_circuit_connections.html.markdown} (100%) rename website/docs/r/{network_express_route_circuit_connections.html.markdown => express_route_circuit_connections.html.markdown} (52%) diff --git a/azurerm/internal/services/network/express_route_circuit_connections_data_source.go b/azurerm/internal/services/network/express_route_circuit_connections_data_source.go index ad69586cdba1..a976549aa0a3 100644 --- a/azurerm/internal/services/network/express_route_circuit_connections_data_source.go +++ b/azurerm/internal/services/network/express_route_circuit_connections_data_source.go @@ -1,78 +1,79 @@ package network import ( - "fmt" - "time" + "fmt" + "time" - "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-05-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/internal/clients" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-05-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/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) + func dataSourceExpressRouteCircuitConnection() *schema.Resource { - return &schema.Resource{ - Read: dataSourceExpressRouteCircuitConnectionRead, + return &schema.Resource{ + Read: dataSourceExpressRouteCircuitConnectionRead, - Timeouts: &schema.ResourceTimeout{ - Read: schema.DefaultTimeout(5 * time.Minute), - }, + Timeouts: &schema.ResourceTimeout{ + Read: schema.DefaultTimeout(5 * time.Minute), + }, - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringIsNotEmpty, - }, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, - "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), + "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), - "circuit_name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringIsNotEmpty, - }, + "circuit_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, - "peering_name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - string(network.AzurePrivatePeering), - string(network.AzurePublicPeering), - string(network.MicrosoftPeering), - }, false), - }, - }, - } + "peering_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(network.AzurePrivatePeering), + string(network.AzurePublicPeering), + string(network.MicrosoftPeering), + }, false), + }, + }, + } } func dataSourceExpressRouteCircuitConnectionRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient - ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) - defer cancel() + client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() - name := d.Get("name").(string) - resourceGroup := d.Get("resource_group_name").(string) - circuitName := d.Get("circuit_name").(string) - peeringName := d.Get("peering_name").(string) + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + circuitName := d.Get("circuit_name").(string) + peeringName := d.Get("peering_name").(string) - resp, err :=client.Get(ctx, resourceGroup, circuitName, peeringName, name) - if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf(" ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q) does not exist", name, resourceGroup, circuitName, peeringName) - } - return fmt.Errorf("retrieving ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", name, resourceGroup, circuitName, peeringName, err) - } - if resp.ID == nil || *resp.ID== "" { - return fmt.Errorf("empty or nil ID returned for ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q) ID", name, resourceGroup, circuitName, peeringName) - } + resp, err := client.Get(ctx, resourceGroup, circuitName, peeringName, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf(" ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q) does not exist", name, resourceGroup, circuitName, peeringName) + } + return fmt.Errorf("retrieving ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", name, resourceGroup, circuitName, peeringName, err) + } + if resp.ID == nil || *resp.ID == "" { + return fmt.Errorf("empty or nil ID returned for ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q) ID", name, resourceGroup, circuitName, peeringName) + } - d.SetId(*resp.ID) - d.Set("name", name) - d.Set("resource_group_name", resourceGroup) - d.Set("circuit_name", circuitName) - d.Set("peering_name", peeringName) - return nil + d.SetId(*resp.ID) + d.Set("name", name) + d.Set("resource_group_name", resourceGroup) + d.Set("circuit_name", circuitName) + d.Set("peering_name", peeringName) + return nil } diff --git a/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go b/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go index 6fb707931faf..b42f24436e7c 100644 --- a/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go @@ -1,54 +1,34 @@ package network_test import ( - "fmt" - "testing" + "fmt" + "os" + "testing" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" ) type ExpressRouteCircuitConnectionDataSource struct{} -var config = ` -provider "azurerm" { - features {} -} - -data "azurerm_express_route_circuit_connection" "example" { - name = "xz-test-conn" - resource_group_name = "xz3-test" - circuit_name = "tf-er" - peering_name = "AzurePrivatePeering" -} -` -func TestAccExpressRouteCircuitConnectionDataSource_ddd(t *testing.T) { - data := acceptance.BuildTestData(t, "data.azurerm_express_route_circuit_connection", "test") - - data.DataSourceTest(t, []resource.TestStep{ - { - Config: config, - Check: resource.ComposeTestCheckFunc( - - ), - }, - }) -} - func TestAccExpressRouteCircuitConnectionDataSource_basic(t *testing.T) { - data := acceptance.BuildTestData(t, "data.azurerm_express_route_circuit_connection", "test") - r := ExpressRouteCircuitConnectionDataSource{} - data.DataSourceTest(t, []resource.TestStep{ - { - Config: r.basic(data), - Check: resource.ComposeTestCheckFunc( - - ), - }, - }) + if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || + os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { + t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") + return + } + + data := acceptance.BuildTestData(t, "data.azurerm_express_route_circuit_connection", "test") + r := ExpressRouteCircuitConnectionDataSource{} + data.DataSourceTest(t, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc(), + }, + }) } -func(ExpressRouteCircuitConnectionDataSource) basic(data acceptance.TestData) string { - return fmt.Sprintf(` +func (ExpressRouteCircuitConnectionDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` %s data "azurerm_express_route_circuit_connection" "test" { diff --git a/azurerm/internal/services/network/express_route_circuit_connections_resource.go b/azurerm/internal/services/network/express_route_circuit_connections_resource.go index a7e21ea4f08a..0f4cb9c2aa8e 100644 --- a/azurerm/internal/services/network/express_route_circuit_connections_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connections_resource.go @@ -36,7 +36,6 @@ func resourceExpressRouteCircuitConnection() *schema.Resource { return err }), - Schema: map[string]*schema.Schema{ "name": { Type: schema.TypeString, @@ -139,8 +138,7 @@ func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, m expressRouteCircuitConnectionParameters := network.ExpressRouteCircuitConnection{ Name: utils.String(d.Get("name").(string)), ExpressRouteCircuitConnectionPropertiesFormat: &network.ExpressRouteCircuitConnectionPropertiesFormat{ - AddressPrefix: utils.String(d.Get("address_prefix").(string)), - AuthorizationKey: utils.String(d.Get("authorization_key").(string)), + AddressPrefix: utils.String(d.Get("address_prefix").(string)), ExpressRouteCircuitPeering: &network.SubResource{ ID: utils.String(d.Get("peering_id").(string)), }, @@ -150,6 +148,11 @@ func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, m Ipv6CircuitConnectionConfig: expandExpressRouteCircuitConnectionIpv6CircuitConnectionConfig(d.Get("ipv6circuit_connection_config").([]interface{})), }, } + + if v, ok := d.GetOk("authorization_key"); ok { + expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.AuthorizationKey = utils.String(v.(string)) + } + future, err := client.CreateOrUpdate(ctx, resourceGroup, circuitName, peeringName, name, expressRouteCircuitConnectionParameters) if err != nil { return fmt.Errorf("creating/updating ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", name, resourceGroup, circuitName, peeringName, err) diff --git a/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go b/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go index 7918ab0196ff..442990df2a90 100644 --- a/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go @@ -1,169 +1,214 @@ package network_test import ( - "context" - "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/internal/acceptance" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" + "context" + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) type ExpressRouteCircuitConnectionResource struct{} func TestAccExpressRouteCircuitConnection_basic(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") - r := ExpressRouteCircuitConnectionResource{} - data.ResourceTest(t, r, []resource.TestStep{ - { - Config: r.basic(data), - Check: resource.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - data.ImportStep(), - }) + if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || + os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { + t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") + return + } + + data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") + r := ExpressRouteCircuitConnectionResource{} + data.ResourceSequentialTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) } func TestAccExpressRouteCircuitConnection_requiresImport(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") - r := ExpressRouteCircuitConnectionResource{} - data.ResourceTest(t, r, []resource.TestStep{ - { - Config: r.basic(data), - Check: resource.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - data.RequiresImportErrorStep(r.requiresImport), - }) + if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || + os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { + t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") + return + } + + data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") + r := ExpressRouteCircuitConnectionResource{} + data.ResourceSequentialTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) } func TestAccExpressRouteCircuitConnection_complete(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") - r := ExpressRouteCircuitConnectionResource{} - data.ResourceTest(t, r, []resource.TestStep{ - { - Config: r.complete(data), - Check: resource.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - data.ImportStep(), - }) + if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || + os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { + t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") + return + } + + data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") + r := ExpressRouteCircuitConnectionResource{} + data.ResourceSequentialTest(t, r, []resource.TestStep{ + { + Config: r.complete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("authorization_key"), + }) } func TestAccExpressRouteCircuitConnection_update(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") - r := ExpressRouteCircuitConnectionResource{} - data.ResourceTest(t, r, []resource.TestStep{ - { - Config: r.basic(data), - Check: resource.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - data.ImportStep(), - { - Config: r.complete(data), - Check: resource.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - data.ImportStep(), - { - Config: r.basic(data), - Check: resource.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - data.ImportStep(), - }) + if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || + os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { + t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") + return + } + + data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") + r := ExpressRouteCircuitConnectionResource{} + data.ResourceSequentialTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.complete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("authorization_key"), + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("authorization_key"), + }) } func TestAccExpressRouteCircuitConnection_updateIpv6CircuitConnectionConfig(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") - r := ExpressRouteCircuitConnectionResource{} - data.ResourceTest(t, r, []resource.TestStep{ - { - Config: r.complete(data), - Check: resource.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - data.ImportStep(), - { - Config: r.updateIpv6CircuitConnectionConfig(data), - Check: resource.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - data.ImportStep(), - }) + if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || + os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { + t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") + return + } + + data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") + r := ExpressRouteCircuitConnectionResource{} + data.ResourceSequentialTest(t, r, []resource.TestStep{ + { + Config: r.complete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.updateIpv6CircuitConnectionConfig(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) } func (r ExpressRouteCircuitConnectionResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) { - id, err := parse.ExpressRouteCircuitConnectionID(state.ID) - if err != nil { - return nil, err - } - resp, err := client.Network.ExpressRouteCircuitConnectionClient.Get(ctx, id.ResourceGroup, id.CircuitName, id.PeeringName, id.Name) - if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - return utils.Bool(false), nil - } - return nil, fmt.Errorf("retrieving ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", id.Name, id.ResourceGroup, id.CircuitName, id.PeeringName, err) - } - return utils.Bool(true), nil + id, err := parse.ExpressRouteCircuitConnectionID(state.ID) + if err != nil { + return nil, err + } + resp, err := client.Network.ExpressRouteCircuitConnectionClient.Get(ctx, id.ResourceGroup, id.CircuitName, id.PeeringName, id.Name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", id.Name, id.ResourceGroup, id.CircuitName, id.PeeringName, err) + } + return utils.Bool(true), nil } func (r ExpressRouteCircuitConnectionResource) template(data acceptance.TestData) string { - return fmt.Sprintf(` + rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") + circuitName1 := os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") + circuitName2 := os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") + + return fmt.Sprintf(` provider "azurerm" { features {} } -resource "azurerm_resource_group" "test" { - name = "acctest-network-%d" - location = "%s" -} - -resource "azurerm_express_route_circuit" "test" { - name = "acctest-nerc-%d" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location +resource "azurerm_express_route_circuit_peering" "test" { + peering_type = "AzurePrivatePeering" + express_route_circuit_name = "%[1]s" + resource_group_name = "%[2]s" + shared_key = "SSSSsssssshhhhhItsASecret" + peer_asn = 100 + primary_peer_address_prefix = "192.168.1.0/30" + secondary_peer_address_prefix = "192.168.1.0/30" + vlan_id = 100 } -resource "azurerm_express_route_circuit_peering" "test" { - name = "acctest-nercp-%d" - resource_group_name = azurerm_resource_group.test.name - circuit_name = azurerm_express_route_circuit.test.name +resource "azurerm_express_route_circuit_peering" "peer_test" { + peering_type = "AzurePrivatePeering" + express_route_circuit_name = "%[3]s" + resource_group_name = "%[2]s" + shared_key = "SSSSsssssshhhhhItsASecret" + peer_asn = 100 + primary_peer_address_prefix = "192.168.1.0/30" + secondary_peer_address_prefix = "192.168.1.0/30" + vlan_id = 100 } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +`, circuitName1, rg, circuitName2) } func (r ExpressRouteCircuitConnectionResource) basic(data acceptance.TestData) string { - template := r.template(data) - return fmt.Sprintf(` + rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") + circuitName := os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") + template := r.template(data) + return fmt.Sprintf(` %s resource "azurerm_express_route_circuit_connection" "test" { name = "acctest-nercc-%d" - resource_group_name = azurerm_resource_group.test.name - circuit_name = azurerm_express_route_circuit.test.name - peering_name = azurerm_express_route_circuit_peering.test.name + resource_group_name = "%s" + circuit_name = "%s" + peering_name = azurerm_express_route_circuit_peering.test.peering_type + peering_id = azurerm_express_route_circuit_peering.test.id + peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id + address_prefix = "192.169.8.0/29" } -`, template, data.RandomInteger) +`, template, data.RandomInteger, rg, circuitName) } func (r ExpressRouteCircuitConnectionResource) requiresImport(data acceptance.TestData) string { - config := r.basic(data) - return fmt.Sprintf(` + config := r.basic(data) + return fmt.Sprintf(` %s resource "azurerm_express_route_circuit_connection" "import" { @@ -171,44 +216,57 @@ resource "azurerm_express_route_circuit_connection" "import" { resource_group_name = azurerm_express_route_circuit_connection.test.resource_group_name circuit_name = azurerm_express_route_circuit_connection.test.circuit_name peering_name = azurerm_express_route_circuit_connection.test.peering_name + peering_id = azurerm_express_route_circuit_peering.test.id + peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id + address_prefix = "192.169.8.0/29" } `, config) } func (r ExpressRouteCircuitConnectionResource) complete(data acceptance.TestData) string { - template := r.template(data) - return fmt.Sprintf(` + rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") + circuitName := os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") + + template := r.template(data) + return fmt.Sprintf(` %s resource "azurerm_express_route_circuit_connection" "test" { name = "acctest-nercc-%d" - resource_group_name = azurerm_resource_group.test.name - circuit_name = azurerm_express_route_circuit.test.name - peering_name = azurerm_express_route_circuit_peering.test.name - address_prefix = "10.0.0.0/29" + resource_group_name = "%s" + circuit_name = "%s" + peering_name = azurerm_express_route_circuit_peering.test.peering_type + peering_id = azurerm_express_route_circuit_peering.test.id + peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id + address_prefix = "192.169.8.0/29" authorization_key = "946a1918-b7a2-4917-b43c-8c4cdaee006a" ipv6circuit_connection_config { address_prefix = "aa:bb::/125" } } -`, template, data.RandomInteger) +`, template, data.RandomInteger, rg, circuitName) } func (r ExpressRouteCircuitConnectionResource) updateIpv6CircuitConnectionConfig(data acceptance.TestData) string { - template := r.template(data) - return fmt.Sprintf(` + rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") + circuitName := os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") + + template := r.template(data) + return fmt.Sprintf(` %s resource "azurerm_express_route_circuit_connection" "test" { name = "acctest-nercc-%d" - resource_group_name = azurerm_resource_group.test.name - circuit_name = azurerm_express_route_circuit.test.name - peering_name = azurerm_express_route_circuit_peering.test.name - address_prefix = "10.0.0.0/29" + resource_group_name = "%s" + circuit_name = "%s" + peering_name = azurerm_express_route_circuit_peering.test.peering_type + peering_id = azurerm_express_route_circuit_peering.test.id + peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id + address_prefix = "192.169.8.0/29" authorization_key = "946a1918-b7a2-4917-b43c-8c4cdaee006a" ipv6circuit_connection_config { address_prefix = "aa:bb::/125" } } -`, template, data.RandomInteger) +`, template, data.RandomInteger, rg, circuitName) } diff --git a/azurerm/internal/services/network/express_route_circuit_peering_resource_test.go b/azurerm/internal/services/network/express_route_circuit_peering_resource_test.go index 93fc503d0f34..00229f384bcb 100644 --- a/azurerm/internal/services/network/express_route_circuit_peering_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_peering_resource_test.go @@ -205,8 +205,8 @@ resource "azurerm_express_route_circuit" "test" { name = "acctest-erc-%d" location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name - service_provider_name = "Equinix" - peering_location = "Silicon Valley" + service_provider_name = "Equinix Test" + peering_location = "Area51" bandwidth_in_mbps = 50 sku { diff --git a/azurerm/internal/services/network/parse/express_route_circuit_connection.go b/azurerm/internal/services/network/parse/express_route_circuit_connection.go new file mode 100644 index 000000000000..7b68183f3373 --- /dev/null +++ b/azurerm/internal/services/network/parse/express_route_circuit_connection.go @@ -0,0 +1,56 @@ +package parse + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type NetworkExpressRouteCircuitConnectionId struct { + SubscriptionId string + ResourceGroup string + CircuitName string + PeeringName string + Name string +} + +func NewExpressRouteCircuitConnectionID(subscriptionId string, resourcegroup string, circuitname string, peeringname string, name string) NetworkExpressRouteCircuitConnectionId { + return NetworkExpressRouteCircuitConnectionId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourcegroup, + CircuitName: circuitname, + PeeringName: peeringname, + Name: name, + } +} + +func (id NetworkExpressRouteCircuitConnectionId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/expressRouteCircuits/%s/peerings/%s/connections/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.CircuitName, id.PeeringName, id.Name) +} + +func ExpressRouteCircuitConnectionID(input string) (*NetworkExpressRouteCircuitConnectionId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, fmt.Errorf("parsing networkExpressRouteCircuitConnection ID %q: %+v", input, err) + } + + networkExpressRouteCircuitConnection := NetworkExpressRouteCircuitConnectionId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + if networkExpressRouteCircuitConnection.CircuitName, err = id.PopSegment("expressRouteCircuits"); err != nil { + return nil, err + } + if networkExpressRouteCircuitConnection.PeeringName, err = id.PopSegment("peerings"); err != nil { + return nil, err + } + if networkExpressRouteCircuitConnection.Name, err = id.PopSegment("connections"); err != nil { + return nil, err + } + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &networkExpressRouteCircuitConnection, nil +} diff --git a/azurerm/internal/services/network/parse/express_route_circuit_connection_test.go b/azurerm/internal/services/network/parse/express_route_circuit_connection_test.go new file mode 100644 index 000000000000..dab7582bcc91 --- /dev/null +++ b/azurerm/internal/services/network/parse/express_route_circuit_connection_test.go @@ -0,0 +1,129 @@ +package parse + +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) + +var _ resourceid.Formatter = NetworkExpressRouteCircuitConnectionId{} + +func TestNetworkExpressRouteCircuitConnectionIDFormatter(t *testing.T) { + actual := NewExpressRouteCircuitConnectionID("12345678-1234-9876-4563-123456789012", "resourceGroup1", "circuit1", "peering1", "connection1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/connection1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestNetworkExpressRouteCircuitConnectionID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *NetworkExpressRouteCircuitConnectionId + }{ + { + // empty + Input: "", + Error: true, + }, + { + // missing subscriptions + Input: "/", + Error: true, + }, + { + // missing value for subscriptions + Input: "/subscriptions/", + Error: true, + }, + { + // missing resourceGroups + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + { + // missing value for resourceGroups + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + { + // missing expressRouteCircuits + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/", + Error: true, + }, + { + // missing value for expressRouteCircuits + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/", + Error: true, + }, + { + // missing peerings + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/", + Error: true, + }, + { + // missing value for peerings + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/", + Error: true, + }, + { + // missing connections + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/", + Error: true, + }, + { + // missing value for connections + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/", + Error: true, + }, + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/connection1", + Expected: &NetworkExpressRouteCircuitConnectionId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resourceGroup1", + CircuitName: "circuit1", + PeeringName: "peering1", + Name: "connection1", + }, + }, + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.NETWORK/EXPRESSROUTECIRCUITS/CIRCUIT1/PEERINGS/PEERING1/CONNECTIONS/CONNECTION1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := ExpressRouteCircuitConnectionID(v.Input) + if err != nil { + if v.Error { + continue + } + t.Fatalf("Expected a value but got an error: %s", err) + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + + if actual.CircuitName != v.Expected.CircuitName { + t.Fatalf("Expected %q but got %q for CircuitName", v.Expected.CircuitName, actual.CircuitName) + } + + if actual.PeeringName != v.Expected.PeeringName { + t.Fatalf("Expected %q but got %q for PeeringName", v.Expected.PeeringName, actual.PeeringName) + } + + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + } +} diff --git a/azurerm/internal/services/network/parse/network_express_route_circuit_connection.go b/azurerm/internal/services/network/parse/network_express_route_circuit_connection.go deleted file mode 100644 index 02536e9598dc..000000000000 --- a/azurerm/internal/services/network/parse/network_express_route_circuit_connection.go +++ /dev/null @@ -1,56 +0,0 @@ -package parse - -import ( - "fmt" - - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" -) - -type NetworkExpressRouteCircuitConnectionId struct { - SubscriptionId string - ResourceGroup string - CircuitName string - PeeringName string - Name string -} - -func NewExpressRouteCircuitConnectionID(subscriptionId string, resourcegroup string, circuitname string, peeringname string, name string) NetworkExpressRouteCircuitConnectionId { - return NetworkExpressRouteCircuitConnectionId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourcegroup, - CircuitName: circuitname, - PeeringName: peeringname, - Name: name, - } -} - -func (id NetworkExpressRouteCircuitConnectionId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/expressRouteCircuits/%s/peerings/%s/connections/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.CircuitName, id.PeeringName, id.Name) -} - -func ExpressRouteCircuitConnectionID(input string) (*NetworkExpressRouteCircuitConnectionId, error) { - id, err := azure.ParseAzureResourceID(input) - if err != nil { - return nil, fmt.Errorf("parsing networkExpressRouteCircuitConnection ID %q: %+v", input, err) - } - - networkExpressRouteCircuitConnection := NetworkExpressRouteCircuitConnectionId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - if networkExpressRouteCircuitConnection.CircuitName, err = id.PopSegment("expressRouteCircuits"); err != nil { - return nil, err - } - if networkExpressRouteCircuitConnection.PeeringName, err = id.PopSegment("peerings"); err != nil { - return nil, err - } - if networkExpressRouteCircuitConnection.Name, err = id.PopSegment("connections"); err != nil { - return nil, err - } - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &networkExpressRouteCircuitConnection, nil -} diff --git a/azurerm/internal/services/network/parse/network_express_route_circuit_connection_test.go b/azurerm/internal/services/network/parse/network_express_route_circuit_connection_test.go deleted file mode 100644 index 49feaae22613..000000000000 --- a/azurerm/internal/services/network/parse/network_express_route_circuit_connection_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package parse - -import ( - "testing" - - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" -) - -var _ resourceid.Formatter = NetworkExpressRouteCircuitConnectionId{} -func TestNetworkExpressRouteCircuitConnectionIDFormatter(t *testing.T) { - actual := NewExpressRouteCircuitConnectionID("12345678-1234-9876-4563-123456789012", "resourceGroup1", "circuit1", "peering1", "connection1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/connection1" - if actual != expected { - t.Fatalf("Expected %q but got %q", expected, actual) - } -} - -func TestNetworkExpressRouteCircuitConnectionID(t *testing.T) { - testData := []struct { - Input string - Error bool - Expected *NetworkExpressRouteCircuitConnectionId - }{ - { - // empty - Input: "", - Error: true, - }, - { - // missing subscriptions - Input: "/", - Error: true, - }, - { - // missing value for subscriptions - Input: "/subscriptions/", - Error: true, - }, - { - // missing resourceGroups - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", - Error: true, - }, - { - // missing value for resourceGroups - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", - Error: true, - }, - { - // missing expressRouteCircuits - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/", - Error: true, - }, - { - // missing value for expressRouteCircuits - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/", - Error: true, - }, - { - // missing peerings - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/", - Error: true, - }, - { - // missing value for peerings - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/", - Error: true, - }, - { - // missing connections - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/", - Error: true, - }, - { - // missing value for connections - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/", - Error: true, - }, - { - // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/connection1", - Expected: &NetworkExpressRouteCircuitConnectionId{ - SubscriptionId:"12345678-1234-9876-4563-123456789012", - ResourceGroup:"resourceGroup1", - CircuitName:"circuit1", - PeeringName:"peering1", - Name:"connection1", - }, - }, - { - // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.NETWORK/EXPRESSROUTECIRCUITS/CIRCUIT1/PEERINGS/PEERING1/CONNECTIONS/CONNECTION1", - Error: true, - }, - } - - for _, v := range testData { - t.Logf("[DEBUG] Testing %q", v.Input) - - actual, err := ExpressRouteCircuitConnectionID(v.Input) - if err != nil { - if v.Error { - continue - } - t.Fatalf("Expected a value but got an error: %s", err) - } - - if actual.SubscriptionId != v.Expected.SubscriptionId { - t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) - } - - if actual.ResourceGroup != v.Expected.ResourceGroup { - t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) - } - - if actual.CircuitName != v.Expected.CircuitName { - t.Fatalf("Expected %q but got %q for CircuitName", v.Expected.CircuitName, actual.CircuitName) - } - - if actual.PeeringName != v.Expected.PeeringName { - t.Fatalf("Expected %q but got %q for PeeringName", v.Expected.PeeringName, actual.PeeringName) - } - - if actual.Name != v.Expected.Name { - t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) - } - } -} diff --git a/website/docs/d/network_express_route_circuit_connections.html.markdown b/website/docs/d/express_route_circuit_connections.html.markdown similarity index 100% rename from website/docs/d/network_express_route_circuit_connections.html.markdown rename to website/docs/d/express_route_circuit_connections.html.markdown diff --git a/website/docs/r/network_express_route_circuit_connections.html.markdown b/website/docs/r/express_route_circuit_connections.html.markdown similarity index 52% rename from website/docs/r/network_express_route_circuit_connections.html.markdown rename to website/docs/r/express_route_circuit_connections.html.markdown index 0deb60120cc1..1b74e76b4bc7 100644 --- a/website/docs/r/network_express_route_circuit_connections.html.markdown +++ b/website/docs/r/express_route_circuit_connections.html.markdown @@ -18,22 +18,89 @@ resource "azurerm_resource_group" "example" { location = "West Europe" } -resource "azurerm_express_route_port" "example" { - name = "example-expressrouteport" - resource_group_name = azurerm_resource_group.example.name - location = azurerm_resource_group.example.location +resource "azurerm_express_route_circuit" "example1" { + name = "expressRoute1" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + service_provider_name = "Equinix" + peering_location = "Silicon Valley" + bandwidth_in_mbps = 50 + + sku { + tier = "Standard" + family = "MeteredData" + } + + allow_classic_operations = false + + tags = { + environment = "Production" + } } -resource "azurerm_express_route_circuit" "example" { - name = "example-expressroutecircuit" - resource_group_name = azurerm_resource_group.example.name - location = azurerm_resource_group.example.location +resource "azurerm_express_route_circuit" "example2" { + name = "expressRoute2" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + service_provider_name = "Equinix" + peering_location = "Silicon Valley" + bandwidth_in_mbps = 50 + + sku { + tier = "Standard" + family = "MeteredData" + } + + allow_classic_operations = false + + tags = { + environment = "Production" + } } -resource "azurerm_express_route_circuit_peering" "example" { - name = "example-expressroutecircuitpeering" - resource_group_name = azurerm_resource_group.example.name - circuit_name = azurerm_express_route_circuit.example.name +resource "azurerm_express_route_circuit_peering" "example1" { + peering_type = "MicrosoftPeering" + express_route_circuit_name = azurerm_express_route_circuit.example.name + resource_group_name = azurerm_resource_group.example.name + peer_asn = 100 + primary_peer_address_prefix = "123.0.0.0/30" + secondary_peer_address_prefix = "123.0.0.4/30" + vlan_id = 300 + + microsoft_peering_config { + advertised_public_prefixes = ["123.1.0.0/24"] + } + + ipv6 { + primary_peer_address_prefix = "2002:db01::/126" + secondary_peer_address_prefix = "2003:db01::/126" + + microsoft_peering { + advertised_public_prefixes = ["2002:db01::/126"] + } + } +} +resource "azurerm_express_route_circuit_peering" "example2" { + peering_type = "MicrosoftPeering" + express_route_circuit_name = azurerm_express_route_circuit.example.name + resource_group_name = azurerm_resource_group.example.name + peer_asn = 100 + primary_peer_address_prefix = "123.0.0.0/30" + secondary_peer_address_prefix = "123.0.0.4/30" + vlan_id = 300 + + microsoft_peering_config { + advertised_public_prefixes = ["123.1.0.0/24"] + } + + ipv6 { + primary_peer_address_prefix = "2002:db01::/126" + secondary_peer_address_prefix = "2003:db01::/126" + + microsoft_peering { + advertised_public_prefixes = ["2002:db01::/126"] + } + } } resource "azurerm_express_route_circuit_connection" "example" { @@ -41,6 +108,9 @@ resource "azurerm_express_route_circuit_connection" "example" { resource_group_name = azurerm_resource_group.example.name circuit_name = azurerm_express_route_circuit.example.name peering_name = azurerm_express_route_circuit_peering.example.name + peering_id = azurerm_express_route_circuit_peering.example1.id + peer_peering_id = azurerm_express_route_circuit_peering.example2.id + address_prefix = "192.169.8.0/29" } ``` @@ -56,9 +126,9 @@ The following arguments are supported: * `peering_name` - (Required) The name of the peering. Changing this forces a new network ExpressRouteCircuitConnection to be created. ---- +* `address_prefix` - (Required) /29 IP address space to carve out Customer addresses for tunnels. -* `address_prefix` - (Optional) /29 IP address space to carve out Customer addresses for tunnels. +--- * `authorization_key` - (Optional) The authorization key. From 3ac150bf2a56a58867b71ee2ee952eadc7ba1e18 Mon Sep 17 00:00:00 2001 From: xuzhang3 Date: Tue, 13 Apr 2021 14:28:09 +0800 Subject: [PATCH 03/28] * remove peering_name * update testcase and doc --- ...s_route_circuit_connections_data_source.go | 21 ++--------- ...te_circuit_connections_data_source_test.go | 1 - ...ress_route_circuit_connections_resource.go | 31 +++++----------- ...route_circuit_connections_resource_test.go | 4 -- ...ss_route_circuit_connections.html.markdown | 3 -- ...ss_route_circuit_connections.html.markdown | 37 +++---------------- 6 files changed, 20 insertions(+), 77 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connections_data_source.go b/azurerm/internal/services/network/express_route_circuit_connections_data_source.go index a976549aa0a3..235402e2a314 100644 --- a/azurerm/internal/services/network/express_route_circuit_connections_data_source.go +++ b/azurerm/internal/services/network/express_route_circuit_connections_data_source.go @@ -4,7 +4,6 @@ import ( "fmt" "time" - "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-05-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" @@ -35,16 +34,6 @@ func dataSourceExpressRouteCircuitConnection() *schema.Resource { Required: true, ValidateFunc: validation.StringIsNotEmpty, }, - - "peering_name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - string(network.AzurePrivatePeering), - string(network.AzurePublicPeering), - string(network.MicrosoftPeering), - }, false), - }, }, } } @@ -57,23 +46,21 @@ func dataSourceExpressRouteCircuitConnectionRead(d *schema.ResourceData, meta in name := d.Get("name").(string) resourceGroup := d.Get("resource_group_name").(string) circuitName := d.Get("circuit_name").(string) - peeringName := d.Get("peering_name").(string) - resp, err := client.Get(ctx, resourceGroup, circuitName, peeringName, name) + resp, err := client.Get(ctx, resourceGroup, circuitName, "AzurePrivatePeering", name) if err != nil { if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf(" ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q) does not exist", name, resourceGroup, circuitName, peeringName) + return fmt.Errorf(" ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q) does not exist", name, resourceGroup, circuitName) } - return fmt.Errorf("retrieving ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", name, resourceGroup, circuitName, peeringName, err) + return fmt.Errorf("retrieving ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q): %+v", name, resourceGroup, circuitName, err) } if resp.ID == nil || *resp.ID == "" { - return fmt.Errorf("empty or nil ID returned for ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q) ID", name, resourceGroup, circuitName, peeringName) + return fmt.Errorf("empty or nil ID returned for ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q) ID", name, resourceGroup, circuitName) } d.SetId(*resp.ID) d.Set("name", name) d.Set("resource_group_name", resourceGroup) d.Set("circuit_name", circuitName) - d.Set("peering_name", peeringName) return nil } diff --git a/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go b/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go index b42f24436e7c..4b6a46b08302 100644 --- a/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go @@ -35,7 +35,6 @@ data "azurerm_express_route_circuit_connection" "test" { name = azurerm_express_route_circuit_connection.test.name resource_group_name = azurerm_express_route_circuit_connection.test.resource_group_name circuit_name = azurerm_express_route_circuit_connection.test.circuit_name - peering_name = azurerm_express_route_circuit_connection.test.peering_name } `, ExpressRouteCircuitConnectionResource{}.basic(data)) } diff --git a/azurerm/internal/services/network/express_route_circuit_connections_resource.go b/azurerm/internal/services/network/express_route_circuit_connections_resource.go index 0f4cb9c2aa8e..473acab222cf 100644 --- a/azurerm/internal/services/network/express_route_circuit_connections_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connections_resource.go @@ -2,12 +2,12 @@ package network import ( "fmt" - "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "log" "time" "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-05-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/tf" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" @@ -53,32 +53,23 @@ func resourceExpressRouteCircuitConnection() *schema.Resource { ValidateFunc: validation.StringIsNotEmpty, }, - "peering_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{ - string(network.AzurePrivatePeering), - string(network.AzurePublicPeering), - string(network.MicrosoftPeering), - }, false), - }, - "peering_id": { Type: schema.TypeString, Required: true, + ForceNew: true, ValidateFunc: azure.ValidateResourceID, }, "peer_peering_id": { Type: schema.TypeString, Required: true, + ForceNew: true, ValidateFunc: azure.ValidateResourceID, }, "address_prefix": { Type: schema.TypeString, - Optional: true, + Required: true, ValidateFunc: validation.IsCIDR, }, @@ -119,15 +110,14 @@ func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, m name := d.Get("name").(string) resourceGroup := d.Get("resource_group_name").(string) circuitName := d.Get("circuit_name").(string) - peeringName := d.Get("peering_name").(string) - id := parse.NewExpressRouteCircuitConnectionID(subscriptionId, resourceGroup, circuitName, peeringName, name).ID() + id := parse.NewExpressRouteCircuitConnectionID(subscriptionId, resourceGroup, circuitName, "AzurePrivatePeering", name).ID() if d.IsNewResource() { - existing, err := client.Get(ctx, resourceGroup, circuitName, peeringName, name) + existing, err := client.Get(ctx, resourceGroup, circuitName, "AzurePrivatePeering", name) if err != nil { if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for existing ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", name, resourceGroup, circuitName, peeringName, err) + return fmt.Errorf("checking for existing ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q): %+v", name, resourceGroup, circuitName, err) } } if !utils.ResponseWasNotFound(existing.Response) { @@ -153,13 +143,13 @@ func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, m expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.AuthorizationKey = utils.String(v.(string)) } - future, err := client.CreateOrUpdate(ctx, resourceGroup, circuitName, peeringName, name, expressRouteCircuitConnectionParameters) + future, err := client.CreateOrUpdate(ctx, resourceGroup, circuitName, "AzurePrivatePeering", name, expressRouteCircuitConnectionParameters) if err != nil { - return fmt.Errorf("creating/updating ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", name, resourceGroup, circuitName, peeringName, err) + return fmt.Errorf("creating/updating ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q): %+v", name, resourceGroup, circuitName, err) } if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation/update of the ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", name, resourceGroup, circuitName, peeringName, err) + return fmt.Errorf("waiting for creation/update of the ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q): %+v", name, resourceGroup, circuitName, err) } d.SetId(id) @@ -188,7 +178,6 @@ func resourceExpressRouteCircuitConnectionRead(d *schema.ResourceData, meta inte d.Set("name", id.Name) d.Set("resource_group_name", id.ResourceGroup) d.Set("circuit_name", id.CircuitName) - d.Set("peering_name", id.PeeringName) d.Set("peering_id", resp.ExpressRouteCircuitPeering.ID) d.Set("peer_peering_id", resp.PeerExpressRouteCircuitPeering.ID) if props := resp.ExpressRouteCircuitConnectionPropertiesFormat; props != nil { diff --git a/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go b/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go index 442990df2a90..0d7d26451096 100644 --- a/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go @@ -198,7 +198,6 @@ resource "azurerm_express_route_circuit_connection" "test" { name = "acctest-nercc-%d" resource_group_name = "%s" circuit_name = "%s" - peering_name = azurerm_express_route_circuit_peering.test.peering_type peering_id = azurerm_express_route_circuit_peering.test.id peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id address_prefix = "192.169.8.0/29" @@ -215,7 +214,6 @@ resource "azurerm_express_route_circuit_connection" "import" { name = azurerm_express_route_circuit_connection.test.name resource_group_name = azurerm_express_route_circuit_connection.test.resource_group_name circuit_name = azurerm_express_route_circuit_connection.test.circuit_name - peering_name = azurerm_express_route_circuit_connection.test.peering_name peering_id = azurerm_express_route_circuit_peering.test.id peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id address_prefix = "192.169.8.0/29" @@ -235,7 +233,6 @@ resource "azurerm_express_route_circuit_connection" "test" { name = "acctest-nercc-%d" resource_group_name = "%s" circuit_name = "%s" - peering_name = azurerm_express_route_circuit_peering.test.peering_type peering_id = azurerm_express_route_circuit_peering.test.id peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id address_prefix = "192.169.8.0/29" @@ -259,7 +256,6 @@ resource "azurerm_express_route_circuit_connection" "test" { name = "acctest-nercc-%d" resource_group_name = "%s" circuit_name = "%s" - peering_name = azurerm_express_route_circuit_peering.test.peering_type peering_id = azurerm_express_route_circuit_peering.test.id peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id address_prefix = "192.169.8.0/29" diff --git a/website/docs/d/express_route_circuit_connections.html.markdown b/website/docs/d/express_route_circuit_connections.html.markdown index 64b9e3bc61fc..e12c6bb26af2 100644 --- a/website/docs/d/express_route_circuit_connections.html.markdown +++ b/website/docs/d/express_route_circuit_connections.html.markdown @@ -17,7 +17,6 @@ data "azurerm_express_route_circuit_connection" "example" { name = "example-expressroutecircuitconnection" resource_group_name = "existing" circuit_name = "existing" - peering_name = "existing" } output "id" { @@ -35,8 +34,6 @@ The following arguments are supported: * `circuit_name` - (Required) The name of the express route circuit. -* `peering_name` - (Required) The name of the peering. - ## Attributes Reference In addition to the Arguments listed above - the following Attributes are exported: diff --git a/website/docs/r/express_route_circuit_connections.html.markdown b/website/docs/r/express_route_circuit_connections.html.markdown index 1b74e76b4bc7..ae92c9485425 100644 --- a/website/docs/r/express_route_circuit_connections.html.markdown +++ b/website/docs/r/express_route_circuit_connections.html.markdown @@ -59,58 +59,35 @@ resource "azurerm_express_route_circuit" "example2" { } resource "azurerm_express_route_circuit_peering" "example1" { - peering_type = "MicrosoftPeering" + peering_type = "AzurePrivatePeering" express_route_circuit_name = azurerm_express_route_circuit.example.name resource_group_name = azurerm_resource_group.example.name peer_asn = 100 primary_peer_address_prefix = "123.0.0.0/30" secondary_peer_address_prefix = "123.0.0.4/30" vlan_id = 300 - - microsoft_peering_config { - advertised_public_prefixes = ["123.1.0.0/24"] - } - - ipv6 { - primary_peer_address_prefix = "2002:db01::/126" - secondary_peer_address_prefix = "2003:db01::/126" - - microsoft_peering { - advertised_public_prefixes = ["2002:db01::/126"] - } - } } resource "azurerm_express_route_circuit_peering" "example2" { - peering_type = "MicrosoftPeering" + peering_type = "AzurePrivatePeering" express_route_circuit_name = azurerm_express_route_circuit.example.name resource_group_name = azurerm_resource_group.example.name peer_asn = 100 primary_peer_address_prefix = "123.0.0.0/30" secondary_peer_address_prefix = "123.0.0.4/30" vlan_id = 300 - - microsoft_peering_config { - advertised_public_prefixes = ["123.1.0.0/24"] - } - - ipv6 { - primary_peer_address_prefix = "2002:db01::/126" - secondary_peer_address_prefix = "2003:db01::/126" - - microsoft_peering { - advertised_public_prefixes = ["2002:db01::/126"] - } - } } resource "azurerm_express_route_circuit_connection" "example" { name = "example-expressroutecircuitconnection" resource_group_name = azurerm_resource_group.example.name circuit_name = azurerm_express_route_circuit.example.name - peering_name = azurerm_express_route_circuit_peering.example.name peering_id = azurerm_express_route_circuit_peering.example1.id peer_peering_id = azurerm_express_route_circuit_peering.example2.id address_prefix = "192.169.8.0/29" + authorization_key = "00000000-0000-0000-0000-000000000000" + ipv6circuit_connection_config { + address_prefix = "2002:db01::/125" + } } ``` @@ -124,8 +101,6 @@ The following arguments are supported: * `circuit_name` - (Required) The name of the express route circuit. Changing this forces a new network ExpressRouteCircuitConnection to be created. -* `peering_name` - (Required) The name of the peering. Changing this forces a new network ExpressRouteCircuitConnection to be created. - * `address_prefix` - (Required) /29 IP address space to carve out Customer addresses for tunnels. --- From 7c390c78d99b0ab9c4403005cab800254506720e Mon Sep 17 00:00:00 2001 From: xuzhang3 Date: Tue, 13 Apr 2021 15:33:28 +0800 Subject: [PATCH 04/28] format --- ...ress_route_circuit_connections_resource.go | 12 +-------- ...route_circuit_connections_resource_test.go | 13 ++++------ ...ess_route_circuit_peering_resource_test.go | 4 +-- ...ss_route_circuit_connections.html.markdown | 6 ++--- ...ss_route_circuit_connections.html.markdown | 26 +++++++++---------- 5 files changed, 24 insertions(+), 37 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connections_resource.go b/azurerm/internal/services/network/express_route_circuit_connections_resource.go index 473acab222cf..5c722fbee063 100644 --- a/azurerm/internal/services/network/express_route_circuit_connections_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connections_resource.go @@ -90,11 +90,6 @@ func resourceExpressRouteCircuitConnection() *schema.Resource { Optional: true, ValidateFunc: validation.IsCIDR, }, - - "circuit_connection_status": { - Type: schema.TypeString, - Computed: true, - }, }, }, }, @@ -230,14 +225,9 @@ func flattenExpressRouteCircuitConnectionIpv6CircuitConnectionConfig(input *netw if input.AddressPrefix != nil { addressPrefix = *input.AddressPrefix } - var circuitConnectionStatus network.CircuitConnectionStatus - if input.CircuitConnectionStatus != "" { - circuitConnectionStatus = input.CircuitConnectionStatus - } return []interface{}{ map[string]interface{}{ - "address_prefix": addressPrefix, - "circuit_connection_status": circuitConnectionStatus, + "address_prefix": addressPrefix, }, } } diff --git a/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go b/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go index 0d7d26451096..1be75e90f0cd 100644 --- a/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go @@ -191,8 +191,8 @@ func (r ExpressRouteCircuitConnectionResource) basic(data acceptance.TestData) s rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") circuitName := os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") template := r.template(data) - return fmt.Sprintf(` -%s + + return fmt.Sprintf(`%s resource "azurerm_express_route_circuit_connection" "test" { name = "acctest-nercc-%d" @@ -207,8 +207,7 @@ resource "azurerm_express_route_circuit_connection" "test" { func (r ExpressRouteCircuitConnectionResource) requiresImport(data acceptance.TestData) string { config := r.basic(data) - return fmt.Sprintf(` -%s + return fmt.Sprintf(`%s resource "azurerm_express_route_circuit_connection" "import" { name = azurerm_express_route_circuit_connection.test.name @@ -226,8 +225,7 @@ func (r ExpressRouteCircuitConnectionResource) complete(data acceptance.TestData circuitName := os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") template := r.template(data) - return fmt.Sprintf(` -%s + return fmt.Sprintf(`%s resource "azurerm_express_route_circuit_connection" "test" { name = "acctest-nercc-%d" @@ -249,8 +247,7 @@ func (r ExpressRouteCircuitConnectionResource) updateIpv6CircuitConnectionConfig circuitName := os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") template := r.template(data) - return fmt.Sprintf(` -%s + return fmt.Sprintf(`%s resource "azurerm_express_route_circuit_connection" "test" { name = "acctest-nercc-%d" diff --git a/azurerm/internal/services/network/express_route_circuit_peering_resource_test.go b/azurerm/internal/services/network/express_route_circuit_peering_resource_test.go index 00229f384bcb..93fc503d0f34 100644 --- a/azurerm/internal/services/network/express_route_circuit_peering_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_peering_resource_test.go @@ -205,8 +205,8 @@ resource "azurerm_express_route_circuit" "test" { name = "acctest-erc-%d" location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name - service_provider_name = "Equinix Test" - peering_location = "Area51" + service_provider_name = "Equinix" + peering_location = "Silicon Valley" bandwidth_in_mbps = 50 sku { diff --git a/website/docs/d/express_route_circuit_connections.html.markdown b/website/docs/d/express_route_circuit_connections.html.markdown index e12c6bb26af2..0b3099c27ee9 100644 --- a/website/docs/d/express_route_circuit_connections.html.markdown +++ b/website/docs/d/express_route_circuit_connections.html.markdown @@ -14,9 +14,9 @@ Use this data source to access information about an existing network ExpressRout ```hcl data "azurerm_express_route_circuit_connection" "example" { - name = "example-expressroutecircuitconnection" + name = "example-expressroutecircuitconnection" resource_group_name = "existing" - circuit_name = "existing" + circuit_name = "existing" } output "id" { @@ -44,4 +44,4 @@ In addition to the Arguments listed above - the following Attributes are exporte The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: -* `read` - (Defaults to 5 minutes) Used when retrieving the network ExpressRouteCircuitConnection. \ No newline at end of file +* `read` - (Defaults to 5 minutes) Used when retrieving the network ExpressRouteCircuitConnection. diff --git a/website/docs/r/express_route_circuit_connections.html.markdown b/website/docs/r/express_route_circuit_connections.html.markdown index ae92c9485425..502dcda39c3c 100644 --- a/website/docs/r/express_route_circuit_connections.html.markdown +++ b/website/docs/r/express_route_circuit_connections.html.markdown @@ -60,7 +60,7 @@ resource "azurerm_express_route_circuit" "example2" { resource "azurerm_express_route_circuit_peering" "example1" { peering_type = "AzurePrivatePeering" - express_route_circuit_name = azurerm_express_route_circuit.example.name + express_route_circuit_name = azurerm_express_route_circuit.example1.name resource_group_name = azurerm_resource_group.example.name peer_asn = 100 primary_peer_address_prefix = "123.0.0.0/30" @@ -69,7 +69,7 @@ resource "azurerm_express_route_circuit_peering" "example1" { } resource "azurerm_express_route_circuit_peering" "example2" { peering_type = "AzurePrivatePeering" - express_route_circuit_name = azurerm_express_route_circuit.example.name + express_route_circuit_name = azurerm_express_route_circuit.example2.name resource_group_name = azurerm_resource_group.example.name peer_asn = 100 primary_peer_address_prefix = "123.0.0.0/30" @@ -78,13 +78,13 @@ resource "azurerm_express_route_circuit_peering" "example2" { } resource "azurerm_express_route_circuit_connection" "example" { - name = "example-expressroutecircuitconnection" + name = "example-expressroutecircuitconnection" resource_group_name = azurerm_resource_group.example.name - circuit_name = azurerm_express_route_circuit.example.name - peering_id = azurerm_express_route_circuit_peering.example1.id - peer_peering_id = azurerm_express_route_circuit_peering.example2.id - address_prefix = "192.169.8.0/29" - authorization_key = "00000000-0000-0000-0000-000000000000" + circuit_name = azurerm_express_route_circuit.example1.name + peering_id = azurerm_express_route_circuit_peering.example1.id + peer_peering_id = azurerm_express_route_circuit_peering.example2.id + address_prefix = "192.169.8.0/29" + authorization_key = "00000000-0000-0000-0000-000000000000" ipv6circuit_connection_config { address_prefix = "2002:db01::/125" } @@ -100,6 +100,10 @@ The following arguments are supported: * `resource_group_name` - (Required) The name of the Resource Group where the network ExpressRouteCircuitConnection should exist. Changing this forces a new network ExpressRouteCircuitConnection to be created. * `circuit_name` - (Required) The name of the express route circuit. Changing this forces a new network ExpressRouteCircuitConnection to be created. + +* `peering_id` - (Required) The ID of the Express Route Circuit Private Peering Resource of the circuit initiating connection. + +* `peer_peering_id` - (Required) The ID of the Express Route Circuit Private Peering Resource of the peered circuit. * `address_prefix` - (Required) /29 IP address space to carve out Customer addresses for tunnels. @@ -121,10 +125,6 @@ In addition to the Arguments listed above - the following Attributes are exporte * `id` - The ID of the network ExpressRouteCircuitConnection. -* `circuit_connection_status` - Express Route Circuit connection state. - -* `type` - Type of the resource. - ## Timeouts The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: @@ -139,4 +139,4 @@ network ExpressRouteCircuitConnections can be imported using the `resource id`, ```shell terraform import azurerm_express_route_circuit_connection.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/connection1 -``` \ No newline at end of file +``` From 7275014faf00bc12d48cf7ef51a12157b7b675b1 Mon Sep 17 00:00:00 2001 From: xuzhang3 Date: Tue, 13 Apr 2021 16:19:14 +0800 Subject: [PATCH 05/28] format --- .../express_route_circuit_connections_data_source_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go b/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go index 4b6a46b08302..971c39d6c45c 100644 --- a/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go @@ -32,9 +32,9 @@ func (ExpressRouteCircuitConnectionDataSource) basic(data acceptance.TestData) s %s data "azurerm_express_route_circuit_connection" "test" { - name = azurerm_express_route_circuit_connection.test.name + name = azurerm_express_route_circuit_connection.test.name resource_group_name = azurerm_express_route_circuit_connection.test.resource_group_name - circuit_name = azurerm_express_route_circuit_connection.test.circuit_name + circuit_name = azurerm_express_route_circuit_connection.test.circuit_name } `, ExpressRouteCircuitConnectionResource{}.basic(data)) } From 1768c01d29800cc9a8580d2245791cd2ca4ce863 Mon Sep 17 00:00:00 2001 From: xuzhang3 Date: Tue, 13 Apr 2021 17:08:31 +0800 Subject: [PATCH 06/28] remove unused params --- .../express_route_circuit_connections_resource_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go b/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go index 1be75e90f0cd..7d560fd6ca1b 100644 --- a/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go @@ -153,7 +153,7 @@ func (r ExpressRouteCircuitConnectionResource) Exists(ctx context.Context, clien return utils.Bool(true), nil } -func (r ExpressRouteCircuitConnectionResource) template(data acceptance.TestData) string { +func (r ExpressRouteCircuitConnectionResource) template() string { rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") circuitName1 := os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") circuitName2 := os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") @@ -190,7 +190,7 @@ resource "azurerm_express_route_circuit_peering" "peer_test" { func (r ExpressRouteCircuitConnectionResource) basic(data acceptance.TestData) string { rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") circuitName := os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") - template := r.template(data) + template := r.template() return fmt.Sprintf(`%s @@ -224,7 +224,7 @@ func (r ExpressRouteCircuitConnectionResource) complete(data acceptance.TestData rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") circuitName := os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") - template := r.template(data) + template := r.template() return fmt.Sprintf(`%s resource "azurerm_express_route_circuit_connection" "test" { @@ -246,7 +246,7 @@ func (r ExpressRouteCircuitConnectionResource) updateIpv6CircuitConnectionConfig rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") circuitName := os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") - template := r.template(data) + template := r.template() return fmt.Sprintf(`%s resource "azurerm_express_route_circuit_connection" "test" { From 39b00d2bef46e38ce49c8fedbbc7b7d778975eb4 Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Fri, 16 Apr 2021 11:51:24 +0800 Subject: [PATCH 07/28] update code --- ...ml.markdown => express_route_circuit_connection.html.markdown} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename website/docs/d/{express_route_circuit_connections.html.markdown => express_route_circuit_connection.html.markdown} (100%) diff --git a/website/docs/d/express_route_circuit_connections.html.markdown b/website/docs/d/express_route_circuit_connection.html.markdown similarity index 100% rename from website/docs/d/express_route_circuit_connections.html.markdown rename to website/docs/d/express_route_circuit_connection.html.markdown From 116abdc14940b57bdd49b475de716702599b310c Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Mon, 19 Apr 2021 14:28:23 +0800 Subject: [PATCH 08/28] update code --- .../parse/authorization_server.go.3000707651 | 75 ++++++++++ ...ress_route_circuit_connection_resource.go} | 127 +++++++---------- ...route_circuit_connection_resource_test.go} | 130 ++++++++---------- ...s_route_circuit_connections_data_source.go | 66 --------- ...te_circuit_connections_data_source_test.go | 40 ------ .../parse/express_route_circuit_connection.go | 69 +++++++--- .../express_route_circuit_connection_test.go | 93 +++++++------ .../parse/express_route_circuit_peering.go | 75 ++++++++++ .../express_route_circuit_peering_test.go | 128 +++++++++++++++++ .../internal/services/network/registration.go | 1 - .../internal/services/network/resourceids.go | 4 + .../express_route_circuit_connection_id.go | 23 ++++ ...xpress_route_circuit_connection_id_test.go | 100 ++++++++++++++ .../express_route_circuit_peering_id.go | 23 ++++ .../express_route_circuit_peering_id_test.go | 88 ++++++++++++ ...ess_route_circuit_connection.html.markdown | 47 ------- ...ss_route_circuit_connection.html.markdown} | 50 +++---- 17 files changed, 744 insertions(+), 395 deletions(-) create mode 100644 azurerm/internal/services/apimanagement/parse/authorization_server.go.3000707651 rename azurerm/internal/services/network/{express_route_circuit_connections_resource.go => express_route_circuit_connection_resource.go} (56%) rename azurerm/internal/services/network/{express_route_circuit_connections_resource_test.go => express_route_circuit_connection_resource_test.go} (80%) delete mode 100644 azurerm/internal/services/network/express_route_circuit_connections_data_source.go delete mode 100644 azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go create mode 100644 azurerm/internal/services/network/parse/express_route_circuit_peering.go create mode 100644 azurerm/internal/services/network/parse/express_route_circuit_peering_test.go create mode 100644 azurerm/internal/services/network/validate/express_route_circuit_connection_id.go create mode 100644 azurerm/internal/services/network/validate/express_route_circuit_connection_id_test.go create mode 100644 azurerm/internal/services/network/validate/express_route_circuit_peering_id.go create mode 100644 azurerm/internal/services/network/validate/express_route_circuit_peering_id_test.go delete mode 100644 website/docs/d/express_route_circuit_connection.html.markdown rename website/docs/r/{express_route_circuit_connections.html.markdown => express_route_circuit_connection.html.markdown} (65%) diff --git a/azurerm/internal/services/apimanagement/parse/authorization_server.go.3000707651 b/azurerm/internal/services/apimanagement/parse/authorization_server.go.3000707651 new file mode 100644 index 000000000000..c6aba6127c9a --- /dev/null +++ b/azurerm/internal/services/apimanagement/parse/authorization_server.go.3000707651 @@ -0,0 +1,75 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type AuthorizationServerId struct { + SubscriptionId string + ResourceGroup string + ServiceName string + Name string +} + +func NewAuthorizationServerID(subscriptionId, resourceGroup, serviceName, name string) AuthorizationServerId { + return AuthorizationServerId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ServiceName: serviceName, + Name: name, + } +} + +func (id AuthorizationServerId) String() string { + segments := []string{ + fmt.Sprintf("Name %q", id.Name), + fmt.Sprintf("Service Name %q", id.ServiceName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Authorization Server", segmentsStr) +} + +func (id AuthorizationServerId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.ApiManagement/service/%s/authorizationServers/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServiceName, id.Name) +} + +// AuthorizationServerID parses a AuthorizationServer ID into an AuthorizationServerId struct +func AuthorizationServerID(input string) (*AuthorizationServerId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := AuthorizationServerId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.ServiceName, err = id.PopSegment("service"); err != nil { + return nil, err + } + if resourceId.Name, err = id.PopSegment("authorizationServers"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/azurerm/internal/services/network/express_route_circuit_connections_resource.go b/azurerm/internal/services/network/express_route_circuit_connection_resource.go similarity index 56% rename from azurerm/internal/services/network/express_route_circuit_connections_resource.go rename to azurerm/internal/services/network/express_route_circuit_connection_resource.go index 5c722fbee063..74c82d7cf626 100644 --- a/azurerm/internal/services/network/express_route_circuit_connections_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource.go @@ -12,6 +12,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/validate" azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" @@ -46,28 +47,21 @@ func resourceExpressRouteCircuitConnection() *schema.Resource { "resource_group_name": azure.SchemaResourceGroupName(), - "circuit_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringIsNotEmpty, - }, - "peering_id": { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: azure.ValidateResourceID, + ValidateFunc: validate.ExpressRouteCircuitPeeringID, }, "peer_peering_id": { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: azure.ValidateResourceID, + ValidateFunc: validate.ExpressRouteCircuitPeeringID, }, - "address_prefix": { + "address_prefix_ipv4": { Type: schema.TypeString, Required: true, ValidateFunc: validation.IsCIDR, @@ -79,58 +73,50 @@ func resourceExpressRouteCircuitConnection() *schema.Resource { Sensitive: true, }, - "ipv6circuit_connection_config": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "address_prefix": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.IsCIDR, - }, - }, - }, + "address_prefix_ipv6": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsCIDR, }, }, } } + func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, meta interface{}) error { subscriptionId := meta.(*clients.Client).Account.SubscriptionId client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - name := d.Get("name").(string) - resourceGroup := d.Get("resource_group_name").(string) - circuitName := d.Get("circuit_name").(string) + expressRouteCircuitPeeringId, err := parse.ExpressRouteCircuitPeeringID(d.Get("peering_id").(string)) + if err != nil { + return err + } - id := parse.NewExpressRouteCircuitConnectionID(subscriptionId, resourceGroup, circuitName, "AzurePrivatePeering", name).ID() + id := parse.NewExpressRouteCircuitConnectionID(subscriptionId, d.Get("resource_group_name").(string), expressRouteCircuitPeeringId.ExpressRouteCircuitName, "AzurePrivatePeering", d.Get("name").(string)) if d.IsNewResource() { - existing, err := client.Get(ctx, resourceGroup, circuitName, "AzurePrivatePeering", name) + existing, err := client.Get(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, "AzurePrivatePeering", id.ConnectionName) if err != nil { if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for existing ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q): %+v", name, resourceGroup, circuitName, err) + return fmt.Errorf("checking for existing %s: %+v", id, err) } } if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_express_route_circuit_connection", id) + return tf.ImportAsExistsError("azurerm_express_route_circuit_connection", id.ID()) } } expressRouteCircuitConnectionParameters := network.ExpressRouteCircuitConnection{ - Name: utils.String(d.Get("name").(string)), + Name: utils.String(id.ConnectionName), ExpressRouteCircuitConnectionPropertiesFormat: &network.ExpressRouteCircuitConnectionPropertiesFormat{ - AddressPrefix: utils.String(d.Get("address_prefix").(string)), + AddressPrefix: utils.String(d.Get("address_prefix_ipv4").(string)), ExpressRouteCircuitPeering: &network.SubResource{ - ID: utils.String(d.Get("peering_id").(string)), + ID: utils.String(expressRouteCircuitPeeringId.ID()), }, PeerExpressRouteCircuitPeering: &network.SubResource{ ID: utils.String(d.Get("peer_peering_id").(string)), }, - Ipv6CircuitConnectionConfig: expandExpressRouteCircuitConnectionIpv6CircuitConnectionConfig(d.Get("ipv6circuit_connection_config").([]interface{})), }, } @@ -138,16 +124,23 @@ func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, m expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.AuthorizationKey = utils.String(v.(string)) } - future, err := client.CreateOrUpdate(ctx, resourceGroup, circuitName, "AzurePrivatePeering", name, expressRouteCircuitConnectionParameters) + if v, ok := d.GetOk("address_prefix_ipv6"); ok { + expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.Ipv6CircuitConnectionConfig = &network.Ipv6CircuitConnectionConfig{ + AddressPrefix: utils.String(v.(string)), + } + } + + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, "AzurePrivatePeering", id.ConnectionName, expressRouteCircuitConnectionParameters) if err != nil { - return fmt.Errorf("creating/updating ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q): %+v", name, resourceGroup, circuitName, err) + return fmt.Errorf("creating/updating ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q): %+v", id.ConnectionName, id.ResourceGroup, id.ExpressRouteCircuitName, err) } if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation/update of the ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q): %+v", name, resourceGroup, circuitName, err) + return fmt.Errorf("waiting for creation of %s: %+v", id, err) } - d.SetId(id) + d.SetId(id.ID()) + return resourceExpressRouteCircuitConnectionRead(d, meta) } @@ -161,27 +154,32 @@ func resourceExpressRouteCircuitConnectionRead(d *schema.ResourceData, meta inte return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.CircuitName, id.PeeringName, id.Name) + resp, err := client.Get(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, id.PeeringName, id.ConnectionName) if err != nil { if utils.ResponseWasNotFound(resp.Response) { - log.Printf("[INFO] express route circuit connection %q does not exist - removing from state", d.Id()) + log.Printf("[INFO] %s does not exist - removing from state", *id) d.SetId("") return nil } - return fmt.Errorf("retrieving ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", id.Name, id.ResourceGroup, id.CircuitName, id.PeeringName, err) + return fmt.Errorf("retrieving %s: %+v", *id, err) } - d.Set("name", id.Name) + d.Set("name", id.ConnectionName) d.Set("resource_group_name", id.ResourceGroup) - d.Set("circuit_name", id.CircuitName) - d.Set("peering_id", resp.ExpressRouteCircuitPeering.ID) - d.Set("peer_peering_id", resp.PeerExpressRouteCircuitPeering.ID) + d.Set("peering_id", parse.NewExpressRouteCircuitPeeringID(id.SubscriptionId, id.ResourceGroup, id.ExpressRouteCircuitName, "AzurePrivatePeering").ID()) + + if peerExpressRouteCircuitPeering := resp.PeerExpressRouteCircuitPeering; peerExpressRouteCircuitPeering != nil && peerExpressRouteCircuitPeering.ID != nil { + d.Set("peer_peering_id", peerExpressRouteCircuitPeering.ID) + } + if props := resp.ExpressRouteCircuitConnectionPropertiesFormat; props != nil { - d.Set("address_prefix", props.AddressPrefix) + d.Set("address_prefix_ipv4", props.AddressPrefix) d.Set("authorization_key", props.AuthorizationKey) - if err := d.Set("ipv6circuit_connection_config", flattenExpressRouteCircuitConnectionIpv6CircuitConnectionConfig(props.Ipv6CircuitConnectionConfig)); err != nil { - return fmt.Errorf("setting `ipv6circuit_connection_config`: %+v", err) + + if props.Ipv6CircuitConnectionConfig != nil && props.Ipv6CircuitConnectionConfig.AddressPrefix != nil { + d.Set("address_prefix_ipv6", props.Ipv6CircuitConnectionConfig.AddressPrefix) } } + return nil } @@ -195,39 +193,14 @@ func resourceExpressRouteCircuitConnectionDelete(d *schema.ResourceData, meta in return err } - future, err := client.Delete(ctx, id.ResourceGroup, id.CircuitName, id.PeeringName, id.Name) + future, err := client.Delete(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, id.PeeringName, id.ConnectionName) if err != nil { - return fmt.Errorf("deleting ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", id.Name, id.ResourceGroup, id.CircuitName, id.PeeringName, err) + return fmt.Errorf("deleting %s: %+v", *id, err) } if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for deletion of the ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", id.Name, id.ResourceGroup, id.CircuitName, id.PeeringName, err) - } - return nil -} - -func expandExpressRouteCircuitConnectionIpv6CircuitConnectionConfig(input []interface{}) *network.Ipv6CircuitConnectionConfig { - if len(input) == 0 { - return nil - } - v := input[0].(map[string]interface{}) - return &network.Ipv6CircuitConnectionConfig{ - AddressPrefix: utils.String(v["address_prefix"].(string)), - } -} - -func flattenExpressRouteCircuitConnectionIpv6CircuitConnectionConfig(input *network.Ipv6CircuitConnectionConfig) []interface{} { - if input == nil { - return make([]interface{}, 0) + return fmt.Errorf("waiting for deletion of %s: %+v", *id, err) } - var addressPrefix string - if input.AddressPrefix != nil { - addressPrefix = *input.AddressPrefix - } - return []interface{}{ - map[string]interface{}{ - "address_prefix": addressPrefix, - }, - } + return nil } diff --git a/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go similarity index 80% rename from azurerm/internal/services/network/express_route_circuit_connections_resource_test.go rename to azurerm/internal/services/network/express_route_circuit_connection_resource_test.go index 7d560fd6ca1b..d8bc8ca47cb7 100644 --- a/azurerm/internal/services/network/express_route_circuit_connections_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go @@ -143,66 +143,29 @@ func (r ExpressRouteCircuitConnectionResource) Exists(ctx context.Context, clien if err != nil { return nil, err } - resp, err := client.Network.ExpressRouteCircuitConnectionClient.Get(ctx, id.ResourceGroup, id.CircuitName, id.PeeringName, id.Name) + resp, err := client.Network.ExpressRouteCircuitConnectionClient.Get(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, id.PeeringName, id.ConnectionName) if err != nil { if utils.ResponseWasNotFound(resp.Response) { return utils.Bool(false), nil } - return nil, fmt.Errorf("retrieving ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q / peeringName %q): %+v", id.Name, id.ResourceGroup, id.CircuitName, id.PeeringName, err) + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) } return utils.Bool(true), nil } -func (r ExpressRouteCircuitConnectionResource) template() string { - rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") - circuitName1 := os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") - circuitName2 := os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") - - return fmt.Sprintf(` -provider "azurerm" { - features {} -} - -resource "azurerm_express_route_circuit_peering" "test" { - peering_type = "AzurePrivatePeering" - express_route_circuit_name = "%[1]s" - resource_group_name = "%[2]s" - shared_key = "SSSSsssssshhhhhItsASecret" - peer_asn = 100 - primary_peer_address_prefix = "192.168.1.0/30" - secondary_peer_address_prefix = "192.168.1.0/30" - vlan_id = 100 -} - -resource "azurerm_express_route_circuit_peering" "peer_test" { - peering_type = "AzurePrivatePeering" - express_route_circuit_name = "%[3]s" - resource_group_name = "%[2]s" - shared_key = "SSSSsssssshhhhhItsASecret" - peer_asn = 100 - primary_peer_address_prefix = "192.168.1.0/30" - secondary_peer_address_prefix = "192.168.1.0/30" - vlan_id = 100 -} -`, circuitName1, rg, circuitName2) -} - func (r ExpressRouteCircuitConnectionResource) basic(data acceptance.TestData) string { rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") - circuitName := os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") - template := r.template() return fmt.Sprintf(`%s resource "azurerm_express_route_circuit_connection" "test" { - name = "acctest-nercc-%d" + name = "acctest-nercc-%d" resource_group_name = "%s" - circuit_name = "%s" - peering_id = azurerm_express_route_circuit_peering.test.id - peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id - address_prefix = "192.169.8.0/29" + peering_id = azurerm_express_route_circuit_peering.test.id + peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id + address_prefix_ipv4 = "192.169.8.0/29" } -`, template, data.RandomInteger, rg, circuitName) +`, r.template(), data.RandomInteger, rg) } func (r ExpressRouteCircuitConnectionResource) requiresImport(data acceptance.TestData) string { @@ -210,56 +173,81 @@ func (r ExpressRouteCircuitConnectionResource) requiresImport(data acceptance.Te return fmt.Sprintf(`%s resource "azurerm_express_route_circuit_connection" "import" { - name = azurerm_express_route_circuit_connection.test.name + name = azurerm_express_route_circuit_connection.test.name resource_group_name = azurerm_express_route_circuit_connection.test.resource_group_name - circuit_name = azurerm_express_route_circuit_connection.test.circuit_name - peering_id = azurerm_express_route_circuit_peering.test.id - peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id - address_prefix = "192.169.8.0/29" + peering_id = azurerm_express_route_circuit_peering.test.id + peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id + address_prefix_ipv4 = azurerm_express_route_circuit_connection.test.address_prefix } `, config) } func (r ExpressRouteCircuitConnectionResource) complete(data acceptance.TestData) string { rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") - circuitName := os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") template := r.template() return fmt.Sprintf(`%s resource "azurerm_express_route_circuit_connection" "test" { - name = "acctest-nercc-%d" + name = "acctest-nercc-%d" resource_group_name = "%s" - circuit_name = "%s" - peering_id = azurerm_express_route_circuit_peering.test.id - peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id - address_prefix = "192.169.8.0/29" - authorization_key = "946a1918-b7a2-4917-b43c-8c4cdaee006a" - ipv6circuit_connection_config { - address_prefix = "aa:bb::/125" - } + peering_id = azurerm_express_route_circuit_peering.test.id + peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id + address_prefix_ipv4 = "192.169.8.0/29" + authorization_key = "946a1918-b7a2-4917-b43c-8c4cdaee006a" + address_prefix_ipv6 = "aa:bb::/125" } -`, template, data.RandomInteger, rg, circuitName) +`, template, data.RandomInteger, rg) } func (r ExpressRouteCircuitConnectionResource) updateIpv6CircuitConnectionConfig(data acceptance.TestData) string { rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") - circuitName := os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") template := r.template() return fmt.Sprintf(`%s resource "azurerm_express_route_circuit_connection" "test" { - name = "acctest-nercc-%d" + name = "acctest-nercc-%d" resource_group_name = "%s" - circuit_name = "%s" - peering_id = azurerm_express_route_circuit_peering.test.id - peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id - address_prefix = "192.169.8.0/29" - authorization_key = "946a1918-b7a2-4917-b43c-8c4cdaee006a" - ipv6circuit_connection_config { - address_prefix = "aa:bb::/125" - } + peering_id = azurerm_express_route_circuit_peering.test.id + peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id + address_prefix_ipv4 = "192.169.8.0/29" + authorization_key = "946a1918-b7a2-4917-b43c-8c4cdaee006a" + address_prefix_ipv6 = "aa:bb::/125" } -`, template, data.RandomInteger, rg, circuitName) +`, template, data.RandomInteger, rg) +} + +func (r ExpressRouteCircuitConnectionResource) template() string { + rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") + circuitName1 := os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") + circuitName2 := os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") + + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_express_route_circuit_peering" "test" { + peering_type = "AzurePrivatePeering" + express_route_circuit_name = "%[1]s" + resource_group_name = "%[2]s" + shared_key = "SSSSsssssshhhhhItsASecret" + peer_asn = 100 + primary_peer_address_prefix = "192.168.1.0/30" + secondary_peer_address_prefix = "192.168.1.0/30" + vlan_id = 100 +} + +resource "azurerm_express_route_circuit_peering" "peer_test" { + peering_type = "AzurePrivatePeering" + express_route_circuit_name = "%[3]s" + resource_group_name = "%[2]s" + shared_key = "SSSSsssssshhhhhItsASecret" + peer_asn = 100 + primary_peer_address_prefix = "192.168.1.0/30" + secondary_peer_address_prefix = "192.168.1.0/30" + vlan_id = 100 +} +`, circuitName1, rg, circuitName2) } diff --git a/azurerm/internal/services/network/express_route_circuit_connections_data_source.go b/azurerm/internal/services/network/express_route_circuit_connections_data_source.go deleted file mode 100644 index 235402e2a314..000000000000 --- a/azurerm/internal/services/network/express_route_circuit_connections_data_source.go +++ /dev/null @@ -1,66 +0,0 @@ -package network - -import ( - "fmt" - "time" - - "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/clients" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" -) - -func dataSourceExpressRouteCircuitConnection() *schema.Resource { - return &schema.Resource{ - Read: dataSourceExpressRouteCircuitConnectionRead, - - Timeouts: &schema.ResourceTimeout{ - Read: schema.DefaultTimeout(5 * time.Minute), - }, - - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringIsNotEmpty, - }, - - "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), - - "circuit_name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringIsNotEmpty, - }, - }, - } -} - -func dataSourceExpressRouteCircuitConnectionRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient - ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) - defer cancel() - - name := d.Get("name").(string) - resourceGroup := d.Get("resource_group_name").(string) - circuitName := d.Get("circuit_name").(string) - - resp, err := client.Get(ctx, resourceGroup, circuitName, "AzurePrivatePeering", name) - if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf(" ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q) does not exist", name, resourceGroup, circuitName) - } - return fmt.Errorf("retrieving ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q): %+v", name, resourceGroup, circuitName, err) - } - if resp.ID == nil || *resp.ID == "" { - return fmt.Errorf("empty or nil ID returned for ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q) ID", name, resourceGroup, circuitName) - } - - d.SetId(*resp.ID) - d.Set("name", name) - d.Set("resource_group_name", resourceGroup) - d.Set("circuit_name", circuitName) - return nil -} diff --git a/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go b/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go deleted file mode 100644 index 971c39d6c45c..000000000000 --- a/azurerm/internal/services/network/express_route_circuit_connections_data_source_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package network_test - -import ( - "fmt" - "os" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" -) - -type ExpressRouteCircuitConnectionDataSource struct{} - -func TestAccExpressRouteCircuitConnectionDataSource_basic(t *testing.T) { - if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || - os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { - t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") - return - } - - data := acceptance.BuildTestData(t, "data.azurerm_express_route_circuit_connection", "test") - r := ExpressRouteCircuitConnectionDataSource{} - data.DataSourceTest(t, []resource.TestStep{ - { - Config: r.basic(data), - Check: resource.ComposeTestCheckFunc(), - }, - }) -} -func (ExpressRouteCircuitConnectionDataSource) basic(data acceptance.TestData) string { - return fmt.Sprintf(` -%s - -data "azurerm_express_route_circuit_connection" "test" { - name = azurerm_express_route_circuit_connection.test.name - resource_group_name = azurerm_express_route_circuit_connection.test.resource_group_name - circuit_name = azurerm_express_route_circuit_connection.test.circuit_name -} -`, ExpressRouteCircuitConnectionResource{}.basic(data)) -} diff --git a/azurerm/internal/services/network/parse/express_route_circuit_connection.go b/azurerm/internal/services/network/parse/express_route_circuit_connection.go index 7b68183f3373..032f5ac4b219 100644 --- a/azurerm/internal/services/network/parse/express_route_circuit_connection.go +++ b/azurerm/internal/services/network/parse/express_route_circuit_connection.go @@ -1,56 +1,81 @@ package parse +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + import ( "fmt" + "strings" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" ) -type NetworkExpressRouteCircuitConnectionId struct { - SubscriptionId string - ResourceGroup string - CircuitName string - PeeringName string - Name string +type ExpressRouteCircuitConnectionId struct { + SubscriptionId string + ResourceGroup string + ExpressRouteCircuitName string + PeeringName string + ConnectionName string +} + +func NewExpressRouteCircuitConnectionID(subscriptionId, resourceGroup, expressRouteCircuitName, peeringName, connectionName string) ExpressRouteCircuitConnectionId { + return ExpressRouteCircuitConnectionId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ExpressRouteCircuitName: expressRouteCircuitName, + PeeringName: peeringName, + ConnectionName: connectionName, + } } -func NewExpressRouteCircuitConnectionID(subscriptionId string, resourcegroup string, circuitname string, peeringname string, name string) NetworkExpressRouteCircuitConnectionId { - return NetworkExpressRouteCircuitConnectionId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourcegroup, - CircuitName: circuitname, - PeeringName: peeringname, - Name: name, +func (id ExpressRouteCircuitConnectionId) String() string { + segments := []string{ + fmt.Sprintf("Connection Name %q", id.ConnectionName), + fmt.Sprintf("Peering Name %q", id.PeeringName), + fmt.Sprintf("Express Route Circuit Name %q", id.ExpressRouteCircuitName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Express Route Circuit Connection", segmentsStr) } -func (id NetworkExpressRouteCircuitConnectionId) ID() string { +func (id ExpressRouteCircuitConnectionId) ID() string { fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/expressRouteCircuits/%s/peerings/%s/connections/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.CircuitName, id.PeeringName, id.Name) + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ExpressRouteCircuitName, id.PeeringName, id.ConnectionName) } -func ExpressRouteCircuitConnectionID(input string) (*NetworkExpressRouteCircuitConnectionId, error) { +// ExpressRouteCircuitConnectionID parses a ExpressRouteCircuitConnection ID into an ExpressRouteCircuitConnectionId struct +func ExpressRouteCircuitConnectionID(input string) (*ExpressRouteCircuitConnectionId, error) { id, err := azure.ParseAzureResourceID(input) if err != nil { - return nil, fmt.Errorf("parsing networkExpressRouteCircuitConnection ID %q: %+v", input, err) + return nil, err } - networkExpressRouteCircuitConnection := NetworkExpressRouteCircuitConnectionId{ + resourceId := ExpressRouteCircuitConnectionId{ SubscriptionId: id.SubscriptionID, ResourceGroup: id.ResourceGroup, } - if networkExpressRouteCircuitConnection.CircuitName, err = id.PopSegment("expressRouteCircuits"); err != nil { + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.ExpressRouteCircuitName, err = id.PopSegment("expressRouteCircuits"); err != nil { return nil, err } - if networkExpressRouteCircuitConnection.PeeringName, err = id.PopSegment("peerings"); err != nil { + if resourceId.PeeringName, err = id.PopSegment("peerings"); err != nil { return nil, err } - if networkExpressRouteCircuitConnection.Name, err = id.PopSegment("connections"); err != nil { + if resourceId.ConnectionName, err = id.PopSegment("connections"); err != nil { return nil, err } + if err := id.ValidateNoEmptySegments(input); err != nil { return nil, err } - return &networkExpressRouteCircuitConnection, nil + return &resourceId, nil } diff --git a/azurerm/internal/services/network/parse/express_route_circuit_connection_test.go b/azurerm/internal/services/network/parse/express_route_circuit_connection_test.go index dab7582bcc91..398802d76113 100644 --- a/azurerm/internal/services/network/parse/express_route_circuit_connection_test.go +++ b/azurerm/internal/services/network/parse/express_route_circuit_connection_test.go @@ -1,96 +1,111 @@ package parse +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + import ( "testing" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" ) -var _ resourceid.Formatter = NetworkExpressRouteCircuitConnectionId{} +var _ resourceid.Formatter = ExpressRouteCircuitConnectionId{} -func TestNetworkExpressRouteCircuitConnectionIDFormatter(t *testing.T) { - actual := NewExpressRouteCircuitConnectionID("12345678-1234-9876-4563-123456789012", "resourceGroup1", "circuit1", "peering1", "connection1").ID() - expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/connection1" +func TestExpressRouteCircuitConnectionIDFormatter(t *testing.T) { + actual := NewExpressRouteCircuitConnectionID("12345678-1234-9876-4563-123456789012", "resGroup1", "circuit1", "peering1", "connection1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/connection1" if actual != expected { t.Fatalf("Expected %q but got %q", expected, actual) } } -func TestNetworkExpressRouteCircuitConnectionID(t *testing.T) { +func TestExpressRouteCircuitConnectionID(t *testing.T) { testData := []struct { Input string Error bool - Expected *NetworkExpressRouteCircuitConnectionId + Expected *ExpressRouteCircuitConnectionId }{ + { // empty Input: "", Error: true, }, + { - // missing subscriptions + // missing SubscriptionId Input: "/", Error: true, }, + { - // missing value for subscriptions + // missing value for SubscriptionId Input: "/subscriptions/", Error: true, }, + { - // missing resourceGroups + // missing ResourceGroup Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", Error: true, }, + { - // missing value for resourceGroups + // missing value for ResourceGroup Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", Error: true, }, + { - // missing expressRouteCircuits - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/", + // missing ExpressRouteCircuitName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", Error: true, }, + { - // missing value for expressRouteCircuits - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/", + // missing value for ExpressRouteCircuitName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/", Error: true, }, + { - // missing peerings - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/", + // missing PeeringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/", Error: true, }, + { - // missing value for peerings - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/", + // missing value for PeeringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/", Error: true, }, + { - // missing connections - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/", + // missing ConnectionName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/", Error: true, }, + { - // missing value for connections - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/", + // missing value for ConnectionName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/", Error: true, }, + { // valid - Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/connection1", - Expected: &NetworkExpressRouteCircuitConnectionId{ - SubscriptionId: "12345678-1234-9876-4563-123456789012", - ResourceGroup: "resourceGroup1", - CircuitName: "circuit1", - PeeringName: "peering1", - Name: "connection1", + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/connection1", + Expected: &ExpressRouteCircuitConnectionId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ExpressRouteCircuitName: "circuit1", + PeeringName: "peering1", + ConnectionName: "connection1", }, }, + { // upper-cased - Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.NETWORK/EXPRESSROUTECIRCUITS/CIRCUIT1/PEERINGS/PEERING1/CONNECTIONS/CONNECTION1", + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/EXPRESSROUTECIRCUITS/CIRCUIT1/PEERINGS/PEERING1/CONNECTIONS/CONNECTION1", Error: true, }, } @@ -103,27 +118,27 @@ func TestNetworkExpressRouteCircuitConnectionID(t *testing.T) { if v.Error { continue } - t.Fatalf("Expected a value but got an error: %s", err) + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") } if actual.SubscriptionId != v.Expected.SubscriptionId { t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) } - if actual.ResourceGroup != v.Expected.ResourceGroup { t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) } - - if actual.CircuitName != v.Expected.CircuitName { - t.Fatalf("Expected %q but got %q for CircuitName", v.Expected.CircuitName, actual.CircuitName) + if actual.ExpressRouteCircuitName != v.Expected.ExpressRouteCircuitName { + t.Fatalf("Expected %q but got %q for ExpressRouteCircuitName", v.Expected.ExpressRouteCircuitName, actual.ExpressRouteCircuitName) } - if actual.PeeringName != v.Expected.PeeringName { t.Fatalf("Expected %q but got %q for PeeringName", v.Expected.PeeringName, actual.PeeringName) } - - if actual.Name != v.Expected.Name { - t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + if actual.ConnectionName != v.Expected.ConnectionName { + t.Fatalf("Expected %q but got %q for ConnectionName", v.Expected.ConnectionName, actual.ConnectionName) } } } diff --git a/azurerm/internal/services/network/parse/express_route_circuit_peering.go b/azurerm/internal/services/network/parse/express_route_circuit_peering.go new file mode 100644 index 000000000000..eb55c135d97e --- /dev/null +++ b/azurerm/internal/services/network/parse/express_route_circuit_peering.go @@ -0,0 +1,75 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type ExpressRouteCircuitPeeringId struct { + SubscriptionId string + ResourceGroup string + ExpressRouteCircuitName string + PeeringName string +} + +func NewExpressRouteCircuitPeeringID(subscriptionId, resourceGroup, expressRouteCircuitName, peeringName string) ExpressRouteCircuitPeeringId { + return ExpressRouteCircuitPeeringId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ExpressRouteCircuitName: expressRouteCircuitName, + PeeringName: peeringName, + } +} + +func (id ExpressRouteCircuitPeeringId) String() string { + segments := []string{ + fmt.Sprintf("Peering Name %q", id.PeeringName), + fmt.Sprintf("Express Route Circuit Name %q", id.ExpressRouteCircuitName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Express Route Circuit Peering", segmentsStr) +} + +func (id ExpressRouteCircuitPeeringId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/expressRouteCircuits/%s/peerings/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ExpressRouteCircuitName, id.PeeringName) +} + +// ExpressRouteCircuitPeeringID parses a ExpressRouteCircuitPeering ID into an ExpressRouteCircuitPeeringId struct +func ExpressRouteCircuitPeeringID(input string) (*ExpressRouteCircuitPeeringId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := ExpressRouteCircuitPeeringId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.ExpressRouteCircuitName, err = id.PopSegment("expressRouteCircuits"); err != nil { + return nil, err + } + if resourceId.PeeringName, err = id.PopSegment("peerings"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/azurerm/internal/services/network/parse/express_route_circuit_peering_test.go b/azurerm/internal/services/network/parse/express_route_circuit_peering_test.go new file mode 100644 index 000000000000..39b00756af4b --- /dev/null +++ b/azurerm/internal/services/network/parse/express_route_circuit_peering_test.go @@ -0,0 +1,128 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) + +var _ resourceid.Formatter = ExpressRouteCircuitPeeringId{} + +func TestExpressRouteCircuitPeeringIDFormatter(t *testing.T) { + actual := NewExpressRouteCircuitPeeringID("12345678-1234-9876-4563-123456789012", "resGroup1", "erCircuit1", "peering1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/erCircuit1/peerings/peering1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestExpressRouteCircuitPeeringID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *ExpressRouteCircuitPeeringId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ExpressRouteCircuitName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", + Error: true, + }, + + { + // missing value for ExpressRouteCircuitName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/", + Error: true, + }, + + { + // missing PeeringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/erCircuit1/", + Error: true, + }, + + { + // missing value for PeeringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/erCircuit1/peerings/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/erCircuit1/peerings/peering1", + Expected: &ExpressRouteCircuitPeeringId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ExpressRouteCircuitName: "erCircuit1", + PeeringName: "peering1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/EXPRESSROUTECIRCUITS/ERCIRCUIT1/PEERINGS/PEERING1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := ExpressRouteCircuitPeeringID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ExpressRouteCircuitName != v.Expected.ExpressRouteCircuitName { + t.Fatalf("Expected %q but got %q for ExpressRouteCircuitName", v.Expected.ExpressRouteCircuitName, actual.ExpressRouteCircuitName) + } + if actual.PeeringName != v.Expected.PeeringName { + t.Fatalf("Expected %q but got %q for PeeringName", v.Expected.PeeringName, actual.PeeringName) + } + } +} diff --git a/azurerm/internal/services/network/registration.go b/azurerm/internal/services/network/registration.go index 3d15483c6feb..ba96cba1ea0d 100644 --- a/azurerm/internal/services/network/registration.go +++ b/azurerm/internal/services/network/registration.go @@ -24,7 +24,6 @@ func (r Registration) SupportedDataSources() map[string]*schema.Resource { "azurerm_application_gateway": dataSourceApplicationGateway(), "azurerm_application_security_group": dataSourceApplicationSecurityGroup(), "azurerm_express_route_circuit": dataSourceExpressRouteCircuit(), - "azurerm_express_route_circuit_connection": dataSourceExpressRouteCircuitConnection(), "azurerm_ip_group": dataSourceIpGroup(), "azurerm_nat_gateway": dataSourceNatGateway(), "azurerm_network_ddos_protection_plan": dataSourceNetworkDDoSProtectionPlan(), diff --git a/azurerm/internal/services/network/resourceids.go b/azurerm/internal/services/network/resourceids.go index 965dc1514633..6a228cdd7ad7 100644 --- a/azurerm/internal/services/network/resourceids.go +++ b/azurerm/internal/services/network/resourceids.go @@ -53,3 +53,7 @@ package network // Virtual Network Gateway //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=VirtualNetworkGateway -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/virtualNetworkGateways/gw1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=VirtualNetworkGatewayIpConfiguration -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/virtualNetworkGateways/gw1/ipConfigurations/cfg1 + +// Express Route Circuit +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ExpressRouteCircuitPeering -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/erCircuit1/peerings/peering1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ExpressRouteCircuitConnection -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/connection1 diff --git a/azurerm/internal/services/network/validate/express_route_circuit_connection_id.go b/azurerm/internal/services/network/validate/express_route_circuit_connection_id.go new file mode 100644 index 000000000000..d0d72159d3a1 --- /dev/null +++ b/azurerm/internal/services/network/validate/express_route_circuit_connection_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" +) + +func ExpressRouteCircuitConnectionID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.ExpressRouteCircuitConnectionID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/azurerm/internal/services/network/validate/express_route_circuit_connection_id_test.go b/azurerm/internal/services/network/validate/express_route_circuit_connection_id_test.go new file mode 100644 index 000000000000..be46de3beee6 --- /dev/null +++ b/azurerm/internal/services/network/validate/express_route_circuit_connection_id_test.go @@ -0,0 +1,100 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestExpressRouteCircuitConnectionID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing ExpressRouteCircuitName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", + Valid: false, + }, + + { + // missing value for ExpressRouteCircuitName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/", + Valid: false, + }, + + { + // missing PeeringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/", + Valid: false, + }, + + { + // missing value for PeeringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/", + Valid: false, + }, + + { + // missing ConnectionName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/", + Valid: false, + }, + + { + // missing value for ConnectionName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/connection1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/EXPRESSROUTECIRCUITS/CIRCUIT1/PEERINGS/PEERING1/CONNECTIONS/CONNECTION1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := ExpressRouteCircuitConnectionID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/azurerm/internal/services/network/validate/express_route_circuit_peering_id.go b/azurerm/internal/services/network/validate/express_route_circuit_peering_id.go new file mode 100644 index 000000000000..15a68871c874 --- /dev/null +++ b/azurerm/internal/services/network/validate/express_route_circuit_peering_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" +) + +func ExpressRouteCircuitPeeringID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.ExpressRouteCircuitPeeringID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/azurerm/internal/services/network/validate/express_route_circuit_peering_id_test.go b/azurerm/internal/services/network/validate/express_route_circuit_peering_id_test.go new file mode 100644 index 000000000000..cb7df71488d0 --- /dev/null +++ b/azurerm/internal/services/network/validate/express_route_circuit_peering_id_test.go @@ -0,0 +1,88 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestExpressRouteCircuitPeeringID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing ExpressRouteCircuitName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", + Valid: false, + }, + + { + // missing value for ExpressRouteCircuitName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/", + Valid: false, + }, + + { + // missing PeeringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/erCircuit1/", + Valid: false, + }, + + { + // missing value for PeeringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/erCircuit1/peerings/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/erCircuit1/peerings/peering1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/EXPRESSROUTECIRCUITS/ERCIRCUIT1/PEERINGS/PEERING1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := ExpressRouteCircuitPeeringID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/website/docs/d/express_route_circuit_connection.html.markdown b/website/docs/d/express_route_circuit_connection.html.markdown deleted file mode 100644 index 0b3099c27ee9..000000000000 --- a/website/docs/d/express_route_circuit_connection.html.markdown +++ /dev/null @@ -1,47 +0,0 @@ ---- -subcategory: "Network" -layout: "azurerm" -page_title: "Azure Resource Manager: Data Source: azurerm_express_route_circuit_connection" -description: |- - Gets information about an existing network ExpressRouteCircuitConnection. ---- - -# Data Source: azurerm_express_route_circuit_connection - -Use this data source to access information about an existing network ExpressRouteCircuitConnection. - -## Example Usage - -```hcl -data "azurerm_express_route_circuit_connection" "example" { - name = "example-expressroutecircuitconnection" - resource_group_name = "existing" - circuit_name = "existing" -} - -output "id" { - value = data.azurerm_express_route_circuit_connection.example.id -} -``` - -## Arguments Reference - -The following arguments are supported: - -* `name` - (Required) The name of this network ExpressRouteCircuitConnection. - -* `resource_group_name` - (Required) The name of the Resource Group where the network ExpressRouteCircuitConnection exists. - -* `circuit_name` - (Required) The name of the express route circuit. - -## Attributes Reference - -In addition to the Arguments listed above - the following Attributes are exported: - -* `id` - The ID of the network ExpressRouteCircuitConnection. - -## Timeouts - -The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: - -* `read` - (Defaults to 5 minutes) Used when retrieving the network ExpressRouteCircuitConnection. diff --git a/website/docs/r/express_route_circuit_connections.html.markdown b/website/docs/r/express_route_circuit_connection.html.markdown similarity index 65% rename from website/docs/r/express_route_circuit_connections.html.markdown rename to website/docs/r/express_route_circuit_connection.html.markdown index 502dcda39c3c..53992470f412 100644 --- a/website/docs/r/express_route_circuit_connections.html.markdown +++ b/website/docs/r/express_route_circuit_connection.html.markdown @@ -3,23 +3,23 @@ subcategory: "Network" layout: "azurerm" page_title: "Azure Resource Manager: azurerm_express_route_circuit_connection" description: |- - Manages a network ExpressRouteCircuitConnection. + Manages an Express Route Circuit Connection. --- # azurerm_express_route_circuit_connection -Manages a network ExpressRouteCircuitConnection. +Manages an Express Route Circuit Connection. ## Example Usage ```hcl resource "azurerm_resource_group" "example" { - name = "example-network" + name = "example-resources" location = "West Europe" } resource "azurerm_express_route_circuit" "example1" { - name = "expressRoute1" + name = "example-circuit" resource_group_name = azurerm_resource_group.example.name location = azurerm_resource_group.example.location service_provider_name = "Equinix" @@ -32,14 +32,10 @@ resource "azurerm_express_route_circuit" "example1" { } allow_classic_operations = false - - tags = { - environment = "Production" - } } resource "azurerm_express_route_circuit" "example2" { - name = "expressRoute2" + name = "example-circuit2" resource_group_name = azurerm_resource_group.example.name location = azurerm_resource_group.example.location service_provider_name = "Equinix" @@ -52,10 +48,6 @@ resource "azurerm_express_route_circuit" "example2" { } allow_classic_operations = false - - tags = { - environment = "Production" - } } resource "azurerm_express_route_circuit_peering" "example1" { @@ -67,6 +59,7 @@ resource "azurerm_express_route_circuit_peering" "example1" { secondary_peer_address_prefix = "123.0.0.4/30" vlan_id = 300 } + resource "azurerm_express_route_circuit_peering" "example2" { peering_type = "AzurePrivatePeering" express_route_circuit_name = azurerm_express_route_circuit.example2.name @@ -95,47 +88,40 @@ resource "azurerm_express_route_circuit_connection" "example" { The following arguments are supported: -* `name` - (Required) The name which should be used for this network ExpressRouteCircuitConnection. Changing this forces a new network ExpressRouteCircuitConnection to be created. +* `name` - (Required) The name which should be used for this Express Route Circuit Connection. Changing this forces a new Express Route Circuit Connection to be created. -* `resource_group_name` - (Required) The name of the Resource Group where the network ExpressRouteCircuitConnection should exist. Changing this forces a new network ExpressRouteCircuitConnection to be created. +* `resource_group_name` - (Required) The name of the Resource Group where the Express Route Circuit Connection should exist. Changing this forces a new Express Route Circuit Connection to be created. -* `circuit_name` - (Required) The name of the express route circuit. Changing this forces a new network ExpressRouteCircuitConnection to be created. +* `peering_id` - (Required) The ID of the Express Route Circuit Private Peering within which this Express Route Circuit Connection should be created. -* `peering_id` - (Required) The ID of the Express Route Circuit Private Peering Resource of the circuit initiating connection. +* `peer_peering_id` - (Required) The ID of the peered Express Route Circuit Private Peering. -* `peer_peering_id` - (Required) The ID of the Express Route Circuit Private Peering Resource of the peered circuit. - -* `address_prefix` - (Required) /29 IP address space to carve out Customer addresses for tunnels. +* `address_prefix_ipv4` - (Required) The IPv4 address space to carve out customer addresses for tunnels. --- * `authorization_key` - (Optional) The authorization key. -* `ipv6circuit_connection_config` - (Optional) A `ipv6circuit_connection_config` block as defined below. - ---- - -An `ipv6circuit_connection_config` block exports the following: - -* `address_prefix` - (Optional) /125 IP address space to carve out customer addresses for global reach. +* `address_prefix_ipv6` - (Required) The IPv6 address space to carve out customer addresses for global reach. ## Attributes Reference In addition to the Arguments listed above - the following Attributes are exported: -* `id` - The ID of the network ExpressRouteCircuitConnection. +* `id` - The ID of the Express Route Circuit Connection. ## 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 network ExpressRouteCircuitConnection. -* `read` - (Defaults to 5 minutes) Used when retrieving the network ExpressRouteCircuitConnection. -* `delete` - (Defaults to 30 minutes) Used when deleting the network ExpressRouteCircuitConnection. +* `create` - (Defaults to 30 minutes) Used when creating the Express Route Circuit Connection. +* `read` - (Defaults to 5 minutes) Used when retrieving the Express Route Circuit Connection. +* `update` - (Defaults to 30 minutes) Used when updating the Express Route Circuit Connection. +* `delete` - (Defaults to 30 minutes) Used when deleting the Express Route Circuit Connection. ## Import -network ExpressRouteCircuitConnections can be imported using the `resource id`, e.g. +Express Route Circuit Connections can be imported using the `resource id`, e.g. ```shell terraform import azurerm_express_route_circuit_connection.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/connection1 From 78614dfa6d240eb066c08df4477562d19a77efff Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Mon, 19 Apr 2021 15:39:50 +0800 Subject: [PATCH 09/28] update code --- .../parse/authorization_server.go.3000707651 | 75 ------------------- ...press_route_circuit_connection_resource.go | 13 ++-- ..._route_circuit_connection_resource_test.go | 57 ++++++-------- ...ess_route_circuit_connection.html.markdown | 26 +++---- 4 files changed, 39 insertions(+), 132 deletions(-) delete mode 100644 azurerm/internal/services/apimanagement/parse/authorization_server.go.3000707651 diff --git a/azurerm/internal/services/apimanagement/parse/authorization_server.go.3000707651 b/azurerm/internal/services/apimanagement/parse/authorization_server.go.3000707651 deleted file mode 100644 index c6aba6127c9a..000000000000 --- a/azurerm/internal/services/apimanagement/parse/authorization_server.go.3000707651 +++ /dev/null @@ -1,75 +0,0 @@ -package parse - -// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten - -import ( - "fmt" - "strings" - - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" -) - -type AuthorizationServerId struct { - SubscriptionId string - ResourceGroup string - ServiceName string - Name string -} - -func NewAuthorizationServerID(subscriptionId, resourceGroup, serviceName, name string) AuthorizationServerId { - return AuthorizationServerId{ - SubscriptionId: subscriptionId, - ResourceGroup: resourceGroup, - ServiceName: serviceName, - Name: name, - } -} - -func (id AuthorizationServerId) String() string { - segments := []string{ - fmt.Sprintf("Name %q", id.Name), - fmt.Sprintf("Service Name %q", id.ServiceName), - fmt.Sprintf("Resource Group %q", id.ResourceGroup), - } - segmentsStr := strings.Join(segments, " / ") - return fmt.Sprintf("%s: (%s)", "Authorization Server", segmentsStr) -} - -func (id AuthorizationServerId) ID() string { - fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.ApiManagement/service/%s/authorizationServers/%s" - return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServiceName, id.Name) -} - -// AuthorizationServerID parses a AuthorizationServer ID into an AuthorizationServerId struct -func AuthorizationServerID(input string) (*AuthorizationServerId, error) { - id, err := azure.ParseAzureResourceID(input) - if err != nil { - return nil, err - } - - resourceId := AuthorizationServerId{ - SubscriptionId: id.SubscriptionID, - ResourceGroup: id.ResourceGroup, - } - - if resourceId.SubscriptionId == "" { - return nil, fmt.Errorf("ID was missing the 'subscriptions' element") - } - - if resourceId.ResourceGroup == "" { - return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") - } - - if resourceId.ServiceName, err = id.PopSegment("service"); err != nil { - return nil, err - } - if resourceId.Name, err = id.PopSegment("authorizationServers"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &resourceId, nil -} diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource.go b/azurerm/internal/services/network/express_route_circuit_connection_resource.go index 74c82d7cf626..cdd1b93a0271 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource.go @@ -8,7 +8,6 @@ import ( "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-05-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/tf" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" @@ -45,8 +44,6 @@ func resourceExpressRouteCircuitConnection() *schema.Resource { ValidateFunc: validation.StringIsNotEmpty, }, - "resource_group_name": azure.SchemaResourceGroupName(), - "peering_id": { Type: schema.TypeString, Required: true, @@ -83,7 +80,6 @@ func resourceExpressRouteCircuitConnection() *schema.Resource { } func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, meta interface{}) error { - subscriptionId := meta.(*clients.Client).Account.SubscriptionId client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -93,7 +89,7 @@ func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, m return err } - id := parse.NewExpressRouteCircuitConnectionID(subscriptionId, d.Get("resource_group_name").(string), expressRouteCircuitPeeringId.ExpressRouteCircuitName, "AzurePrivatePeering", d.Get("name").(string)) + id := parse.NewExpressRouteCircuitConnectionID(expressRouteCircuitPeeringId.SubscriptionId, expressRouteCircuitPeeringId.ResourceGroup, expressRouteCircuitPeeringId.ExpressRouteCircuitName, "AzurePrivatePeering", d.Get("name").(string)) if d.IsNewResource() { existing, err := client.Get(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, "AzurePrivatePeering", id.ConnectionName) @@ -102,6 +98,7 @@ func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, m return fmt.Errorf("checking for existing %s: %+v", id, err) } } + if !utils.ResponseWasNotFound(existing.Response) { return tf.ImportAsExistsError("azurerm_express_route_circuit_connection", id.ID()) } @@ -132,11 +129,11 @@ func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, m future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, "AzurePrivatePeering", id.ConnectionName, expressRouteCircuitConnectionParameters) if err != nil { - return fmt.Errorf("creating/updating ExpressRouteCircuitConnection %q (Resource Group %q / circuitName %q): %+v", id.ConnectionName, id.ResourceGroup, id.ExpressRouteCircuitName, err) + return fmt.Errorf("creating/updating %s: %+v", id, err) } if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation of %s: %+v", id, err) + return fmt.Errorf("waiting for creation/update of %s: %+v", id, err) } d.SetId(id.ID()) @@ -163,8 +160,8 @@ func resourceExpressRouteCircuitConnectionRead(d *schema.ResourceData, meta inte } return fmt.Errorf("retrieving %s: %+v", *id, err) } + d.Set("name", id.ConnectionName) - d.Set("resource_group_name", id.ResourceGroup) d.Set("peering_id", parse.NewExpressRouteCircuitPeeringID(id.SubscriptionId, id.ResourceGroup, id.ExpressRouteCircuitName, "AzurePrivatePeering").ID()) if peerExpressRouteCircuitPeering := resp.PeerExpressRouteCircuitPeering; peerExpressRouteCircuitPeering != nil && peerExpressRouteCircuitPeering.ID != nil { diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go index d8bc8ca47cb7..478d6acdbd8f 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go @@ -18,8 +18,7 @@ import ( type ExpressRouteCircuitConnectionResource struct{} func TestAccExpressRouteCircuitConnection_basic(t *testing.T) { - if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || - os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { + if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") return } @@ -78,8 +77,7 @@ func TestAccExpressRouteCircuitConnection_complete(t *testing.T) { } func TestAccExpressRouteCircuitConnection_update(t *testing.T) { - if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || - os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { + if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") return } @@ -111,9 +109,8 @@ func TestAccExpressRouteCircuitConnection_update(t *testing.T) { }) } -func TestAccExpressRouteCircuitConnection_updateIpv6CircuitConnectionConfig(t *testing.T) { - if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || - os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { +func TestAccExpressRouteCircuitConnection_updateAddressPrefixIPv6(t *testing.T) { + if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") return } @@ -129,7 +126,7 @@ func TestAccExpressRouteCircuitConnection_updateIpv6CircuitConnectionConfig(t *t }, data.ImportStep(), { - Config: r.updateIpv6CircuitConnectionConfig(data), + Config: r.updateAddressPrefixIPv6(data), Check: resource.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), @@ -143,79 +140,73 @@ func (r ExpressRouteCircuitConnectionResource) Exists(ctx context.Context, clien if err != nil { return nil, err } + resp, err := client.Network.ExpressRouteCircuitConnectionClient.Get(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, id.PeeringName, id.ConnectionName) if err != nil { if utils.ResponseWasNotFound(resp.Response) { return utils.Bool(false), nil } + return nil, fmt.Errorf("retrieving %s: %+v", *id, err) } + return utils.Bool(true), nil } func (r ExpressRouteCircuitConnectionResource) basic(data acceptance.TestData) string { - rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") - - return fmt.Sprintf(`%s + return fmt.Sprintf(` +%s resource "azurerm_express_route_circuit_connection" "test" { - name = "acctest-nercc-%d" - resource_group_name = "%s" + name = "acctest-ExpressRouteCircuitConn-%d" peering_id = azurerm_express_route_circuit_peering.test.id peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id address_prefix_ipv4 = "192.169.8.0/29" } -`, r.template(), data.RandomInteger, rg) +`, r.template(), data.RandomInteger) } func (r ExpressRouteCircuitConnectionResource) requiresImport(data acceptance.TestData) string { - config := r.basic(data) - return fmt.Sprintf(`%s + return fmt.Sprintf(` +%s resource "azurerm_express_route_circuit_connection" "import" { name = azurerm_express_route_circuit_connection.test.name - resource_group_name = azurerm_express_route_circuit_connection.test.resource_group_name peering_id = azurerm_express_route_circuit_peering.test.id peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id address_prefix_ipv4 = azurerm_express_route_circuit_connection.test.address_prefix } -`, config) +`, r.basic(data)) } func (r ExpressRouteCircuitConnectionResource) complete(data acceptance.TestData) string { - rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") - - template := r.template() - return fmt.Sprintf(`%s + return fmt.Sprintf(` +%s resource "azurerm_express_route_circuit_connection" "test" { - name = "acctest-nercc-%d" - resource_group_name = "%s" + name = "acctest-ExpressRouteCircuitConn-%d" peering_id = azurerm_express_route_circuit_peering.test.id peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id address_prefix_ipv4 = "192.169.8.0/29" authorization_key = "946a1918-b7a2-4917-b43c-8c4cdaee006a" address_prefix_ipv6 = "aa:bb::/125" } -`, template, data.RandomInteger, rg) +`, r.template(), data.RandomInteger) } -func (r ExpressRouteCircuitConnectionResource) updateIpv6CircuitConnectionConfig(data acceptance.TestData) string { - rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") - - template := r.template() - return fmt.Sprintf(`%s +func (r ExpressRouteCircuitConnectionResource) updateAddressPrefixIPv6(data acceptance.TestData) string { + return fmt.Sprintf(` +%s resource "azurerm_express_route_circuit_connection" "test" { - name = "acctest-nercc-%d" - resource_group_name = "%s" + name = "acctest-ExpressRouteCircuitConn-%d" peering_id = azurerm_express_route_circuit_peering.test.id peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id address_prefix_ipv4 = "192.169.8.0/29" authorization_key = "946a1918-b7a2-4917-b43c-8c4cdaee006a" address_prefix_ipv6 = "aa:bb::/125" } -`, template, data.RandomInteger, rg) +`, r.template(), data.RandomInteger) } func (r ExpressRouteCircuitConnectionResource) template() string { diff --git a/website/docs/r/express_route_circuit_connection.html.markdown b/website/docs/r/express_route_circuit_connection.html.markdown index 53992470f412..ee36f971577a 100644 --- a/website/docs/r/express_route_circuit_connection.html.markdown +++ b/website/docs/r/express_route_circuit_connection.html.markdown @@ -18,7 +18,7 @@ resource "azurerm_resource_group" "example" { location = "West Europe" } -resource "azurerm_express_route_circuit" "example1" { +resource "azurerm_express_route_circuit" "example" { name = "example-circuit" resource_group_name = azurerm_resource_group.example.name location = azurerm_resource_group.example.location @@ -50,9 +50,9 @@ resource "azurerm_express_route_circuit" "example2" { allow_classic_operations = false } -resource "azurerm_express_route_circuit_peering" "example1" { +resource "azurerm_express_route_circuit_peering" "example" { peering_type = "AzurePrivatePeering" - express_route_circuit_name = azurerm_express_route_circuit.example1.name + express_route_circuit_name = azurerm_express_route_circuit.example.name resource_group_name = azurerm_resource_group.example.name peer_asn = 100 primary_peer_address_prefix = "123.0.0.0/30" @@ -71,16 +71,12 @@ resource "azurerm_express_route_circuit_peering" "example2" { } resource "azurerm_express_route_circuit_connection" "example" { - name = "example-expressroutecircuitconnection" - resource_group_name = azurerm_resource_group.example.name - circuit_name = azurerm_express_route_circuit.example1.name - peering_id = azurerm_express_route_circuit_peering.example1.id + name = "example-expressroutecircuitconn" + peering_id = azurerm_express_route_circuit_peering.example.id peer_peering_id = azurerm_express_route_circuit_peering.example2.id - address_prefix = "192.169.8.0/29" + address_prefix_ipv4 = "192.169.8.0/29" authorization_key = "00000000-0000-0000-0000-000000000000" - ipv6circuit_connection_config { - address_prefix = "2002:db01::/125" - } + address_prefix_ipv6 = "2002:db01::/125" } ``` @@ -90,17 +86,15 @@ The following arguments are supported: * `name` - (Required) The name which should be used for this Express Route Circuit Connection. Changing this forces a new Express Route Circuit Connection to be created. -* `resource_group_name` - (Required) The name of the Resource Group where the Express Route Circuit Connection should exist. Changing this forces a new Express Route Circuit Connection to be created. - -* `peering_id` - (Required) The ID of the Express Route Circuit Private Peering within which this Express Route Circuit Connection should be created. +* `peering_id` - (Required) The ID of the Express Route Circuit Private Peering within which this Express Route Circuit Connection should be created. Changing this forces a new Express Route Circuit Connection to be created. -* `peer_peering_id` - (Required) The ID of the peered Express Route Circuit Private Peering. +* `peer_peering_id` - (Required) The ID of the peered Express Route Circuit Private Peering. Changing this forces a new Express Route Circuit Connection to be created. * `address_prefix_ipv4` - (Required) The IPv4 address space to carve out customer addresses for tunnels. --- -* `authorization_key` - (Optional) The authorization key. +* `authorization_key` - (Optional) The authorization key which is associated with the Express Route Circuit Connection. * `address_prefix_ipv6` - (Required) The IPv6 address space to carve out customer addresses for global reach. From 32ad5610cbd8ac7de959cd51d9672d4cbe8e84d7 Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Mon, 19 Apr 2021 15:46:34 +0800 Subject: [PATCH 10/28] update code --- .../network/express_route_circuit_connection_resource.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource.go b/azurerm/internal/services/network/express_route_circuit_connection_resource.go index cdd1b93a0271..c4a00f1c7420 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource.go @@ -164,13 +164,16 @@ func resourceExpressRouteCircuitConnectionRead(d *schema.ResourceData, meta inte d.Set("name", id.ConnectionName) d.Set("peering_id", parse.NewExpressRouteCircuitPeeringID(id.SubscriptionId, id.ResourceGroup, id.ExpressRouteCircuitName, "AzurePrivatePeering").ID()) - if peerExpressRouteCircuitPeering := resp.PeerExpressRouteCircuitPeering; peerExpressRouteCircuitPeering != nil && peerExpressRouteCircuitPeering.ID != nil { - d.Set("peer_peering_id", peerExpressRouteCircuitPeering.ID) + if resp.PeerExpressRouteCircuitPeering != nil && resp.PeerExpressRouteCircuitPeering.ID != nil { + d.Set("peer_peering_id", resp.PeerExpressRouteCircuitPeering.ID) } if props := resp.ExpressRouteCircuitConnectionPropertiesFormat; props != nil { d.Set("address_prefix_ipv4", props.AddressPrefix) - d.Set("authorization_key", props.AuthorizationKey) + + if props.AuthorizationKey != nil { + d.Set("authorization_key", props.AuthorizationKey) + } if props.Ipv6CircuitConnectionConfig != nil && props.Ipv6CircuitConnectionConfig.AddressPrefix != nil { d.Set("address_prefix_ipv6", props.Ipv6CircuitConnectionConfig.AddressPrefix) From 4eba331e88bcdfd3b728809e6a6b160715542a09 Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Mon, 19 Apr 2021 16:17:13 +0800 Subject: [PATCH 11/28] update code --- ...press_route_circuit_connection_resource.go | 9 +- .../express_route_circuit_connection_name.go | 21 +++++ .../express_route_circuit_connection_test.go | 86 +++++++++++++++++++ 3 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 azurerm/internal/services/network/validate/express_route_circuit_connection_name.go create mode 100644 azurerm/internal/services/network/validate/express_route_circuit_connection_test.go diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource.go b/azurerm/internal/services/network/express_route_circuit_connection_resource.go index c4a00f1c7420..f9334cb2fb96 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource.go @@ -41,7 +41,7 @@ func resourceExpressRouteCircuitConnection() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: validation.StringIsNotEmpty, + ValidateFunc: validate.ExpressRouteCircuitConnectionName, }, "peering_id": { @@ -65,9 +65,10 @@ func resourceExpressRouteCircuitConnection() *schema.Resource { }, "authorization_key": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, + Type: schema.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.IsUUID, }, "address_prefix_ipv6": { diff --git a/azurerm/internal/services/network/validate/express_route_circuit_connection_name.go b/azurerm/internal/services/network/validate/express_route_circuit_connection_name.go new file mode 100644 index 000000000000..099c07792c03 --- /dev/null +++ b/azurerm/internal/services/network/validate/express_route_circuit_connection_name.go @@ -0,0 +1,21 @@ +package validate + +import ( + "fmt" + "regexp" +) + +func ExpressRouteCircuitConnectionName(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) + return + } + + if !regexp.MustCompile(`^(([a-zA-Z0-9])|([a-zA-Z0-9][a-zA-Z0-9_.-]{0,78}[a-zA-Z0-9_]))$`).MatchString(v) { + errors = append(errors, fmt.Errorf("%q must be between 1 and 80 characters in length and must begin with a letter or number, end with a letter, number or underscore, and may contain only letters, numbers, underscores, periods, or hyphens", k)) + return + } + + return +} diff --git a/azurerm/internal/services/network/validate/express_route_circuit_connection_test.go b/azurerm/internal/services/network/validate/express_route_circuit_connection_test.go new file mode 100644 index 000000000000..bff150935ea7 --- /dev/null +++ b/azurerm/internal/services/network/validate/express_route_circuit_connection_test.go @@ -0,0 +1,86 @@ +package validate + +import ( + "strings" + "testing" +) + +func TestExpressRouteCircuitConnectionName(t *testing.T) { + testCases := []struct { + Input string + Expected bool + }{ + { + Input: "", + Expected: false, + }, + { + Input: "a", + Expected: true, + }, + { + Input: "2", + Expected: true, + }, + { + Input: "_", + Expected: false, + }, + { + Input: "a_", + Expected: true, + }, + { + Input: "2_", + Expected: true, + }, + { + Input: "_a", + Expected: false, + }, + { + Input: "1a", + Expected: true, + }, + { + Input: "a2", + Expected: true, + }, + { + Input: "a-", + Expected: false, + }, + { + Input: "a-b", + Expected: true, + }, + { + Input: "a.b", + Expected: true, + }, + { + Input: "Test", + Expected: true, + }, + { + Input: strings.Repeat("s", 79), + Expected: true, + }, + { + Input: strings.Repeat("s", 80), + Expected: true, + }, + { + Input: strings.Repeat("s", 81), + Expected: false, + }, + } + + for _, v := range testCases { + _, errors := ExpressRouteCircuitConnectionName(v.Input, "name") + result := len(errors) == 0 + if result != v.Expected { + t.Fatalf("Expected the result to be %t but got %t (and %d errors)", v.Expected, result, len(errors)) + } + } +} From a8193454c6977a496642422470ba0a6e5300b3a3 Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Tue, 20 Apr 2021 12:37:51 +0800 Subject: [PATCH 12/28] update code --- ...press_route_circuit_connection_resource.go | 4 ++++ ..._route_circuit_connection_resource_test.go | 22 +++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource.go b/azurerm/internal/services/network/express_route_circuit_connection_resource.go index f9334cb2fb96..388be4c0ce33 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource.go @@ -174,10 +174,14 @@ func resourceExpressRouteCircuitConnectionRead(d *schema.ResourceData, meta inte if props.AuthorizationKey != nil { d.Set("authorization_key", props.AuthorizationKey) + } else { + d.Set("authorization_key", "") } if props.Ipv6CircuitConnectionConfig != nil && props.Ipv6CircuitConnectionConfig.AddressPrefix != nil { d.Set("address_prefix_ipv6", props.Ipv6CircuitConnectionConfig.AddressPrefix) + } else { + d.Set("address_prefix_ipv6", "") } } diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go index 478d6acdbd8f..6a49da1de2a3 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go @@ -72,7 +72,7 @@ func TestAccExpressRouteCircuitConnection_complete(t *testing.T) { check.That(data.ResourceName).ExistsInAzure(r), ), }, - data.ImportStep("authorization_key"), + data.ImportStep(), }) } @@ -98,14 +98,14 @@ func TestAccExpressRouteCircuitConnection_update(t *testing.T) { check.That(data.ResourceName).ExistsInAzure(r), ), }, - data.ImportStep("authorization_key"), + data.ImportStep(), { Config: r.basic(data), Check: resource.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, - data.ImportStep("authorization_key"), + data.ImportStep(), }) } @@ -172,9 +172,9 @@ func (r ExpressRouteCircuitConnectionResource) requiresImport(data acceptance.Te resource "azurerm_express_route_circuit_connection" "import" { name = azurerm_express_route_circuit_connection.test.name - peering_id = azurerm_express_route_circuit_peering.test.id - peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id - address_prefix_ipv4 = azurerm_express_route_circuit_connection.test.address_prefix + peering_id = azurerm_express_route_circuit_connection.test.peering_id + peer_peering_id = azurerm_express_route_circuit_connection.test.peer_peering_id + address_prefix_ipv4 = azurerm_express_route_circuit_connection.test.address_prefix_ipv4 } `, r.basic(data)) } @@ -187,8 +187,8 @@ resource "azurerm_express_route_circuit_connection" "test" { name = "acctest-ExpressRouteCircuitConn-%d" peering_id = azurerm_express_route_circuit_peering.test.id peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id - address_prefix_ipv4 = "192.169.8.0/29" - authorization_key = "946a1918-b7a2-4917-b43c-8c4cdaee006a" + address_prefix_ipv4 = "192.169.9.0/29" + authorization_key = "846a1918-b7a2-4917-b43c-8c4cdaee006a" address_prefix_ipv6 = "aa:bb::/125" } `, r.template(), data.RandomInteger) @@ -202,9 +202,9 @@ resource "azurerm_express_route_circuit_connection" "test" { name = "acctest-ExpressRouteCircuitConn-%d" peering_id = azurerm_express_route_circuit_peering.test.id peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id - address_prefix_ipv4 = "192.169.8.0/29" - authorization_key = "946a1918-b7a2-4917-b43c-8c4cdaee006a" - address_prefix_ipv6 = "aa:bb::/125" + address_prefix_ipv4 = "192.169.9.0/29" + authorization_key = "846a1918-b7a2-4917-b43c-8c4cdaee006a" + address_prefix_ipv6 = "aa:cc::/125" } `, r.template(), data.RandomInteger) } From 10409c60a7b4a2ac97e222f29c1f5b8414d0c5c7 Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Tue, 15 Jun 2021 15:13:17 +0800 Subject: [PATCH 13/28] update code --- .../express_route_circuit_connection_resource.go | 16 ++++++++-------- ...xpress_route_circuit_connection.html.markdown | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource.go b/azurerm/internal/services/network/express_route_circuit_connection_resource.go index 388be4c0ce33..fc220239dc97 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource.go @@ -90,10 +90,10 @@ func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, m return err } - id := parse.NewExpressRouteCircuitConnectionID(expressRouteCircuitPeeringId.SubscriptionId, expressRouteCircuitPeeringId.ResourceGroup, expressRouteCircuitPeeringId.ExpressRouteCircuitName, "AzurePrivatePeering", d.Get("name").(string)) + id := parse.NewExpressRouteCircuitConnectionID(expressRouteCircuitPeeringId.SubscriptionId, expressRouteCircuitPeeringId.ResourceGroup, expressRouteCircuitPeeringId.ExpressRouteCircuitName, string(network.AzurePrivatePeering), d.Get("name").(string)) if d.IsNewResource() { - existing, err := client.Get(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, "AzurePrivatePeering", id.ConnectionName) + existing, err := client.Get(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, string(network.AzurePrivatePeering), id.ConnectionName) if err != nil { if !utils.ResponseWasNotFound(existing.Response) { return fmt.Errorf("checking for existing %s: %+v", id, err) @@ -128,7 +128,7 @@ func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, m } } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, "AzurePrivatePeering", id.ConnectionName, expressRouteCircuitConnectionParameters) + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, string(network.AzurePrivatePeering), id.ConnectionName, expressRouteCircuitConnectionParameters) if err != nil { return fmt.Errorf("creating/updating %s: %+v", id, err) } @@ -163,11 +163,7 @@ func resourceExpressRouteCircuitConnectionRead(d *schema.ResourceData, meta inte } d.Set("name", id.ConnectionName) - d.Set("peering_id", parse.NewExpressRouteCircuitPeeringID(id.SubscriptionId, id.ResourceGroup, id.ExpressRouteCircuitName, "AzurePrivatePeering").ID()) - - if resp.PeerExpressRouteCircuitPeering != nil && resp.PeerExpressRouteCircuitPeering.ID != nil { - d.Set("peer_peering_id", resp.PeerExpressRouteCircuitPeering.ID) - } + d.Set("peering_id", parse.NewExpressRouteCircuitPeeringID(id.SubscriptionId, id.ResourceGroup, id.ExpressRouteCircuitName, string(network.AzurePrivatePeering)).ID()) if props := resp.ExpressRouteCircuitConnectionPropertiesFormat; props != nil { d.Set("address_prefix_ipv4", props.AddressPrefix) @@ -183,6 +179,10 @@ func resourceExpressRouteCircuitConnectionRead(d *schema.ResourceData, meta inte } else { d.Set("address_prefix_ipv6", "") } + + if props.PeerExpressRouteCircuitPeering != nil && props.PeerExpressRouteCircuitPeering.ID != nil { + d.Set("peer_peering_id", resp.PeerExpressRouteCircuitPeering.ID) + } } return nil diff --git a/website/docs/r/express_route_circuit_connection.html.markdown b/website/docs/r/express_route_circuit_connection.html.markdown index ee36f971577a..c558d0312e11 100644 --- a/website/docs/r/express_route_circuit_connection.html.markdown +++ b/website/docs/r/express_route_circuit_connection.html.markdown @@ -96,7 +96,7 @@ The following arguments are supported: * `authorization_key` - (Optional) The authorization key which is associated with the Express Route Circuit Connection. -* `address_prefix_ipv6` - (Required) The IPv6 address space to carve out customer addresses for global reach. +* `address_prefix_ipv6` - (Optional) The IPv6 address space from which to allocate customer addresses for global reach. ## Attributes Reference From 84da7565622149d6194d2711e5ab2d9a0755e3e9 Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Tue, 15 Jun 2021 15:55:00 +0800 Subject: [PATCH 14/28] update code --- .../express_route_circuit_connection_resource.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource.go b/azurerm/internal/services/network/express_route_circuit_connection_resource.go index fc220239dc97..e9fdb0c1468b 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource.go @@ -5,7 +5,7 @@ import ( "log" "time" - "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-05-01/network" + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-11-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/tf" @@ -90,10 +90,10 @@ func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, m return err } - id := parse.NewExpressRouteCircuitConnectionID(expressRouteCircuitPeeringId.SubscriptionId, expressRouteCircuitPeeringId.ResourceGroup, expressRouteCircuitPeeringId.ExpressRouteCircuitName, string(network.AzurePrivatePeering), d.Get("name").(string)) + id := parse.NewExpressRouteCircuitConnectionID(expressRouteCircuitPeeringId.SubscriptionId, expressRouteCircuitPeeringId.ResourceGroup, expressRouteCircuitPeeringId.ExpressRouteCircuitName, string(network.ExpressRoutePeeringTypeAzurePrivatePeering), d.Get("name").(string)) if d.IsNewResource() { - existing, err := client.Get(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, string(network.AzurePrivatePeering), id.ConnectionName) + existing, err := client.Get(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, string(network.ExpressRoutePeeringTypeAzurePrivatePeering), id.ConnectionName) if err != nil { if !utils.ResponseWasNotFound(existing.Response) { return fmt.Errorf("checking for existing %s: %+v", id, err) @@ -128,7 +128,7 @@ func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, m } } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, string(network.AzurePrivatePeering), id.ConnectionName, expressRouteCircuitConnectionParameters) + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, string(network.ExpressRoutePeeringTypeAzurePrivatePeering), id.ConnectionName, expressRouteCircuitConnectionParameters) if err != nil { return fmt.Errorf("creating/updating %s: %+v", id, err) } @@ -163,7 +163,7 @@ func resourceExpressRouteCircuitConnectionRead(d *schema.ResourceData, meta inte } d.Set("name", id.ConnectionName) - d.Set("peering_id", parse.NewExpressRouteCircuitPeeringID(id.SubscriptionId, id.ResourceGroup, id.ExpressRouteCircuitName, string(network.AzurePrivatePeering)).ID()) + d.Set("peering_id", parse.NewExpressRouteCircuitPeeringID(id.SubscriptionId, id.ResourceGroup, id.ExpressRouteCircuitName, string(network.ExpressRoutePeeringTypeAzurePrivatePeering)).ID()) if props := resp.ExpressRouteCircuitConnectionPropertiesFormat; props != nil { d.Set("address_prefix_ipv4", props.AddressPrefix) From 68b41134936077166a6f84e31905e5052a62724c Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Tue, 15 Jun 2021 17:13:12 +0800 Subject: [PATCH 15/28] update code --- ...press_route_circuit_connection_resource.go | 73 +++++++++++++++---- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource.go b/azurerm/internal/services/network/express_route_circuit_connection_resource.go index e9fdb0c1468b..0374315c74bf 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource.go @@ -19,9 +19,9 @@ import ( func resourceExpressRouteCircuitConnection() *schema.Resource { return &schema.Resource{ - Create: resourceExpressRouteCircuitConnectionCreateUpdate, + Create: resourceExpressRouteCircuitConnectionCreate, Read: resourceExpressRouteCircuitConnectionRead, - Update: resourceExpressRouteCircuitConnectionCreateUpdate, + Update: resourceExpressRouteCircuitConnectionUpdate, Delete: resourceExpressRouteCircuitConnectionDelete, Timeouts: &schema.ResourceTimeout{ @@ -80,9 +80,9 @@ func resourceExpressRouteCircuitConnection() *schema.Resource { } } -func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceExpressRouteCircuitConnectionCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient - ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() expressRouteCircuitPeeringId, err := parse.ExpressRouteCircuitPeeringID(d.Get("peering_id").(string)) @@ -92,19 +92,17 @@ func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, m id := parse.NewExpressRouteCircuitConnectionID(expressRouteCircuitPeeringId.SubscriptionId, expressRouteCircuitPeeringId.ResourceGroup, expressRouteCircuitPeeringId.ExpressRouteCircuitName, string(network.ExpressRoutePeeringTypeAzurePrivatePeering), d.Get("name").(string)) - if d.IsNewResource() { - existing, err := client.Get(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, string(network.ExpressRoutePeeringTypeAzurePrivatePeering), id.ConnectionName) - if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("checking for existing %s: %+v", id, err) - } - } - + existing, err := client.Get(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, string(network.ExpressRoutePeeringTypeAzurePrivatePeering), id.ConnectionName) + if err != nil { if !utils.ResponseWasNotFound(existing.Response) { - return tf.ImportAsExistsError("azurerm_express_route_circuit_connection", id.ID()) + return fmt.Errorf("checking for existing %s: %+v", id, err) } } + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_express_route_circuit_connection", id.ID()) + } + expressRouteCircuitConnectionParameters := network.ExpressRouteCircuitConnection{ Name: utils.String(id.ConnectionName), ExpressRouteCircuitConnectionPropertiesFormat: &network.ExpressRouteCircuitConnectionPropertiesFormat{ @@ -130,11 +128,11 @@ func resourceExpressRouteCircuitConnectionCreateUpdate(d *schema.ResourceData, m future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, string(network.ExpressRoutePeeringTypeAzurePrivatePeering), id.ConnectionName, expressRouteCircuitConnectionParameters) if err != nil { - return fmt.Errorf("creating/updating %s: %+v", id, err) + return fmt.Errorf("creating %s: %+v", id, err) } if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation/update of %s: %+v", id, err) + return fmt.Errorf("waiting for creation of %s: %+v", id, err) } d.SetId(id.ID()) @@ -188,6 +186,51 @@ func resourceExpressRouteCircuitConnectionRead(d *schema.ResourceData, meta inte return nil } +func resourceExpressRouteCircuitConnectionUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient + ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ExpressRouteCircuitConnectionID(d.Id()) + if err != nil { + return err + } + + expressRouteCircuitConnectionParameters := network.ExpressRouteCircuitConnection{ + Name: utils.String(id.ConnectionName), + ExpressRouteCircuitConnectionPropertiesFormat: &network.ExpressRouteCircuitConnectionPropertiesFormat{ + AddressPrefix: utils.String(d.Get("address_prefix_ipv4").(string)), + ExpressRouteCircuitPeering: &network.SubResource{ + ID: utils.String(d.Get("peering_id").(string)), + }, + PeerExpressRouteCircuitPeering: &network.SubResource{ + ID: utils.String(d.Get("peer_peering_id").(string)), + }, + }, + } + + if v, ok := d.GetOk("authorization_key"); ok { + expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.AuthorizationKey = utils.String(v.(string)) + } + + if v, ok := d.GetOk("address_prefix_ipv6"); ok { + expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.Ipv6CircuitConnectionConfig = &network.Ipv6CircuitConnectionConfig{ + AddressPrefix: utils.String(v.(string)), + } + } + + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, string(network.ExpressRoutePeeringTypeAzurePrivatePeering), id.ConnectionName, expressRouteCircuitConnectionParameters) + if err != nil { + return fmt.Errorf("updating %s: %+v", id, err) + } + + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for update of %s: %+v", id, err) + } + + return resourceExpressRouteCircuitConnectionRead(d, meta) +} + func resourceExpressRouteCircuitConnectionDelete(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) From 3f1ae941de9e0533e80dce55fccaf2a5e7e97bf8 Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Thu, 17 Jun 2021 14:09:16 +0800 Subject: [PATCH 16/28] update code --- ...press_route_circuit_connection_resource.go | 93 +++++++++++-------- ..._route_circuit_connection_resource_test.go | 33 +++---- ...ess_route_circuit_connection.html.markdown | 6 +- 3 files changed, 72 insertions(+), 60 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource.go b/azurerm/internal/services/network/express_route_circuit_connection_resource.go index 0374315c74bf..54017dd8fc13 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource.go @@ -6,73 +6,72 @@ import ( "time" "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-11-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/tf" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/validate" - azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/pluginsdk" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) -func resourceExpressRouteCircuitConnection() *schema.Resource { - return &schema.Resource{ +func resourceExpressRouteCircuitConnection() *pluginsdk.Resource { + return &pluginsdk.Resource{ Create: resourceExpressRouteCircuitConnectionCreate, Read: resourceExpressRouteCircuitConnectionRead, Update: resourceExpressRouteCircuitConnectionUpdate, Delete: resourceExpressRouteCircuitConnectionDelete, - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(30 * time.Minute), - Read: schema.DefaultTimeout(5 * time.Minute), - Update: schema.DefaultTimeout(30 * time.Minute), - Delete: schema.DefaultTimeout(30 * time.Minute), + 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: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { _, err := parse.ExpressRouteCircuitConnectionID(id) return err }), - Schema: map[string]*schema.Schema{ + Schema: map[string]*pluginsdk.Schema{ "name": { - Type: schema.TypeString, + Type: pluginsdk.TypeString, Required: true, ForceNew: true, ValidateFunc: validate.ExpressRouteCircuitConnectionName, }, "peering_id": { - Type: schema.TypeString, + Type: pluginsdk.TypeString, Required: true, ForceNew: true, ValidateFunc: validate.ExpressRouteCircuitPeeringID, }, "peer_peering_id": { - Type: schema.TypeString, + Type: pluginsdk.TypeString, Required: true, ForceNew: true, ValidateFunc: validate.ExpressRouteCircuitPeeringID, }, "address_prefix_ipv4": { - Type: schema.TypeString, + Type: pluginsdk.TypeString, Required: true, ValidateFunc: validation.IsCIDR, }, "authorization_key": { - Type: schema.TypeString, + Type: pluginsdk.TypeString, Optional: true, Sensitive: true, ValidateFunc: validation.IsUUID, }, "address_prefix_ipv6": { - Type: schema.TypeString, + Type: pluginsdk.TypeString, Optional: true, ValidateFunc: validation.IsCIDR, }, @@ -80,19 +79,19 @@ func resourceExpressRouteCircuitConnection() *schema.Resource { } } -func resourceExpressRouteCircuitConnectionCreate(d *schema.ResourceData, meta interface{}) error { +func resourceExpressRouteCircuitConnectionCreate(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - expressRouteCircuitPeeringId, err := parse.ExpressRouteCircuitPeeringID(d.Get("peering_id").(string)) + circuitPeeringId, err := parse.ExpressRouteCircuitPeeringID(d.Get("peering_id").(string)) if err != nil { return err } - id := parse.NewExpressRouteCircuitConnectionID(expressRouteCircuitPeeringId.SubscriptionId, expressRouteCircuitPeeringId.ResourceGroup, expressRouteCircuitPeeringId.ExpressRouteCircuitName, string(network.ExpressRoutePeeringTypeAzurePrivatePeering), d.Get("name").(string)) + id := parse.NewExpressRouteCircuitConnectionID(circuitPeeringId.SubscriptionId, circuitPeeringId.ResourceGroup, circuitPeeringId.ExpressRouteCircuitName, circuitPeeringId.PeeringName, d.Get("name").(string)) - existing, err := client.Get(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, string(network.ExpressRoutePeeringTypeAzurePrivatePeering), id.ConnectionName) + existing, err := client.Get(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, id.PeeringName, id.ConnectionName) if err != nil { if !utils.ResponseWasNotFound(existing.Response) { return fmt.Errorf("checking for existing %s: %+v", id, err) @@ -103,15 +102,20 @@ func resourceExpressRouteCircuitConnectionCreate(d *schema.ResourceData, meta in return tf.ImportAsExistsError("azurerm_express_route_circuit_connection", id.ID()) } + circuitPeerPeeringId, err := parse.ExpressRouteCircuitPeeringID(d.Get("peer_peering_id").(string)) + if err != nil { + return err + } + expressRouteCircuitConnectionParameters := network.ExpressRouteCircuitConnection{ Name: utils.String(id.ConnectionName), ExpressRouteCircuitConnectionPropertiesFormat: &network.ExpressRouteCircuitConnectionPropertiesFormat{ AddressPrefix: utils.String(d.Get("address_prefix_ipv4").(string)), ExpressRouteCircuitPeering: &network.SubResource{ - ID: utils.String(expressRouteCircuitPeeringId.ID()), + ID: utils.String(circuitPeeringId.ID()), }, PeerExpressRouteCircuitPeering: &network.SubResource{ - ID: utils.String(d.Get("peer_peering_id").(string)), + ID: utils.String(circuitPeerPeeringId.ID()), }, }, } @@ -126,7 +130,7 @@ func resourceExpressRouteCircuitConnectionCreate(d *schema.ResourceData, meta in } } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, string(network.ExpressRoutePeeringTypeAzurePrivatePeering), id.ConnectionName, expressRouteCircuitConnectionParameters) + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, id.PeeringName, id.ConnectionName, expressRouteCircuitConnectionParameters) if err != nil { return fmt.Errorf("creating %s: %+v", id, err) } @@ -140,7 +144,7 @@ func resourceExpressRouteCircuitConnectionCreate(d *schema.ResourceData, meta in return resourceExpressRouteCircuitConnectionRead(d, meta) } -func resourceExpressRouteCircuitConnectionRead(d *schema.ResourceData, meta interface{}) error { +func resourceExpressRouteCircuitConnectionRead(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() @@ -161,32 +165,29 @@ func resourceExpressRouteCircuitConnectionRead(d *schema.ResourceData, meta inte } d.Set("name", id.ConnectionName) - d.Set("peering_id", parse.NewExpressRouteCircuitPeeringID(id.SubscriptionId, id.ResourceGroup, id.ExpressRouteCircuitName, string(network.ExpressRoutePeeringTypeAzurePrivatePeering)).ID()) + d.Set("peering_id", parse.NewExpressRouteCircuitPeeringID(id.SubscriptionId, id.ResourceGroup, id.ExpressRouteCircuitName, id.PeeringName).ID()) if props := resp.ExpressRouteCircuitConnectionPropertiesFormat; props != nil { d.Set("address_prefix_ipv4", props.AddressPrefix) + d.Set("authorization_key", props.AuthorizationKey) - if props.AuthorizationKey != nil { - d.Set("authorization_key", props.AuthorizationKey) - } else { - d.Set("authorization_key", "") - } - - if props.Ipv6CircuitConnectionConfig != nil && props.Ipv6CircuitConnectionConfig.AddressPrefix != nil { + if props.Ipv6CircuitConnectionConfig != nil { d.Set("address_prefix_ipv6", props.Ipv6CircuitConnectionConfig.AddressPrefix) - } else { - d.Set("address_prefix_ipv6", "") } if props.PeerExpressRouteCircuitPeering != nil && props.PeerExpressRouteCircuitPeering.ID != nil { - d.Set("peer_peering_id", resp.PeerExpressRouteCircuitPeering.ID) + circuitPeerPeeringId, err := parse.ExpressRouteCircuitPeeringID(*props.PeerExpressRouteCircuitPeering.ID) + if err != nil { + return err + } + d.Set("peer_peering_id", circuitPeerPeeringId.ID()) } } return nil } -func resourceExpressRouteCircuitConnectionUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceExpressRouteCircuitConnectionUpdate(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -196,15 +197,25 @@ func resourceExpressRouteCircuitConnectionUpdate(d *schema.ResourceData, meta in return err } + circuitPeeringId, err := parse.ExpressRouteCircuitPeeringID(d.Get("peering_id").(string)) + if err != nil { + return err + } + + circuitPeerPeeringId, err := parse.ExpressRouteCircuitPeeringID(d.Get("peer_peering_id").(string)) + if err != nil { + return err + } + expressRouteCircuitConnectionParameters := network.ExpressRouteCircuitConnection{ Name: utils.String(id.ConnectionName), ExpressRouteCircuitConnectionPropertiesFormat: &network.ExpressRouteCircuitConnectionPropertiesFormat{ AddressPrefix: utils.String(d.Get("address_prefix_ipv4").(string)), ExpressRouteCircuitPeering: &network.SubResource{ - ID: utils.String(d.Get("peering_id").(string)), + ID: utils.String(circuitPeeringId.ID()), }, PeerExpressRouteCircuitPeering: &network.SubResource{ - ID: utils.String(d.Get("peer_peering_id").(string)), + ID: utils.String(circuitPeerPeeringId.ID()), }, }, } @@ -219,7 +230,7 @@ func resourceExpressRouteCircuitConnectionUpdate(d *schema.ResourceData, meta in } } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, string(network.ExpressRoutePeeringTypeAzurePrivatePeering), id.ConnectionName, expressRouteCircuitConnectionParameters) + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ExpressRouteCircuitName, id.PeeringName, id.ConnectionName, expressRouteCircuitConnectionParameters) if err != nil { return fmt.Errorf("updating %s: %+v", id, err) } @@ -231,7 +242,7 @@ func resourceExpressRouteCircuitConnectionUpdate(d *schema.ResourceData, meta in return resourceExpressRouteCircuitConnectionRead(d, meta) } -func resourceExpressRouteCircuitConnectionDelete(d *schema.ResourceData, meta interface{}) error { +func resourceExpressRouteCircuitConnectionDelete(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go index 6a49da1de2a3..efa40de09470 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go @@ -7,20 +7,19 @@ import ( "testing" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/terraform" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/pluginsdk" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) type ExpressRouteCircuitConnectionResource struct{} func TestAccExpressRouteCircuitConnection_basic(t *testing.T) { - if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { + if ok := skipExpressRouteCircuitConnection(); ok { t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") - return } data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") @@ -37,10 +36,8 @@ func TestAccExpressRouteCircuitConnection_basic(t *testing.T) { } func TestAccExpressRouteCircuitConnection_requiresImport(t *testing.T) { - if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || - os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { + if ok := skipExpressRouteCircuitConnection(); ok { t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") - return } data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") @@ -57,10 +54,8 @@ func TestAccExpressRouteCircuitConnection_requiresImport(t *testing.T) { } func TestAccExpressRouteCircuitConnection_complete(t *testing.T) { - if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || - os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { + if ok := skipExpressRouteCircuitConnection(); ok { t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") - return } data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") @@ -77,9 +72,8 @@ func TestAccExpressRouteCircuitConnection_complete(t *testing.T) { } func TestAccExpressRouteCircuitConnection_update(t *testing.T) { - if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { + if ok := skipExpressRouteCircuitConnection(); ok { t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") - return } data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") @@ -110,9 +104,8 @@ func TestAccExpressRouteCircuitConnection_update(t *testing.T) { } func TestAccExpressRouteCircuitConnection_updateAddressPrefixIPv6(t *testing.T) { - if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { + if ok := skipExpressRouteCircuitConnection(); ok { t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") - return } data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") @@ -135,7 +128,7 @@ func TestAccExpressRouteCircuitConnection_updateAddressPrefixIPv6(t *testing.T) }) } -func (r ExpressRouteCircuitConnectionResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) { +func (r ExpressRouteCircuitConnectionResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := parse.ExpressRouteCircuitConnectionID(state.ID) if err != nil { return nil, err @@ -223,7 +216,7 @@ resource "azurerm_express_route_circuit_peering" "test" { peering_type = "AzurePrivatePeering" express_route_circuit_name = "%[1]s" resource_group_name = "%[2]s" - shared_key = "SSSSsssssshhhhhItsASecret" + shared_key = "ItsASecret" peer_asn = 100 primary_peer_address_prefix = "192.168.1.0/30" secondary_peer_address_prefix = "192.168.1.0/30" @@ -234,7 +227,7 @@ resource "azurerm_express_route_circuit_peering" "peer_test" { peering_type = "AzurePrivatePeering" express_route_circuit_name = "%[3]s" resource_group_name = "%[2]s" - shared_key = "SSSSsssssshhhhhItsASecret" + shared_key = "ItsASecret" peer_asn = 100 primary_peer_address_prefix = "192.168.1.0/30" secondary_peer_address_prefix = "192.168.1.0/30" @@ -242,3 +235,11 @@ resource "azurerm_express_route_circuit_peering" "peer_test" { } `, circuitName1, rg, circuitName2) } + +func skipExpressRouteCircuitConnection() bool { + if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { + return true + } + + return false +} diff --git a/website/docs/r/express_route_circuit_connection.html.markdown b/website/docs/r/express_route_circuit_connection.html.markdown index c558d0312e11..9ec139d73671 100644 --- a/website/docs/r/express_route_circuit_connection.html.markdown +++ b/website/docs/r/express_route_circuit_connection.html.markdown @@ -86,11 +86,11 @@ The following arguments are supported: * `name` - (Required) The name which should be used for this Express Route Circuit Connection. Changing this forces a new Express Route Circuit Connection to be created. -* `peering_id` - (Required) The ID of the Express Route Circuit Private Peering within which this Express Route Circuit Connection should be created. Changing this forces a new Express Route Circuit Connection to be created. +* `peering_id` - (Required) The ID of the Express Route Circuit Private Peering that this Express Route Circuit Connection connects with. Changing this forces a new Express Route Circuit Connection to be created. * `peer_peering_id` - (Required) The ID of the peered Express Route Circuit Private Peering. Changing this forces a new Express Route Circuit Connection to be created. - -* `address_prefix_ipv4` - (Required) The IPv4 address space to carve out customer addresses for tunnels. + +* `address_prefix_ipv4` - (Required) The IPv4 address space from which to allocate customer address for global reach. --- From 80825183040107123ebebaea3709fcf8e5d30621 Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Thu, 17 Jun 2021 16:48:00 +0800 Subject: [PATCH 17/28] update code --- .../express_route_circuit_connection_resource.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource.go b/azurerm/internal/services/network/express_route_circuit_connection_resource.go index 54017dd8fc13..244f88299533 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource.go @@ -169,11 +169,18 @@ func resourceExpressRouteCircuitConnectionRead(d *pluginsdk.ResourceData, meta i if props := resp.ExpressRouteCircuitConnectionPropertiesFormat; props != nil { d.Set("address_prefix_ipv4", props.AddressPrefix) - d.Set("authorization_key", props.AuthorizationKey) - if props.Ipv6CircuitConnectionConfig != nil { - d.Set("address_prefix_ipv6", props.Ipv6CircuitConnectionConfig.AddressPrefix) + authorizationKey := "" + if props.AuthorizationKey != nil { + authorizationKey = *props.AuthorizationKey } + d.Set("authorization_key", authorizationKey) + + addressPrefixIPv6 := "" + if props.Ipv6CircuitConnectionConfig != nil && props.Ipv6CircuitConnectionConfig.AddressPrefix != nil { + addressPrefixIPv6 = *props.Ipv6CircuitConnectionConfig.AddressPrefix + } + d.Set("address_prefix_ipv6", addressPrefixIPv6) if props.PeerExpressRouteCircuitPeering != nil && props.PeerExpressRouteCircuitPeering.ID != nil { circuitPeerPeeringId, err := parse.ExpressRouteCircuitPeeringID(*props.PeerExpressRouteCircuitPeering.ID) From 1e9b435d6c73d307d1bdb5c0195497a9799679d3 Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Fri, 18 Jun 2021 13:59:09 +0800 Subject: [PATCH 18/28] update code --- ...press_route_circuit_connection_resource.go | 9 ++----- ..._route_circuit_connection_resource_test.go | 26 +++++-------------- 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource.go b/azurerm/internal/services/network/express_route_circuit_connection_resource.go index 244f88299533..be76642dad6e 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource.go @@ -6,12 +6,12 @@ import ( "time" "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-11-01/network" - "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/pluginsdk" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -169,12 +169,7 @@ func resourceExpressRouteCircuitConnectionRead(d *pluginsdk.ResourceData, meta i if props := resp.ExpressRouteCircuitConnectionPropertiesFormat; props != nil { d.Set("address_prefix_ipv4", props.AddressPrefix) - - authorizationKey := "" - if props.AuthorizationKey != nil { - authorizationKey = *props.AuthorizationKey - } - d.Set("authorization_key", authorizationKey) + d.Set("authorization_key", props.AuthorizationKey) addressPrefixIPv6 := "" if props.Ipv6CircuitConnectionConfig != nil && props.Ipv6CircuitConnectionConfig.AddressPrefix != nil { diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go index efa40de09470..7a251ddb2088 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go @@ -18,9 +18,7 @@ import ( type ExpressRouteCircuitConnectionResource struct{} func TestAccExpressRouteCircuitConnection_basic(t *testing.T) { - if ok := skipExpressRouteCircuitConnection(); ok { - t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") - } + skipExpressRouteCircuitConnection(t) data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") r := ExpressRouteCircuitConnectionResource{} @@ -36,9 +34,7 @@ func TestAccExpressRouteCircuitConnection_basic(t *testing.T) { } func TestAccExpressRouteCircuitConnection_requiresImport(t *testing.T) { - if ok := skipExpressRouteCircuitConnection(); ok { - t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") - } + skipExpressRouteCircuitConnection(t) data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") r := ExpressRouteCircuitConnectionResource{} @@ -54,9 +50,7 @@ func TestAccExpressRouteCircuitConnection_requiresImport(t *testing.T) { } func TestAccExpressRouteCircuitConnection_complete(t *testing.T) { - if ok := skipExpressRouteCircuitConnection(); ok { - t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") - } + skipExpressRouteCircuitConnection(t) data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") r := ExpressRouteCircuitConnectionResource{} @@ -72,9 +66,7 @@ func TestAccExpressRouteCircuitConnection_complete(t *testing.T) { } func TestAccExpressRouteCircuitConnection_update(t *testing.T) { - if ok := skipExpressRouteCircuitConnection(); ok { - t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") - } + skipExpressRouteCircuitConnection(t) data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") r := ExpressRouteCircuitConnectionResource{} @@ -104,9 +96,7 @@ func TestAccExpressRouteCircuitConnection_update(t *testing.T) { } func TestAccExpressRouteCircuitConnection_updateAddressPrefixIPv6(t *testing.T) { - if ok := skipExpressRouteCircuitConnection(); ok { - t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") - } + skipExpressRouteCircuitConnection(t) data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") r := ExpressRouteCircuitConnectionResource{} @@ -236,10 +226,8 @@ resource "azurerm_express_route_circuit_peering" "peer_test" { `, circuitName1, rg, circuitName2) } -func skipExpressRouteCircuitConnection() bool { +func skipExpressRouteCircuitConnection(t *testing.T) { if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { - return true + t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") } - - return false } From 00028bc54b9c94594b01fc33e43190a937e8ce7c Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Sat, 26 Jun 2021 00:03:59 +0800 Subject: [PATCH 19/28] update code --- ..._route_circuit_connection_resource_test.go | 115 +++++++++++------- ...ess_route_circuit_connection.html.markdown | 59 +++++---- 2 files changed, 107 insertions(+), 67 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go index 7a251ddb2088..4ae04b2bdf1c 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go @@ -3,10 +3,8 @@ package network_test import ( "context" "fmt" - "os" "testing" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" @@ -18,14 +16,12 @@ import ( type ExpressRouteCircuitConnectionResource struct{} func TestAccExpressRouteCircuitConnection_basic(t *testing.T) { - skipExpressRouteCircuitConnection(t) - data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") r := ExpressRouteCircuitConnectionResource{} - data.ResourceSequentialTest(t, r, []resource.TestStep{ + data.ResourceSequentialTest(t, r, []acceptance.TestStep{ { Config: r.basic(data), - Check: resource.ComposeTestCheckFunc( + Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, @@ -34,14 +30,12 @@ func TestAccExpressRouteCircuitConnection_basic(t *testing.T) { } func TestAccExpressRouteCircuitConnection_requiresImport(t *testing.T) { - skipExpressRouteCircuitConnection(t) - data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") r := ExpressRouteCircuitConnectionResource{} - data.ResourceSequentialTest(t, r, []resource.TestStep{ + data.ResourceSequentialTest(t, r, []acceptance.TestStep{ { Config: r.basic(data), - Check: resource.ComposeTestCheckFunc( + Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, @@ -50,14 +44,12 @@ func TestAccExpressRouteCircuitConnection_requiresImport(t *testing.T) { } func TestAccExpressRouteCircuitConnection_complete(t *testing.T) { - skipExpressRouteCircuitConnection(t) - data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") r := ExpressRouteCircuitConnectionResource{} - data.ResourceSequentialTest(t, r, []resource.TestStep{ + data.ResourceSequentialTest(t, r, []acceptance.TestStep{ { Config: r.complete(data), - Check: resource.ComposeTestCheckFunc( + Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, @@ -66,28 +58,26 @@ func TestAccExpressRouteCircuitConnection_complete(t *testing.T) { } func TestAccExpressRouteCircuitConnection_update(t *testing.T) { - skipExpressRouteCircuitConnection(t) - data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") r := ExpressRouteCircuitConnectionResource{} - data.ResourceSequentialTest(t, r, []resource.TestStep{ + data.ResourceSequentialTest(t, r, []acceptance.TestStep{ { Config: r.basic(data), - Check: resource.ComposeTestCheckFunc( + Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, data.ImportStep(), { Config: r.complete(data), - Check: resource.ComposeTestCheckFunc( + Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, data.ImportStep(), { Config: r.basic(data), - Check: resource.ComposeTestCheckFunc( + Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, @@ -96,21 +86,19 @@ func TestAccExpressRouteCircuitConnection_update(t *testing.T) { } func TestAccExpressRouteCircuitConnection_updateAddressPrefixIPv6(t *testing.T) { - skipExpressRouteCircuitConnection(t) - data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") r := ExpressRouteCircuitConnectionResource{} - data.ResourceSequentialTest(t, r, []resource.TestStep{ + data.ResourceSequentialTest(t, r, []acceptance.TestStep{ { Config: r.complete(data), - Check: resource.ComposeTestCheckFunc( + Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, data.ImportStep(), { Config: r.updateAddressPrefixIPv6(data), - Check: resource.ComposeTestCheckFunc( + Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, @@ -146,7 +134,7 @@ resource "azurerm_express_route_circuit_connection" "test" { peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id address_prefix_ipv4 = "192.169.8.0/29" } -`, r.template(), data.RandomInteger) +`, r.template(data), data.RandomInteger) } func (r ExpressRouteCircuitConnectionResource) requiresImport(data acceptance.TestData) string { @@ -174,7 +162,7 @@ resource "azurerm_express_route_circuit_connection" "test" { authorization_key = "846a1918-b7a2-4917-b43c-8c4cdaee006a" address_prefix_ipv6 = "aa:bb::/125" } -`, r.template(), data.RandomInteger) +`, r.template(data), data.RandomInteger) } func (r ExpressRouteCircuitConnectionResource) updateAddressPrefixIPv6(data acceptance.TestData) string { @@ -189,23 +177,68 @@ resource "azurerm_express_route_circuit_connection" "test" { authorization_key = "846a1918-b7a2-4917-b43c-8c4cdaee006a" address_prefix_ipv6 = "aa:cc::/125" } -`, r.template(), data.RandomInteger) +`, r.template(data), data.RandomInteger) } -func (r ExpressRouteCircuitConnectionResource) template() string { - rg := os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") - circuitName1 := os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") - circuitName2 := os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") - +func (r ExpressRouteCircuitConnectionResource) template(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { features {} } +resource "azurerm_resource_group" "test" { + name = "acctestRG-ercircuitconn-%d" + location = "%s" +} + +resource "azurerm_express_route_port" "test" { + name = "acctest-erp-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + peering_location = "Equinix-Seattle-SE2" + bandwidth_in_gbps = 10 + encapsulation = "Dot1Q" +} + +resource "azurerm_express_route_circuit" "test" { + name = "acctest-erc-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + express_route_port_id = azurerm_express_route_port.test.id + bandwidth_in_gbps = 5 + + sku { + tier = "Standard" + family = "MeteredData" + } +} + +resource "azurerm_express_route_port" "peer_test" { + name = "acctest-erp-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + peering_location = "Allied-Toronto-King-West" + bandwidth_in_gbps = 10 + encapsulation = "Dot1Q" +} + +resource "azurerm_express_route_circuit" "peer_test" { + name = "acctest-erc-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + express_route_port_id = azurerm_express_route_port.peer_test.id + bandwidth_in_gbps = 5 + + sku { + tier = "Standard" + family = "MeteredData" + } +} + resource "azurerm_express_route_circuit_peering" "test" { peering_type = "AzurePrivatePeering" - express_route_circuit_name = "%[1]s" - resource_group_name = "%[2]s" + express_route_circuit_name = azurerm_express_route_circuit.test.name + resource_group_name = azurerm_resource_group.test.name shared_key = "ItsASecret" peer_asn = 100 primary_peer_address_prefix = "192.168.1.0/30" @@ -215,19 +248,13 @@ resource "azurerm_express_route_circuit_peering" "test" { resource "azurerm_express_route_circuit_peering" "peer_test" { peering_type = "AzurePrivatePeering" - express_route_circuit_name = "%[3]s" - resource_group_name = "%[2]s" + express_route_circuit_name = azurerm_express_route_circuit.peer_test.name + resource_group_name = azurerm_resource_group.test.name shared_key = "ItsASecret" peer_asn = 100 primary_peer_address_prefix = "192.168.1.0/30" secondary_peer_address_prefix = "192.168.1.0/30" vlan_id = 100 } -`, circuitName1, rg, circuitName2) -} - -func skipExpressRouteCircuitConnection(t *testing.T) { - if os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_FIRST") == "" || os.Getenv("ARM_TEST_CIRCUIT_NAME_SECOND") == "" { - t.Skip("Skipping as ARM_TEST_DATA_RESOURCE_GROUP and/or ARM_TEST_CIRCUIT_NAME_FIRST and/or ARM_TEST_CIRCUIT_NAME_SECOND are not specified") - } +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) } diff --git a/website/docs/r/express_route_circuit_connection.html.markdown b/website/docs/r/express_route_circuit_connection.html.markdown index 9ec139d73671..8d11df3cda6e 100644 --- a/website/docs/r/express_route_circuit_connection.html.markdown +++ b/website/docs/r/express_route_circuit_connection.html.markdown @@ -18,65 +18,78 @@ resource "azurerm_resource_group" "example" { location = "West Europe" } +resource "azurerm_express_route_port" "example" { + name = "example-erport" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + peering_location = "Equinix-Seattle-SE2" + bandwidth_in_gbps = 10 + encapsulation = "Dot1Q" +} + resource "azurerm_express_route_circuit" "example" { - name = "example-circuit" - resource_group_name = azurerm_resource_group.example.name + name = "example-ercircuit" location = azurerm_resource_group.example.location - service_provider_name = "Equinix" - peering_location = "Silicon Valley" - bandwidth_in_mbps = 50 + resource_group_name = azurerm_resource_group.example.name + express_route_port_id = azurerm_express_route_port.example.id + bandwidth_in_gbps = 5 sku { tier = "Standard" family = "MeteredData" } +} - allow_classic_operations = false +resource "azurerm_express_route_port" "example2" { + name = "example-erport2" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + peering_location = "Allied-Toronto-King-West" + bandwidth_in_gbps = 10 + encapsulation = "Dot1Q" } resource "azurerm_express_route_circuit" "example2" { - name = "example-circuit2" - resource_group_name = azurerm_resource_group.example.name + name = "example-ercircuit2" location = azurerm_resource_group.example.location - service_provider_name = "Equinix" - peering_location = "Silicon Valley" - bandwidth_in_mbps = 50 + resource_group_name = azurerm_resource_group.example.name + express_route_port_id = azurerm_express_route_port.example2.id + bandwidth_in_gbps = 5 sku { tier = "Standard" family = "MeteredData" } - - allow_classic_operations = false } resource "azurerm_express_route_circuit_peering" "example" { peering_type = "AzurePrivatePeering" express_route_circuit_name = azurerm_express_route_circuit.example.name resource_group_name = azurerm_resource_group.example.name + shared_key = "ItsASecret" peer_asn = 100 - primary_peer_address_prefix = "123.0.0.0/30" - secondary_peer_address_prefix = "123.0.0.4/30" - vlan_id = 300 + primary_peer_address_prefix = "192.168.1.0/30" + secondary_peer_address_prefix = "192.168.1.0/30" + vlan_id = 100 } resource "azurerm_express_route_circuit_peering" "example2" { peering_type = "AzurePrivatePeering" express_route_circuit_name = azurerm_express_route_circuit.example2.name resource_group_name = azurerm_resource_group.example.name + shared_key = "ItsASecret" peer_asn = 100 - primary_peer_address_prefix = "123.0.0.0/30" - secondary_peer_address_prefix = "123.0.0.4/30" - vlan_id = 300 + primary_peer_address_prefix = "192.168.1.0/30" + secondary_peer_address_prefix = "192.168.1.0/30" + vlan_id = 100 } resource "azurerm_express_route_circuit_connection" "example" { - name = "example-expressroutecircuitconn" + name = "example-ercircuitconnection" peering_id = azurerm_express_route_circuit_peering.example.id peer_peering_id = azurerm_express_route_circuit_peering.example2.id - address_prefix_ipv4 = "192.169.8.0/29" - authorization_key = "00000000-0000-0000-0000-000000000000" - address_prefix_ipv6 = "2002:db01::/125" + address_prefix_ipv4 = "192.169.9.0/29" + authorization_key = "846a1918-b7a2-4917-b43c-8c4cdaee006a" } ``` From 7e8910c0c964cbacbcf2e79eb0099d05efdd0799 Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Sat, 26 Jun 2021 00:43:40 +0800 Subject: [PATCH 20/28] update code --- .../network/express_route_circuit_connection_resource_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go index 4ae04b2bdf1c..71b2f9ae98b3 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go @@ -214,7 +214,7 @@ resource "azurerm_express_route_circuit" "test" { } resource "azurerm_express_route_port" "peer_test" { - name = "acctest-erp-%d" + name = "acctest-erp2-%d" resource_group_name = azurerm_resource_group.test.name location = azurerm_resource_group.test.location peering_location = "Allied-Toronto-King-West" @@ -223,7 +223,7 @@ resource "azurerm_express_route_port" "peer_test" { } resource "azurerm_express_route_circuit" "peer_test" { - name = "acctest-erc-%d" + name = "acctest-erc2-%d" location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name express_route_port_id = azurerm_express_route_port.peer_test.id From 1b344e2a7e6686148f8c991a109aab31fbd05ed8 Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Sat, 26 Jun 2021 11:07:00 +0800 Subject: [PATCH 21/28] update code --- ..._route_circuit_connection_resource_test.go | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go index 71b2f9ae98b3..f5ec4bf913fc 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go @@ -85,27 +85,6 @@ func TestAccExpressRouteCircuitConnection_update(t *testing.T) { }) } -func TestAccExpressRouteCircuitConnection_updateAddressPrefixIPv6(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") - r := ExpressRouteCircuitConnectionResource{} - data.ResourceSequentialTest(t, r, []acceptance.TestStep{ - { - Config: r.complete(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - data.ImportStep(), - { - Config: r.updateAddressPrefixIPv6(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), - ), - }, - data.ImportStep(), - }) -} - func (r ExpressRouteCircuitConnectionResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := parse.ExpressRouteCircuitConnectionID(state.ID) if err != nil { @@ -160,22 +139,6 @@ resource "azurerm_express_route_circuit_connection" "test" { peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id address_prefix_ipv4 = "192.169.9.0/29" authorization_key = "846a1918-b7a2-4917-b43c-8c4cdaee006a" - address_prefix_ipv6 = "aa:bb::/125" -} -`, r.template(data), data.RandomInteger) -} - -func (r ExpressRouteCircuitConnectionResource) updateAddressPrefixIPv6(data acceptance.TestData) string { - return fmt.Sprintf(` -%s - -resource "azurerm_express_route_circuit_connection" "test" { - name = "acctest-ExpressRouteCircuitConn-%d" - peering_id = azurerm_express_route_circuit_peering.test.id - peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id - address_prefix_ipv4 = "192.169.9.0/29" - authorization_key = "846a1918-b7a2-4917-b43c-8c4cdaee006a" - address_prefix_ipv6 = "aa:cc::/125" } `, r.template(data), data.RandomInteger) } From 31630832f3e452807b18845f162c654570b34418 Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Sat, 26 Jun 2021 14:30:17 +0800 Subject: [PATCH 22/28] update code --- ..._route_circuit_connection_resource_test.go | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go index f5ec4bf913fc..8e570adaba14 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go @@ -15,7 +15,18 @@ import ( type ExpressRouteCircuitConnectionResource struct{} -func TestAccExpressRouteCircuitConnection_basic(t *testing.T) { +func TestAccExpressRouteCircuitConnection(t *testing.T) { + acceptance.RunTestsInSequence(t, map[string]map[string]func(t *testing.T){ + "Resource": { + "basic": testAccExpressRouteCircuitConnection_basic, + "requiresImport": testAccExpressRouteCircuitConnection_requiresImport, + "complete": testAccExpressRouteCircuitConnection_complete, + "update": testAccExpressRouteCircuitConnection_update, + }, + }) +} + +func testAccExpressRouteCircuitConnection_basic(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") r := ExpressRouteCircuitConnectionResource{} data.ResourceSequentialTest(t, r, []acceptance.TestStep{ @@ -29,7 +40,7 @@ func TestAccExpressRouteCircuitConnection_basic(t *testing.T) { }) } -func TestAccExpressRouteCircuitConnection_requiresImport(t *testing.T) { +func testAccExpressRouteCircuitConnection_requiresImport(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") r := ExpressRouteCircuitConnectionResource{} data.ResourceSequentialTest(t, r, []acceptance.TestStep{ @@ -43,7 +54,7 @@ func TestAccExpressRouteCircuitConnection_requiresImport(t *testing.T) { }) } -func TestAccExpressRouteCircuitConnection_complete(t *testing.T) { +func testAccExpressRouteCircuitConnection_complete(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") r := ExpressRouteCircuitConnectionResource{} data.ResourceSequentialTest(t, r, []acceptance.TestStep{ @@ -57,7 +68,7 @@ func TestAccExpressRouteCircuitConnection_complete(t *testing.T) { }) } -func TestAccExpressRouteCircuitConnection_update(t *testing.T) { +func testAccExpressRouteCircuitConnection_update(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_express_route_circuit_connection", "test") r := ExpressRouteCircuitConnectionResource{} data.ResourceSequentialTest(t, r, []acceptance.TestStep{ @@ -137,7 +148,7 @@ resource "azurerm_express_route_circuit_connection" "test" { name = "acctest-ExpressRouteCircuitConn-%d" peering_id = azurerm_express_route_circuit_peering.test.id peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id - address_prefix_ipv4 = "192.169.9.0/29" + address_prefix_ipv4 = "192.169.8.0/29" authorization_key = "846a1918-b7a2-4917-b43c-8c4cdaee006a" } `, r.template(data), data.RandomInteger) From 9298a2d2c9bd47dedf99ea1a08079da8f388cf22 Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Sat, 26 Jun 2021 16:33:47 +0800 Subject: [PATCH 23/28] update code --- ...press_route_circuit_connection_resource.go | 4 ++++ ..._route_circuit_connection_resource_test.go | 20 ++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource.go b/azurerm/internal/services/network/express_route_circuit_connection_resource.go index be76642dad6e..ab93dd05314a 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource.go @@ -122,6 +122,8 @@ func resourceExpressRouteCircuitConnectionCreate(d *pluginsdk.ResourceData, meta if v, ok := d.GetOk("authorization_key"); ok { expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.AuthorizationKey = utils.String(v.(string)) + } else { + expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.AuthorizationKey = nil } if v, ok := d.GetOk("address_prefix_ipv6"); ok { @@ -224,6 +226,8 @@ func resourceExpressRouteCircuitConnectionUpdate(d *pluginsdk.ResourceData, meta if v, ok := d.GetOk("authorization_key"); ok { expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.AuthorizationKey = utils.String(v.(string)) + } else { + expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.AuthorizationKey = nil } if v, ok := d.GetOk("address_prefix_ipv6"); ok { diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go index 8e570adaba14..6439909fd313 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go @@ -73,21 +73,21 @@ func testAccExpressRouteCircuitConnection_update(t *testing.T) { r := ExpressRouteCircuitConnectionResource{} data.ResourceSequentialTest(t, r, []acceptance.TestStep{ { - Config: r.basic(data), + Config: r.complete(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, data.ImportStep(), { - Config: r.complete(data), + Config: r.updateAuthorizationKey(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, data.ImportStep(), { - Config: r.basic(data), + Config: r.complete(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), @@ -154,6 +154,20 @@ resource "azurerm_express_route_circuit_connection" "test" { `, r.template(data), data.RandomInteger) } +func (r ExpressRouteCircuitConnectionResource) updateAuthorizationKey(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_express_route_circuit_connection" "test" { + name = "acctest-ExpressRouteCircuitConn-%d" + peering_id = azurerm_express_route_circuit_peering.test.id + peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id + address_prefix_ipv4 = "192.169.8.0/29" + authorization_key = "946a1918-b7a2-4917-b43c-8c4cdaee007a" +} +`, r.template(data), data.RandomInteger) +} + func (r ExpressRouteCircuitConnectionResource) template(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { From 2b2345673fcd8a2cfb272096597dc9f9fd2fd5d0 Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Sat, 26 Jun 2021 17:55:54 +0800 Subject: [PATCH 24/28] update code --- .../network/express_route_circuit_connection_resource.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource.go b/azurerm/internal/services/network/express_route_circuit_connection_resource.go index ab93dd05314a..be76642dad6e 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource.go @@ -122,8 +122,6 @@ func resourceExpressRouteCircuitConnectionCreate(d *pluginsdk.ResourceData, meta if v, ok := d.GetOk("authorization_key"); ok { expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.AuthorizationKey = utils.String(v.(string)) - } else { - expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.AuthorizationKey = nil } if v, ok := d.GetOk("address_prefix_ipv6"); ok { @@ -226,8 +224,6 @@ func resourceExpressRouteCircuitConnectionUpdate(d *pluginsdk.ResourceData, meta if v, ok := d.GetOk("authorization_key"); ok { expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.AuthorizationKey = utils.String(v.(string)) - } else { - expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.AuthorizationKey = nil } if v, ok := d.GetOk("address_prefix_ipv6"); ok { From 3e9557ba951273a1ed54f0c606f5223bad4b3925 Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Wed, 30 Jun 2021 08:07:42 +0800 Subject: [PATCH 25/28] update code --- ...press_route_circuit_connection_resource.go | 51 ++++++-- ..._route_circuit_connection_resource_test.go | 35 +++--- .../network/parse/express_route_circuit.go | 69 +++++++++++ .../parse/express_route_circuit_test.go | 112 ++++++++++++++++++ .../internal/services/network/resourceids.go | 1 + .../validate/express_route_circuit_id.go | 23 ++++ .../validate/express_route_circuit_id_test.go | 76 ++++++++++++ ...ess_route_circuit_connection.html.markdown | 4 +- 8 files changed, 340 insertions(+), 31 deletions(-) create mode 100644 azurerm/internal/services/network/parse/express_route_circuit.go create mode 100644 azurerm/internal/services/network/parse/express_route_circuit_test.go create mode 100644 azurerm/internal/services/network/validate/express_route_circuit_id.go create mode 100644 azurerm/internal/services/network/validate/express_route_circuit_id_test.go diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource.go b/azurerm/internal/services/network/express_route_circuit_connection_resource.go index be76642dad6e..4e42aaa15a79 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource.go @@ -60,14 +60,18 @@ func resourceExpressRouteCircuitConnection() *pluginsdk.Resource { "address_prefix_ipv4": { Type: pluginsdk.TypeString, Required: true, + ForceNew: true, ValidateFunc: validation.IsCIDR, }, "authorization_key": { - Type: pluginsdk.TypeString, - Optional: true, - Sensitive: true, - ValidateFunc: validation.IsUUID, + Type: pluginsdk.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.All( + validation.StringIsNotEmpty, + validation.IsUUID, + ), }, "address_prefix_ipv6": { @@ -81,6 +85,7 @@ func resourceExpressRouteCircuitConnection() *pluginsdk.Resource { func resourceExpressRouteCircuitConnectionCreate(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient + circuitClient := meta.(*clients.Client).Network.ExpressRouteCircuitsClient ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -125,8 +130,19 @@ func resourceExpressRouteCircuitConnectionCreate(d *pluginsdk.ResourceData, meta } if v, ok := d.GetOk("address_prefix_ipv6"); ok { - expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.Ipv6CircuitConnectionConfig = &network.Ipv6CircuitConnectionConfig{ - AddressPrefix: utils.String(v.(string)), + circuitId := parse.NewExpressRouteCircuitID(circuitPeeringId.SubscriptionId, circuitPeeringId.ResourceGroup, circuitPeeringId.ExpressRouteCircuitName) + + circuit, err := circuitClient.Get(ctx, circuitId.ResourceGroup, circuitId.Name) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", circuitId, err) + } + + if circuit.ExpressRouteCircuitPropertiesFormat != nil && circuit.ExpressRouteCircuitPropertiesFormat.ExpressRoutePort != nil { + return fmt.Errorf("`address_prefix_ipv6` cannot be set when ExpressRoute Circuit Connection with ExpressRoute Circuit based on ExpressRoute Port") + } else { + expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.Ipv6CircuitConnectionConfig = &network.Ipv6CircuitConnectionConfig{ + AddressPrefix: utils.String(v.(string)), + } } } @@ -169,7 +185,12 @@ func resourceExpressRouteCircuitConnectionRead(d *pluginsdk.ResourceData, meta i if props := resp.ExpressRouteCircuitConnectionPropertiesFormat; props != nil { d.Set("address_prefix_ipv4", props.AddressPrefix) - d.Set("authorization_key", props.AuthorizationKey) + + authorizationKey := "" + if props.AuthorizationKey != nil { + authorizationKey = *props.AuthorizationKey + } + d.Set("authorization_key", authorizationKey) addressPrefixIPv6 := "" if props.Ipv6CircuitConnectionConfig != nil && props.Ipv6CircuitConnectionConfig.AddressPrefix != nil { @@ -191,6 +212,7 @@ func resourceExpressRouteCircuitConnectionRead(d *pluginsdk.ResourceData, meta i func resourceExpressRouteCircuitConnectionUpdate(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Network.ExpressRouteCircuitConnectionClient + circuitClient := meta.(*clients.Client).Network.ExpressRouteCircuitsClient ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -227,8 +249,19 @@ func resourceExpressRouteCircuitConnectionUpdate(d *pluginsdk.ResourceData, meta } if v, ok := d.GetOk("address_prefix_ipv6"); ok { - expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.Ipv6CircuitConnectionConfig = &network.Ipv6CircuitConnectionConfig{ - AddressPrefix: utils.String(v.(string)), + circuitId := parse.NewExpressRouteCircuitID(circuitPeeringId.SubscriptionId, circuitPeeringId.ResourceGroup, circuitPeeringId.ExpressRouteCircuitName) + + circuit, err := circuitClient.Get(ctx, circuitId.ResourceGroup, circuitId.Name) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", circuitId, err) + } + + if circuit.ExpressRouteCircuitPropertiesFormat != nil && circuit.ExpressRouteCircuitPropertiesFormat.ExpressRoutePort != nil { + return fmt.Errorf("`address_prefix_ipv6` cannot be set when ExpressRoute Circuit Connection with ExpressRoute Circuit based on ExpressRoute Port") + } else { + expressRouteCircuitConnectionParameters.ExpressRouteCircuitConnectionPropertiesFormat.Ipv6CircuitConnectionConfig = &network.Ipv6CircuitConnectionConfig{ + AddressPrefix: utils.String(v.(string)), + } } } diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go index 6439909fd313..b8aa5499f576 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go @@ -59,7 +59,7 @@ func testAccExpressRouteCircuitConnection_complete(t *testing.T) { r := ExpressRouteCircuitConnectionResource{} data.ResourceSequentialTest(t, r, []acceptance.TestStep{ { - Config: r.complete(data), + Config: r.complete(data, "846a1918-b7a2-4917-b43c-8c4cdaee006a"), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), @@ -73,21 +73,28 @@ func testAccExpressRouteCircuitConnection_update(t *testing.T) { r := ExpressRouteCircuitConnectionResource{} data.ResourceSequentialTest(t, r, []acceptance.TestStep{ { - Config: r.complete(data), + Config: r.basic(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, data.ImportStep(), { - Config: r.updateAuthorizationKey(data), + Config: r.complete(data, "846a1918-b7a2-4917-b43c-8c4cdaee006a"), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, data.ImportStep(), { - Config: r.complete(data), + Config: r.complete(data, "946a1918-b7a2-4917-b43c-8c4cdaee006a"), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.basic(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), @@ -140,7 +147,7 @@ resource "azurerm_express_route_circuit_connection" "import" { `, r.basic(data)) } -func (r ExpressRouteCircuitConnectionResource) complete(data acceptance.TestData) string { +func (r ExpressRouteCircuitConnectionResource) complete(data acceptance.TestData, authorizationKey string) string { return fmt.Sprintf(` %s @@ -149,23 +156,9 @@ resource "azurerm_express_route_circuit_connection" "test" { peering_id = azurerm_express_route_circuit_peering.test.id peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id address_prefix_ipv4 = "192.169.8.0/29" - authorization_key = "846a1918-b7a2-4917-b43c-8c4cdaee006a" + authorization_key = "%s" } -`, r.template(data), data.RandomInteger) -} - -func (r ExpressRouteCircuitConnectionResource) updateAuthorizationKey(data acceptance.TestData) string { - return fmt.Sprintf(` -%s - -resource "azurerm_express_route_circuit_connection" "test" { - name = "acctest-ExpressRouteCircuitConn-%d" - peering_id = azurerm_express_route_circuit_peering.test.id - peer_peering_id = azurerm_express_route_circuit_peering.peer_test.id - address_prefix_ipv4 = "192.169.8.0/29" - authorization_key = "946a1918-b7a2-4917-b43c-8c4cdaee007a" -} -`, r.template(data), data.RandomInteger) +`, r.template(data), data.RandomInteger, authorizationKey) } func (r ExpressRouteCircuitConnectionResource) template(data acceptance.TestData) string { diff --git a/azurerm/internal/services/network/parse/express_route_circuit.go b/azurerm/internal/services/network/parse/express_route_circuit.go new file mode 100644 index 000000000000..ba60a9aab8bf --- /dev/null +++ b/azurerm/internal/services/network/parse/express_route_circuit.go @@ -0,0 +1,69 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type ExpressRouteCircuitId struct { + SubscriptionId string + ResourceGroup string + Name string +} + +func NewExpressRouteCircuitID(subscriptionId, resourceGroup, name string) ExpressRouteCircuitId { + return ExpressRouteCircuitId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + Name: name, + } +} + +func (id ExpressRouteCircuitId) String() string { + segments := []string{ + fmt.Sprintf("Name %q", id.Name), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Express Route Circuit", segmentsStr) +} + +func (id ExpressRouteCircuitId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/expressRouteCircuits/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.Name) +} + +// ExpressRouteCircuitID parses a ExpressRouteCircuit ID into an ExpressRouteCircuitId struct +func ExpressRouteCircuitID(input string) (*ExpressRouteCircuitId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := ExpressRouteCircuitId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.Name, err = id.PopSegment("expressRouteCircuits"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/azurerm/internal/services/network/parse/express_route_circuit_test.go b/azurerm/internal/services/network/parse/express_route_circuit_test.go new file mode 100644 index 000000000000..afa42498692b --- /dev/null +++ b/azurerm/internal/services/network/parse/express_route_circuit_test.go @@ -0,0 +1,112 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) + +var _ resourceid.Formatter = ExpressRouteCircuitId{} + +func TestExpressRouteCircuitIDFormatter(t *testing.T) { + actual := NewExpressRouteCircuitID("12345678-1234-9876-4563-123456789012", "resGroup1", "erCircuit1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/erCircuit1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestExpressRouteCircuitID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *ExpressRouteCircuitId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", + Error: true, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/erCircuit1", + Expected: &ExpressRouteCircuitId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + Name: "erCircuit1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/EXPRESSROUTECIRCUITS/ERCIRCUIT1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := ExpressRouteCircuitID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + } +} diff --git a/azurerm/internal/services/network/resourceids.go b/azurerm/internal/services/network/resourceids.go index ab48dcb63cb8..725e2fbcd257 100644 --- a/azurerm/internal/services/network/resourceids.go +++ b/azurerm/internal/services/network/resourceids.go @@ -62,5 +62,6 @@ package network //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=VirtualNetworkGatewayIpConfiguration -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/virtualNetworkGateways/gw1/ipConfigurations/cfg1 // Express Route Circuit +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ExpressRouteCircuit -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/erCircuit1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ExpressRouteCircuitPeering -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/erCircuit1/peerings/peering1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ExpressRouteCircuitConnection -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/circuit1/peerings/peering1/connections/connection1 diff --git a/azurerm/internal/services/network/validate/express_route_circuit_id.go b/azurerm/internal/services/network/validate/express_route_circuit_id.go new file mode 100644 index 000000000000..8801427b12bc --- /dev/null +++ b/azurerm/internal/services/network/validate/express_route_circuit_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" +) + +func ExpressRouteCircuitID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.ExpressRouteCircuitID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/azurerm/internal/services/network/validate/express_route_circuit_id_test.go b/azurerm/internal/services/network/validate/express_route_circuit_id_test.go new file mode 100644 index 000000000000..bccd0e0d0717 --- /dev/null +++ b/azurerm/internal/services/network/validate/express_route_circuit_id_test.go @@ -0,0 +1,76 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestExpressRouteCircuitID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", + Valid: false, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/expressRouteCircuits/erCircuit1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/EXPRESSROUTECIRCUITS/ERCIRCUIT1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := ExpressRouteCircuitID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/website/docs/r/express_route_circuit_connection.html.markdown b/website/docs/r/express_route_circuit_connection.html.markdown index 8d11df3cda6e..1625595a2827 100644 --- a/website/docs/r/express_route_circuit_connection.html.markdown +++ b/website/docs/r/express_route_circuit_connection.html.markdown @@ -103,7 +103,7 @@ The following arguments are supported: * `peer_peering_id` - (Required) The ID of the peered Express Route Circuit Private Peering. Changing this forces a new Express Route Circuit Connection to be created. -* `address_prefix_ipv4` - (Required) The IPv4 address space from which to allocate customer address for global reach. +* `address_prefix_ipv4` - (Required) The IPv4 address space from which to allocate customer address for global reach. Changing this forces a new Express Route Circuit Connection to be created. --- @@ -111,6 +111,8 @@ The following arguments are supported: * `address_prefix_ipv6` - (Optional) The IPv6 address space from which to allocate customer addresses for global reach. +-> **NOTE**: `address_prefix_ipv6` cannot be set when ExpressRoute Circuit Connection with ExpressRoute Circuit based on ExpressRoute Port. + ## Attributes Reference In addition to the Arguments listed above - the following Attributes are exported: From b174375c2648affe291e92e8e8e91d46254847b9 Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Wed, 30 Jun 2021 11:01:31 +0800 Subject: [PATCH 26/28] update code --- .../network/express_route_circuit_connection_resource.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource.go b/azurerm/internal/services/network/express_route_circuit_connection_resource.go index 4e42aaa15a79..853ce73a0472 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource.go @@ -186,8 +186,10 @@ func resourceExpressRouteCircuitConnectionRead(d *pluginsdk.ResourceData, meta i if props := resp.ExpressRouteCircuitConnectionPropertiesFormat; props != nil { d.Set("address_prefix_ipv4", props.AddressPrefix) + // The ExpressRoute Circuit Connection API returns "*****************" for AuthorizationKey when it's changed from a valid value to `nil` + // See more details from https://github.com/Azure/azure-rest-api-specs/issues/15030 authorizationKey := "" - if props.AuthorizationKey != nil { + if props.AuthorizationKey != nil && *props.AuthorizationKey != "*****************" { authorizationKey = *props.AuthorizationKey } d.Set("authorization_key", authorizationKey) From 49dd452a8178967cc7650203bde3371edeb3291a Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Wed, 30 Jun 2021 12:51:43 +0800 Subject: [PATCH 27/28] update code --- .../express_route_circuit_connection_resource.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource.go b/azurerm/internal/services/network/express_route_circuit_connection_resource.go index 853ce73a0472..8ceec877ab09 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource.go @@ -65,13 +65,10 @@ func resourceExpressRouteCircuitConnection() *pluginsdk.Resource { }, "authorization_key": { - Type: pluginsdk.TypeString, - Optional: true, - Sensitive: true, - ValidateFunc: validation.All( - validation.StringIsNotEmpty, - validation.IsUUID, - ), + Type: pluginsdk.TypeString, + Optional: true, + Sensitive: true, + ValidateFunc: validation.IsUUID, }, "address_prefix_ipv6": { From 7960a66b4d8b2f6c0febfcfcd065b3742270314b Mon Sep 17 00:00:00 2001 From: neil-yechenwei Date: Wed, 30 Jun 2021 13:16:47 +0800 Subject: [PATCH 28/28] update code --- .../network/express_route_circuit_connection_resource_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go index b8aa5499f576..f9c7d98b442b 100644 --- a/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go +++ b/azurerm/internal/services/network/express_route_circuit_connection_resource_test.go @@ -198,7 +198,7 @@ resource "azurerm_express_route_port" "peer_test" { name = "acctest-erp2-%d" resource_group_name = azurerm_resource_group.test.name location = azurerm_resource_group.test.location - peering_location = "Allied-Toronto-King-West" + peering_location = "CDC-Canberra" bandwidth_in_gbps = 10 encapsulation = "Dot1Q" }