diff --git a/docs/data-sources/equinix_fabric_cloud_router.md b/docs/data-sources/equinix_fabric_cloud_router.md index 2040a2c71..f0ce71683 100644 --- a/docs/data-sources/equinix_fabric_cloud_router.md +++ b/docs/data-sources/equinix_fabric_cloud_router.md @@ -30,11 +30,13 @@ data "equinix_fabric_cloud_router" "cloud_router_data_name" { ### Read-Only - `account` (Set of Object) Customer account information that is associated with this Fabric Cloud Router (see [below for nested schema](#nestedatt--account)) -- `bgp_ipv4_routes_count` (Number) Access point used and maximum number of IPv4 BGP routes -- `bgp_ipv6_routes_count` (Number) Access point used and maximum number of IPv6 BGP routes +- `bgp_ipv4_routes_count` (Number) Number of IPv4 BGP routes in use (including non-distinct prefixes) +- `bgp_ipv6_routes_count` (Number) Number of IPv6 BGP routes in use (including non-distinct prefixes) - `change_log` (Set of Object) Captures Fabric Cloud Router lifecycle change information (see [below for nested schema](#nestedatt--change_log)) -- `connections_count` (Number) Number of connections associated with this Access point +- `connections_count` (Number) Number of connections associated with this Fabric Cloud Router instance - `description` (String) Customer-provided Fabric Cloud Router description +- `distinct_ipv4_prefixes_count` (Number) Number of distinct IPv4 routes +- `distinct_ipv6_prefixes_count` (Number) Number of distinct IPv6 routes - `equinix_asn` (Number) Equinix ASN - `href` (String) Fabric Cloud Router URI information - `id` (String) The ID of this resource. @@ -42,23 +44,17 @@ data "equinix_fabric_cloud_router" "cloud_router_data_name" { - `name` (String) Fabric Cloud Router name. An alpha-numeric 24 characters string which can include only hyphens and underscores - `notifications` (List of Object) Preferences for notifications on Fabric Cloud Router configuration or status changes (see [below for nested schema](#nestedatt--notifications)) - `order` (Set of Object) Order information related to this Fabric Cloud Router (see [below for nested schema](#nestedatt--order)) -- `package` (Set of Object) Fabric Cloud Router package information (see [below for nested schema](#nestedatt--package)) -- `project` (Set of Object) Project information (see [below for nested schema](#nestedatt--project)) +- `package` (Set of Object) Fabric Cloud Router Package Type (see [below for nested schema](#nestedatt--package)) +- `project` (Set of Object) Customer resource hierarchy project information.Applicable to customers onboarded to Equinix Identity and Access Management. For more information see Identity and Access Management: Projects (see [below for nested schema](#nestedatt--project)) - `state` (String) Fabric Cloud Router overall state -- `type` (String) Defines the Fabric Cloud Router type like XF_GATEWAY +- `type` (String) Defines the FCR type like; XF_ROUTER ### Nested Schema for `account` Read-Only: -- `account_name` (String) - `account_number` (Number) -- `global_cust_id` (String) -- `global_org_id` (String) -- `global_organization_name` (String) -- `org_id` (Number) -- `organization_name` (String) @@ -127,3 +123,4 @@ Read-Only: - `href` (String) - `project_id` (String) + diff --git a/docs/resources/equinix_fabric_cloud_router.md b/docs/resources/equinix_fabric_cloud_router.md index 7eda617f2..a75d77ff9 100644 --- a/docs/resources/equinix_fabric_cloud_router.md +++ b/docs/resources/equinix_fabric_cloud_router.md @@ -47,31 +47,42 @@ resource "equinix_fabric_cloud_router" "new_cloud_router"{ ### Required +- `account` (Block Set, Min: 1, Max: 1) Customer account information that is associated with this Fabric Cloud Router (see [below for nested schema](#nestedblock--account)) - `location` (Block Set, Min: 1, Max: 1) Fabric Cloud Router location (see [below for nested schema](#nestedblock--location)) - `name` (String) Fabric Cloud Router name. An alpha-numeric 24 characters string which can include only hyphens and underscores - `notifications` (Block List, Min: 1) Preferences for notifications on Fabric Cloud Router configuration or status changes (see [below for nested schema](#nestedblock--notifications)) -- `package` (Block Set, Min: 1, Max: 1) Fabric Cloud Router location (see [below for nested schema](#nestedblock--package)) -- `type` (String) Defines the FCR type like XF_ROUTER +- `order` (Block Set, Min: 1, Max: 1) Order information related to this Fabric Cloud Router (see [below for nested schema](#nestedblock--order)) +- `package` (Block Set, Min: 1, Max: 1) Fabric Cloud Router Package Type (see [below for nested schema](#nestedblock--package)) +- `project` (Block Set, Min: 1, Max: 1) Customer resource hierarchy project information.Applicable to customers onboarded to Equinix Identity and Access Management. For more information see Identity and Access Management: Projects (see [below for nested schema](#nestedblock--project)) +- `type` (String) Defines the FCR type like; XF_ROUTER ### Optional -- `account` (Block Set, Max: 1) Customer account information that is associated with this Fabric Cloud Router (see [below for nested schema](#nestedblock--account)) - `description` (String) Customer-provided Fabric Cloud Router description -- `order` (Block Set, Max: 1) Order information related to this Fabric Cloud Router (see [below for nested schema](#nestedblock--order)) -- `project` (Block Set, Max: 1) Fabric Cloud Router project (see [below for nested schema](#nestedblock--project)) +- `href` (String) Fabric Cloud Router URI information - `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts)) +- `uuid` (String) Equinix-assigned Fabric Cloud Router identifier ### Read-Only -- `bgp_ipv4_routes_count` (Number) Access point used and maximum number of IPv4 BGP routes -- `bgp_ipv6_routes_count` (Number) Access point used and maximum number of IPv6 BGP routes +- `bgp_ipv4_routes_count` (Number) Number of IPv4 BGP routes in use (including non-distinct prefixes) +- `bgp_ipv6_routes_count` (Number) Number of IPv6 BGP routes in use (including non-distinct prefixes) - `change_log` (Set of Object) Captures Fabric Cloud Router lifecycle change information (see [below for nested schema](#nestedatt--change_log)) -- `connections_count` (Number) Number of connections associated with this Access point +- `connections_count` (Number) Number of connections associated with this Fabric Cloud Router instance +- `distinct_ipv4_prefixes_count` (Number) Number of distinct IPv4 routes +- `distinct_ipv6_prefixes_count` (Number) Number of distinct IPv6 routes - `equinix_asn` (Number) Equinix ASN -- `href` (String) Fabric Cloud Router URI information - `id` (String) The ID of this resource. - `state` (String) Fabric Cloud Router overall state + +### Nested Schema for `account` + +Optional: + +- `account_number` (Number) Account Number + + ### Nested Schema for `location` @@ -96,22 +107,6 @@ Optional: - `send_interval` (String) Send interval - -### Nested Schema for `package` - -Required: - -- `code` (String) Fabric Cloud Router package code - - - -### Nested Schema for `account` - -Optional: - -- `account_number` (Number) Account Number - - ### Nested Schema for `order` @@ -123,6 +118,14 @@ Optional: - `purchase_order_number` (String) Purchase order number + +### Nested Schema for `package` + +Required: + +- `code` (String) Fabric Cloud Router package code + + ### Nested Schema for `project` diff --git a/equinix/data_source_fabric_cloud_router.go b/equinix/data_source_fabric_cloud_router.go index bcbd2329a..e914f79ff 100644 --- a/equinix/data_source_fabric_cloud_router.go +++ b/equinix/data_source_fabric_cloud_router.go @@ -7,16 +7,34 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func dataSourceCloudRouter() *schema.Resource { +func readFabricCloudRouterResourceSchema() map[string]*schema.Schema { + sch := fabricCloudRouterResourceSchema() + for key, _ := range sch { + if key == "uuid" { + sch[key].Required = true + sch[key].Optional = false + sch[key].Computed = false + } else { + sch[key].Required = false + sch[key].Optional = false + sch[key].Computed = true + sch[key].MaxItems = 0 + sch[key].ValidateFunc = nil + } + } + return sch +} + +func dataSourceFabricCloudRouter() *schema.Resource { return &schema.Resource{ - ReadContext: dataSourceCloudRouterRead, - Schema: readCloudRouterResourceSchema(), + ReadContext: dataSourceFabricCloudRouterRead, + Schema: readFabricCloudRouterResourceSchema(), Description: "Fabric V4 API compatible data resource that allow user to fetch Fabric Cloud Router for a given UUID", } } -func dataSourceCloudRouterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func dataSourceFabricCloudRouterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { uuid, _ := d.Get("uuid").(string) d.SetId(uuid) - return resourceCloudRouterRead(ctx, d, meta) + return resourceFabricCloudRouterRead(ctx, d, meta) } diff --git a/equinix/fabric_cloud_router_read_schema.go b/equinix/fabric_cloud_router_read_schema.go deleted file mode 100644 index 31c4d7373..000000000 --- a/equinix/fabric_cloud_router_read_schema.go +++ /dev/null @@ -1,127 +0,0 @@ -package equinix - -import ( - equinix_schema "github.com/equinix/terraform-provider-equinix/internal/fabric/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func readPackageSch() map[string]*schema.Schema { - return map[string]*schema.Schema{ - "code": { - Type: schema.TypeString, - Computed: true, - Description: "Fabric Cloud Router package code", - }, - } -} - -func readCloudRouterResourceSchema() map[string]*schema.Schema { - return map[string]*schema.Schema{ - "uuid": { - Type: schema.TypeString, - Required: true, - Description: "Equinix-assigned Fabric Cloud Router identifier", - }, - "href": { - Type: schema.TypeString, - Computed: true, - Description: "Fabric Cloud Router URI information", - }, - "name": { - Type: schema.TypeString, - Computed: true, - Description: "Fabric Cloud Router name. An alpha-numeric 24 characters string which can include only hyphens and underscores", - }, - "description": { - Type: schema.TypeString, - Computed: true, - Description: "Customer-provided Fabric Cloud Router description", - }, - "state": { - Type: schema.TypeString, - Computed: true, - Description: "Fabric Cloud Router overall state", - }, - "equinix_asn": { - Type: schema.TypeInt, - Computed: true, - Description: "Equinix ASN", - }, - "bgp_ipv4_routes_count": { - Type: schema.TypeInt, - Computed: true, - Description: "Access point used and maximum number of IPv4 BGP routes", - }, - "bgp_ipv6_routes_count": { - Type: schema.TypeInt, - Computed: true, - Description: "Access point used and maximum number of IPv6 BGP routes", - }, - "connections_count": { - Type: schema.TypeInt, - Computed: true, - Description: "Number of connections associated with this Access point", - }, - "package": { - Type: schema.TypeSet, - Computed: true, - Description: "Fabric Cloud Router package information", - Elem: &schema.Resource{ - Schema: readPackageSch(), - }, - }, - "change_log": { - Type: schema.TypeSet, - Computed: true, - Description: "Captures Fabric Cloud Router lifecycle change information", - Elem: &schema.Resource{ - Schema: equinix_schema.ChangeLogSch(), - }, - }, - "type": { - Type: schema.TypeString, - Computed: true, - Description: "Defines the Fabric Cloud Router type like XF_GATEWAY", - }, - "location": { - Type: schema.TypeSet, - Computed: true, - Description: "Fabric Cloud Router location", - Elem: &schema.Resource{ - Schema: equinix_schema.LocationSch(), - }, - }, - "project": { - Type: schema.TypeSet, - Computed: true, - Description: "Project information", - Elem: &schema.Resource{ - Schema: equinix_schema.ProjectSch(), - }, - }, - "account": { - Type: schema.TypeSet, - Computed: true, - Description: "Customer account information that is associated with this Fabric Cloud Router", - Elem: &schema.Resource{ - Schema: equinix_schema.AccountSch(), - }, - }, - "order": { - Type: schema.TypeSet, - Computed: true, - Description: "Order information related to this Fabric Cloud Router", - Elem: &schema.Resource{ - Schema: equinix_schema.OrderSch(), - }, - }, - "notifications": { - Type: schema.TypeList, - Computed: true, - Description: "Preferences for notifications on Fabric Cloud Router configuration or status changes", - Elem: &schema.Resource{ - Schema: equinix_schema.NotificationSch(), - }, - }, - } -} diff --git a/equinix/fabric_cloud_router_schema.go b/equinix/fabric_cloud_router_schema.go deleted file mode 100644 index 6c2d70921..000000000 --- a/equinix/fabric_cloud_router_schema.go +++ /dev/null @@ -1,169 +0,0 @@ -package equinix - -import ( - equinix_schema "github.com/equinix/terraform-provider-equinix/internal/fabric/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -) - -func createPackageSch() map[string]*schema.Schema { - return map[string]*schema.Schema{ - "code": { - Type: schema.TypeString, - Required: true, - Description: "Fabric Cloud Router package code", - }, - } -} - -var createPackageRes = &schema.Resource{ - Schema: createPackageSch(), -} - -var createCloudRouterAccountRes = &schema.Resource{ - Schema: createCloudRouterAccountSch(), -} - -func createCloudRouterAccountSch() map[string]*schema.Schema { - return map[string]*schema.Schema{ - "account_number": { - Type: schema.TypeInt, - Computed: true, - Optional: true, - Description: "Account Number", - }, - } -} - -var createCloudRouterProjectSchRes = &schema.Resource{ - Schema: createCloudRouterProjectSch(), -} - -func createCloudRouterProjectSch() map[string]*schema.Schema { - return map[string]*schema.Schema{ - "project_id": { - Type: schema.TypeString, - Computed: true, - Optional: true, - Description: "Project Id", - }, - "href": { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Unique Resource URL", - }, - } -} - -func createCloudRouterResourceSchema() map[string]*schema.Schema { - return map[string]*schema.Schema{ - "href": { - Type: schema.TypeString, - Computed: true, - Description: "Fabric Cloud Router URI information", - }, - "name": { - Type: schema.TypeString, - Required: true, - Description: "Fabric Cloud Router name. An alpha-numeric 24 characters string which can include only hyphens and underscores", - }, - "description": { - Type: schema.TypeString, - Optional: true, - Description: "Customer-provided Fabric Cloud Router description", - }, - "state": { - Type: schema.TypeString, - Computed: true, - Description: "Fabric Cloud Router overall state", - }, - "equinix_asn": { - Type: schema.TypeInt, - Computed: true, - Description: "Equinix ASN", - }, - "package": { - Type: schema.TypeSet, - Required: true, - Description: "Fabric Cloud Router location", - MaxItems: 1, - Elem: &schema.Resource{ - Schema: createPackageSch(), - }, - }, - "change_log": { - Type: schema.TypeSet, - Computed: true, - Description: "Captures Fabric Cloud Router lifecycle change information", - Elem: &schema.Resource{ - Schema: equinix_schema.ChangeLogSch(), - }, - }, - "type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{"XF_ROUTER"}, true), - Description: "Defines the FCR type like XF_ROUTER", - }, - "location": { - Type: schema.TypeSet, - Required: true, - Description: "Fabric Cloud Router location", - MaxItems: 1, - Elem: &schema.Resource{ - Schema: equinix_schema.LocationSch(), - }, - }, - "project": { - Type: schema.TypeSet, - Optional: true, - Description: "Fabric Cloud Router project", - MaxItems: 1, - Elem: &schema.Resource{ - Schema: createCloudRouterProjectSch(), - }, - }, - "account": { - Type: schema.TypeSet, - Optional: true, - Description: "Customer account information that is associated with this Fabric Cloud Router", - MaxItems: 1, - Elem: &schema.Resource{ - Schema: createCloudRouterAccountSch(), - }, - }, - "order": { - Type: schema.TypeSet, - Optional: true, - Description: "Order information related to this Fabric Cloud Router", - MaxItems: 1, - Elem: &schema.Resource{ - Schema: equinix_schema.OrderSch(), - }, - }, - "notifications": { - Type: schema.TypeList, - Required: true, - Description: "Preferences for notifications on Fabric Cloud Router configuration or status changes", - Elem: &schema.Resource{ - Schema: equinix_schema.NotificationSch(), - }, - }, - "bgp_ipv4_routes_count": { - Type: schema.TypeInt, - Computed: true, - Description: "Access point used and maximum number of IPv4 BGP routes", - }, - "bgp_ipv6_routes_count": { - Type: schema.TypeInt, - Computed: true, - Description: "Access point used and maximum number of IPv6 BGP routes", - }, - "connections_count": { - Type: schema.TypeInt, - Computed: true, - Description: "Number of connections associated with this Access point", - }, - } -} diff --git a/equinix/fabric_mapping_helper.go b/equinix/fabric_mapping_helper.go index d538b685a..d8a77b111 100644 --- a/equinix/fabric_mapping_helper.go +++ b/equinix/fabric_mapping_helper.go @@ -206,45 +206,6 @@ func interfaceToFabric(interfaceList []interface{}) v4.ModelInterface { return il } -func accountToCloudRouter(accountList []interface{}) v4.SimplifiedAccount { - sa := v4.SimplifiedAccount{} - for _, ll := range accountList { - llMap := ll.(map[string]interface{}) - ac := llMap["account_number"].(int) - sa = v4.SimplifiedAccount{AccountNumber: int64(ac)} - } - return sa -} - -func packageToCloudRouter(packageList []interface{}) v4.CloudRouterPackageType { - p := v4.CloudRouterPackageType{} - for _, pl := range packageList { - plMap := pl.(map[string]interface{}) - code := plMap["code"].(string) - p = v4.CloudRouterPackageType{Code: code} - } - return p -} - -func accountCloudRouterToTerra(account *v4.SimplifiedAccount) *schema.Set { - if account == nil { - return nil - } - accounts := []*v4.SimplifiedAccount{account} - mappedAccounts := make([]interface{}, len(accounts)) - for i, account := range accounts { - mappedAccounts[i] = map[string]interface{}{ - "account_number": int(account.AccountNumber), - } - } - accountSet := schema.NewSet( - schema.HashResource(createCloudRouterAccountRes), - mappedAccounts, - ) - - return accountSet -} - func operationToTerra(operation *v4.ConnectionOperation) *schema.Set { if operation == nil { return nil @@ -340,21 +301,6 @@ func cloudRouterToTerra(cloudRouter *v4.CloudRouter) *schema.Set { return linkedProtocolSet } -func cloudRouterPackageToTerra(packageType *v4.CloudRouterPackageType) *schema.Set { - packageTypes := []*v4.CloudRouterPackageType{packageType} - mappedPackages := make([]interface{}, len(packageTypes)) - for i, packageType := range packageTypes { - mappedPackages[i] = map[string]interface{}{ - "code": packageType.Code, - } - } - packageSet := schema.NewSet( - schema.HashResource(createPackageRes), - mappedPackages, - ) - return packageSet -} - func virtualDeviceToTerra(virtualDevice *v4.VirtualDevice) *schema.Set { if virtualDevice == nil { return nil @@ -875,23 +821,3 @@ func getUpdateRequests(conn v4.Connection, d *schema.ResourceData) ([][]v4.Conne return changeOps, nil } - -func getCloudRouterUpdateRequest(conn v4.CloudRouter, d *schema.ResourceData) (v4.CloudRouterChangeOperation, error) { - changeOps := v4.CloudRouterChangeOperation{} - existingName := conn.Name - existingPackage := conn.Package_.Code - updateNameVal := d.Get("name") - updatePackageVal := d.Get("conn.Package_.Code") - - log.Printf("existing name %s, existing Package %s, Update Name Request %s, Update Package Request %s ", - existingName, existingPackage, updateNameVal, updatePackageVal) - - if existingName != updateNameVal { - changeOps = v4.CloudRouterChangeOperation{Op: "replace", Path: "/name", Value: &updateNameVal} - } else if existingPackage != updatePackageVal { - changeOps = v4.CloudRouterChangeOperation{Op: "replace", Path: "/package", Value: &updatePackageVal} - } else { - return changeOps, fmt.Errorf("nothing to update for the connection %s", existingName) - } - return changeOps, nil -} diff --git a/equinix/provider.go b/equinix/provider.go index e690af081..c305fe1ed 100644 --- a/equinix/provider.go +++ b/equinix/provider.go @@ -84,7 +84,7 @@ func Provider() *schema.Provider { "equinix_ecx_l2_sellerprofiles": dataSourceECXL2SellerProfiles(), "equinix_fabric_routing_protocol": dataSourceRoutingProtocol(), "equinix_fabric_connection": dataSourceFabricConnection(), - "equinix_fabric_cloud_router": dataSourceCloudRouter(), + "equinix_fabric_cloud_router": dataSourceFabricCloudRouter(), "equinix_fabric_network": dataSourceFabricNetwork(), "equinix_fabric_port": dataSourceFabricPort(), "equinix_fabric_ports": dataSourceFabricGetPortsByName(), @@ -120,8 +120,8 @@ func Provider() *schema.Provider { "equinix_ecx_l2_connection": resourceECXL2Connection(), "equinix_ecx_l2_connection_accepter": resourceECXL2ConnectionAccepter(), "equinix_ecx_l2_serviceprofile": resourceECXL2ServiceProfile(), - "equinix_fabric_cloud_router": resourceCloudRouter(), "equinix_fabric_network": resourceFabricNetwork(), + "equinix_fabric_cloud_router": resourceFabricCloudRouter(), "equinix_fabric_connection": resourceFabricConnection(), "equinix_fabric_routing_protocol": resourceFabricRoutingProtocol(), "equinix_fabric_service_profile": resourceFabricServiceProfile(), diff --git a/equinix/resource_fabric_cloud_router.go b/equinix/resource_fabric_cloud_router.go index 96c6903a9..66f75d77f 100644 --- a/equinix/resource_fabric_cloud_router.go +++ b/equinix/resource_fabric_cloud_router.go @@ -3,6 +3,9 @@ package equinix import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "log" "strings" "time" @@ -15,11 +18,175 @@ import ( v4 "github.com/equinix-labs/fabric-go/fabric/v4" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourceCloudRouter() *schema.Resource { +func fabricCloudRouterPackageSch() map[string]*schema.Schema { + return map[string]*schema.Schema{ + "code": { + Type: schema.TypeString, + Required: true, + Description: "Fabric Cloud Router package code", + }, + } +} +func fabricCloudRouterAccountSch() map[string]*schema.Schema { + return map[string]*schema.Schema{ + "account_number": { + Type: schema.TypeInt, + Computed: true, + Optional: true, + Description: "Account Number", + }, + } +} +func fabricCloudRouterProjectSch() map[string]*schema.Schema { + return map[string]*schema.Schema{ + "project_id": { + Type: schema.TypeString, + Computed: true, + Optional: true, + Description: "Project Id", + }, + "href": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Unique Resource URL", + }, + } +} + +func fabricCloudRouterResourceSchema() map[string]*schema.Schema { + return map[string]*schema.Schema{ + "uuid": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Equinix-assigned Fabric Cloud Router identifier", + }, + "href": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Fabric Cloud Router URI information", + }, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 24), + Description: "Fabric Cloud Router name. An alpha-numeric 24 characters string which can include only hyphens and underscores", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Customer-provided Fabric Cloud Router description", + }, + "state": { + Type: schema.TypeString, + Computed: true, + Description: "Fabric Cloud Router overall state", + }, + "equinix_asn": { + Type: schema.TypeInt, + Computed: true, + Description: "Equinix ASN", + }, + "package": { + Type: schema.TypeSet, + Required: true, + Description: "Fabric Cloud Router Package Type", + MaxItems: 1, + Elem: &schema.Resource{ + Schema: fabricCloudRouterPackageSch(), + }, + }, + "change_log": { + Type: schema.TypeSet, + Computed: true, + Description: "Captures Fabric Cloud Router lifecycle change information", + Elem: &schema.Resource{ + Schema: equinix_fabric_schema.ChangeLogSch(), + }, + }, + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"XF_ROUTER"}, true), + Description: "Defines the FCR type like; XF_ROUTER", + }, + "location": { + Type: schema.TypeSet, + Required: true, + Description: "Fabric Cloud Router location", + MaxItems: 1, + Elem: &schema.Resource{ + Schema: equinix_fabric_schema.LocationSch(), + }, + }, + "project": { + Type: schema.TypeSet, + Required: true, + Description: "Customer resource hierarchy project information.Applicable to customers onboarded to Equinix Identity and Access Management. For more information see Identity and Access Management: Projects", + MaxItems: 1, + Elem: &schema.Resource{ + Schema: fabricCloudRouterProjectSch(), + }, + }, + "account": { + Type: schema.TypeSet, + Required: true, + Description: "Customer account information that is associated with this Fabric Cloud Router", + MaxItems: 1, + Elem: &schema.Resource{ + Schema: fabricCloudRouterAccountSch(), + }, + }, + "order": { + Type: schema.TypeSet, + Required: true, + Description: "Order information related to this Fabric Cloud Router", + MaxItems: 1, + Elem: &schema.Resource{ + Schema: equinix_fabric_schema.OrderSch(), + }, + }, + "notifications": { + Type: schema.TypeList, + Required: true, + Description: "Preferences for notifications on Fabric Cloud Router configuration or status changes", + Elem: &schema.Resource{ + Schema: equinix_fabric_schema.NotificationSch(), + }, + }, + "bgp_ipv4_routes_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of IPv4 BGP routes in use (including non-distinct prefixes)", + }, + "bgp_ipv6_routes_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of IPv6 BGP routes in use (including non-distinct prefixes)", + }, + "distinct_ipv4_prefixes_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of distinct IPv4 routes", + }, + "distinct_ipv6_prefixes_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of distinct IPv6 routes", + }, + "connections_count": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of connections associated with this Fabric Cloud Router instance", + }, + } +} + +func resourceFabricCloudRouter() *schema.Resource { return &schema.Resource{ Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(6 * time.Minute), @@ -27,35 +194,74 @@ func resourceCloudRouter() *schema.Resource { Delete: schema.DefaultTimeout(6 * time.Minute), Read: schema.DefaultTimeout(6 * time.Minute), }, - ReadContext: resourceCloudRouterRead, - CreateContext: resourceCloudRouterCreate, - UpdateContext: resourceCloudRouterUpdate, - DeleteContext: resourceCloudRouterDelete, + ReadContext: resourceFabricCloudRouterRead, + CreateContext: resourceFabricCloudRouterCreate, + UpdateContext: resourceFabricCloudRouterUpdate, + DeleteContext: resourceFabricCloudRouterDelete, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, - Schema: createCloudRouterResourceSchema(), + Schema: fabricCloudRouterResourceSchema(), Description: "Fabric V4 API compatible resource allows creation and management of Equinix Fabric Cloud Router", } } -func resourceCloudRouterCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func accountCloudRouterTerraToGo(accountList []interface{}) v4.SimplifiedAccount { + sa := v4.SimplifiedAccount{} + for _, ll := range accountList { + llMap := ll.(map[string]interface{}) + ac := llMap["account_number"].(int) + sa = v4.SimplifiedAccount{AccountNumber: int64(ac)} + } + return sa +} +func locationCloudRouterTerraToGo(locationList []interface{}) v4.SimplifiedLocationWithoutIbx { + sl := v4.SimplifiedLocationWithoutIbx{} + for _, ll := range locationList { + llMap := ll.(map[string]interface{}) + mc := llMap["metro_code"].(string) + sl = v4.SimplifiedLocationWithoutIbx{MetroCode: mc} + } + return sl +} +func packageCloudRouterTerraToGo(packageList []interface{}) v4.CloudRouterPackageType { + p := v4.CloudRouterPackageType{} + for _, pl := range packageList { + plMap := pl.(map[string]interface{}) + code := plMap["code"].(string) + p = v4.CloudRouterPackageType{Code: code} + } + return p +} +func projectCloudRouterTerraToGo(projectRequest []interface{}) v4.Project { + if projectRequest == nil { + return v4.Project{} + } + mappedPr := v4.Project{} + for _, pr := range projectRequest { + prMap := pr.(map[string]interface{}) + projectId := prMap["project_id"].(string) + mappedPr = v4.Project{ProjectId: projectId} + } + return mappedPr +} +func resourceFabricCloudRouterCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client := meta.(*config.Config).FabricClient ctx = context.WithValue(ctx, v4.ContextAccessToken, meta.(*config.Config).FabricAuthToken) schemaNotifications := d.Get("notifications").([]interface{}) notifications := equinix_fabric_schema.NotificationsToFabric(schemaNotifications) schemaAccount := d.Get("account").(*schema.Set).List() - account := accountToCloudRouter(schemaAccount) + account := accountCloudRouterTerraToGo(schemaAccount) schemaLocation := d.Get("location").(*schema.Set).List() - location := equinix_fabric_schema.LocationWithoutIBXToFabric(schemaLocation) + location := locationCloudRouterTerraToGo(schemaLocation) project := v4.Project{} schemaProject := d.Get("project").(*schema.Set).List() if len(schemaProject) != 0 { - project = equinix_fabric_schema.ProjectToFabric(schemaProject) + project = projectCloudRouterTerraToGo(schemaProject) } schemaPackage := d.Get("package").(*schema.Set).List() - packages := packageToCloudRouter(schemaPackage) + packages := packageCloudRouterTerraToGo(schemaPackage) createRequest := v4.CloudRouterPostRequest{ Name: d.Get("name").(string), @@ -82,10 +288,10 @@ func resourceCloudRouterCreate(ctx context.Context, d *schema.ResourceData, meta return diag.Errorf("error waiting for Cloud Router (%s) to be created: %s", d.Id(), err) } - return resourceCloudRouterRead(ctx, d, meta) + return resourceFabricCloudRouterRead(ctx, d, meta) } -func resourceCloudRouterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceFabricCloudRouterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client := meta.(*config.Config).FabricClient ctx = context.WithValue(ctx, v4.ContextAccessToken, meta.(*config.Config).FabricAuthToken) CloudRouter, _, err := client.CloudRoutersApi.GetCloudRouterByUuid(ctx, d.Id()) @@ -103,29 +309,82 @@ func resourceCloudRouterRead(ctx context.Context, d *schema.ResourceData, meta i func setCloudRouterMap(d *schema.ResourceData, fcr v4.CloudRouter) diag.Diagnostics { diags := diag.Diagnostics{} err := equinix_schema.SetMap(d, map[string]interface{}{ - "name": fcr.Name, - "href": fcr.Href, - "type": fcr.Type_, - "state": fcr.State, - "package": cloudRouterPackageToTerra(fcr.Package_), - "location": equinix_fabric_schema.LocationWithoutIBXToTerra(fcr.Location), - "change_log": equinix_fabric_schema.ChangeLogToTerra(fcr.ChangeLog), - "account": accountCloudRouterToTerra(fcr.Account), - "notifications": equinix_fabric_schema.NotificationsToTerra(fcr.Notifications), - "project": equinix_fabric_schema.ProjectToTerra(fcr.Project), - "equinix_asn": fcr.EquinixAsn, - "bgp_ipv4_routes_count": fcr.BgpIpv4RoutesCount, - "bgp_ipv6_routes_count": fcr.BgpIpv6RoutesCount, - "connections_count": fcr.ConnectionsCount, - "order": equinix_fabric_schema.OrderToTerra(fcr.Order), + "name": fcr.Name, + "href": fcr.Href, + "type": fcr.Type_, + "state": fcr.State, + "package": packageCloudRouterGoToTerra(fcr.Package_), + "location": equinix_fabric_schema.LocationWithoutIBXToTerra(fcr.Location), + "change_log": equinix_fabric_schema.ChangeLogToTerra(fcr.ChangeLog), + "account": accountCloudRouterToTerra(fcr.Account), + "notifications": equinix_fabric_schema.NotificationsToTerra(fcr.Notifications), + "project": equinix_fabric_schema.ProjectToTerra(fcr.Project), + "equinix_asn": fcr.EquinixAsn, + "bgp_ipv4_routes_count": fcr.BgpIpv4RoutesCount, + "bgp_ipv6_routes_count": fcr.BgpIpv6RoutesCount, + "distinct_ipv4_prefixes_count": fcr.DistinctIpv4PrefixesCount, + "distinct_ipv6_prefixes_count": fcr.DistinctIpv6PrefixesCount, + "connections_count": fcr.ConnectionsCount, + "order": equinix_fabric_schema.OrderToTerra(fcr.Order), }) if err != nil { return diag.FromErr(err) } return diags } +func accountCloudRouterToTerra(account *v4.SimplifiedAccount) *schema.Set { + if account == nil { + return nil + } + accounts := []*v4.SimplifiedAccount{account} + mappedAccounts := make([]interface{}, len(accounts)) + for i, account := range accounts { + mappedAccounts[i] = map[string]interface{}{ + "account_number": int(account.AccountNumber), + } + } + accountSet := schema.NewSet( + schema.HashResource(&schema.Resource{Schema: equinix_fabric_schema.AccountSch()}), + mappedAccounts, + ) + + return accountSet +} +func packageCloudRouterGoToTerra(packageType *v4.CloudRouterPackageType) *schema.Set { + packageTypes := []*v4.CloudRouterPackageType{packageType} + mappedPackages := make([]interface{}, len(packageTypes)) + for i, packageType := range packageTypes { + mappedPackages[i] = map[string]interface{}{ + "code": packageType.Code, + } + } + packageSet := schema.NewSet( + schema.HashResource(&schema.Resource{Schema: fabricCloudRouterPackageSch()}), + mappedPackages, + ) + return packageSet +} +func getCloudRouterUpdateRequest(conn v4.CloudRouter, d *schema.ResourceData) (v4.CloudRouterChangeOperation, error) { + changeOps := v4.CloudRouterChangeOperation{} + existingName := conn.Name + existingPackage := conn.Package_.Code + updateNameVal := d.Get("name") + updatePackageVal := d.Get("conn.Package_.Code") + + log.Printf("existing name %s, existing Package %s, Update Name Request %s, Update Package Request %s ", + existingName, existingPackage, updateNameVal, updatePackageVal) + + if existingName != updateNameVal { + changeOps = v4.CloudRouterChangeOperation{Op: "replace", Path: "/name", Value: &updateNameVal} + } else if existingPackage != updatePackageVal { + changeOps = v4.CloudRouterChangeOperation{Op: "replace", Path: "/package", Value: &updatePackageVal} + } else { + return changeOps, fmt.Errorf("nothing to update for the connection %s", existingName) + } + return changeOps, nil +} -func resourceCloudRouterUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceFabricCloudRouterUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client := meta.(*config.Config).FabricClient ctx = context.WithValue(ctx, v4.ContextAccessToken, meta.(*config.Config).FabricAuthToken) dbConn, err := waitUntilCloudRouterIsProvisioned(d.Id(), meta, ctx) @@ -216,7 +475,7 @@ func waitUntilCloudRouterIsProvisioned(uuid string, meta interface{}, ctx contex return dbConn, err } -func resourceCloudRouterDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceFabricCloudRouterDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { diags := diag.Diagnostics{} client := meta.(*config.Config).FabricClient ctx = context.WithValue(ctx, v4.ContextAccessToken, meta.(*config.Config).FabricAuthToken)