Skip to content

Commit

Permalink
Merge pull request #224 from equinix/zside_service_token_feature
Browse files Browse the repository at this point in the history
add attribute zside_service_token to equinix_ecx_l2_connection
  • Loading branch information
displague authored Jul 15, 2022
2 parents a7ecacd + bb71256 commit 28170ac
Show file tree
Hide file tree
Showing 7 changed files with 374 additions and 91 deletions.
55 changes: 43 additions & 12 deletions docs/resources/equinix_ecx_l2_connection.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ layer 2 connections.

## Example Usage

### Non-redundant Connection from own Equinix Port
### Non-redundant Connection from own Equinix Fabric Port

```hcl
data "equinix_ecx_l2_sellerprofile" "aws" {
Expand All @@ -35,7 +35,7 @@ resource "equinix_ecx_l2_connection" "port-2-aws" {
}
```

### Redundant Connection from own Equinix Ports
### Redundant Connection from own Equinix Fabric Ports

```hcl
data "equinix_ecx_l2_sellerprofile" "azure" {
Expand Down Expand Up @@ -112,6 +112,25 @@ resource "equinix_ecx_l2_connection" "token-to-gcp" {
}
```

### Non-redundant Connection from own Equinix Fabric Port to an Equinix customer port using Z-Side Service token

```hcl
data "equinix_ecx_port" "sv-qinq-pri" {
name = "CX-SV5-NL-Dot1q-BO-10G-PRI"
}
resource "equinix_ecx_l2_connection" "port-to-token" {
name = "tf-port-token"
zside_service_token = "e9c22453-d3a7-4d5d-9112-d50173531392"
speed = 200
speed_unit = "MB"
notifications = ["john@equinix.com", "marry@equinix.com"]
seller_metro_code = "FR"
port_uuid = data.equinix_ecx_port.sv-qinq-pri.id
vlan_stag = 1000
}
```

-> **NOTE:** See [Equinix Fabric connecting to the cloud](../guides/equinix_fabric_cloud_providers.md)
guide for more details on how to connect to a CSP.

Expand All @@ -128,16 +147,20 @@ hyphens and underscores
notifications.
* `purchase_order_number` - (Optional) Connection's purchase order number to reflect on the invoice
* `port_uuid` - (Required when `device_uuid` or `service_token` are not set) Unique identifier of
the Equinix port from which the connection would originate.
the Equinix Fabric Port from which the connection would originate.
* `device_uuid` - (Required when `port_uuid` or `service_token` are not set) Unique identifier of
the Network Edge virtual device from which the connection would originate.
* `device_interface_id` - (Optional) Applicable with `device_uuid`, identifier of network interface
on a given device, used for a connection. If not specified then first available interface will be
selected.
* `service_token`- (Required when `port_uuid` or `device_uuid` are not set) - Unique Equinix Fabric
key given by a provider that grants you authorization to the Equinix Port or virtual device from
which the connection would originate.
More details in [A-Side Fabric Service Tokens](https://docs.equinix.com/en-us/Content/Interconnection/Fabric/service%20tokens/Fabric-Service-Tokens.htm).
* `service_token`- (Required when `port_uuid` or `device_uuid` are not set) - A-side
service tokens authorize you to create a connection from a customer port, which created the token
for you, to a service profile or your own port.
More details in [A-Side Fabric Service Tokens](https://docs.equinix.com/en-us/Content/Interconnection/Fabric/service%20tokens/Fabric-Service-Tokens.htm#:~:text=the%20service%20token.-,A%2DSide%20Service%20Tokens,-If%20you%20want).
* `zside_service_token`- (Required when `profile_uuid` or `zside_port_uuid` are not set) - Z-side
service tokens authorize you to create a connection from your port or virtual device to a customer
port which created the token for you. `zside_service_token` cannot be used with `secondary_connection`.
More details in [Z-Side Fabric Service Tokens](https://docs.equinix.com/en-us/Content/Interconnection/Fabric/service%20tokens/Fabric-Service-Tokens.htm#:~:text=requirements%20per%20provider.-,Z%2DSide%20Service%20Tokens,-If%20you%20want).

-> **NOTE:** Service tokens can't be reused. To recreate a resource or to create a new one for
another connection even from same interconnection asset, you will need to request another token
Expand Down Expand Up @@ -187,7 +210,7 @@ connectivity. See [Secondary Connection](#secondary-connection) below for more d

-> **NOTE:** Some service provider do not directly support redundant connections in their service
profiles. However, some of them offer active/active (BGP multipath) or active/passive (failover)
configurations in their platforms and you can still achieve that highly resilient network
configurations in their platforms and you still achieve that highly resilient network
connections by creating an `equinix_ecx_l2_connection` resource for each connection instead of
defining a `secondary_connection` block.

Expand All @@ -198,15 +221,15 @@ The `secondary_connection` block supports the following arguments:
specified primary `speed` will be used.
* `speed_unit` - (Optional) Unit of the speed/bandwidth to be allocated to the secondary
connection. If not specified primary `speed_unit` will be used.
* `port_uuid` - (Optional) Applicable with primary `port_uuid`. Identifier of the Equinix port from
* `port_uuid` - (Optional) Applicable with primary `port_uuid`. Identifier of the Equinix Fabric Port from
which the secondary connection would originate. If not specified primary `port_uuid` will be used.
* `device_uuid` - (Optional) Applicable with primary `device_uuid`. Identifier of the Network Edge
virtual device from which the secondary connection would originate. If not specified primary
`device_uuid` will be used.
* `device_interface_id` - (Optional) Applicable with `device_uuid`, identifier of network interface
on a given device. If not specified then first available interface will be selected.
* `service_token`- (Optional) Required with primary `service_token`. Unique Equinix Fabric key
given by a provider that grants you authorization to enable connectivity from an Equinix Port or
given by a provider that grants you authorization to enable connectivity from an Equinix Fabric Port or
virtual device. Each connection (primary and secondary) requires a separate token.
More details in [Fabric Service Tokens](https://docs.equinix.com/en-us/Content/Interconnection/Fabric/service%20tokens/Fabric-Service-Tokens.htm).
* `vlan_stag` - (Required when `port_uuid` is set) S-Tag/Outer-Tag of the secondary connection, a
Expand Down Expand Up @@ -238,12 +261,15 @@ assigned by the Fabric.
* `zside_vlan_stag` - When not provided as an argument, it is S-Tag/Outer-Tag of the connection on
the Z side, assigned by the Fabric.
* `actions` - One or more pending actions to complete connection provisioning.
* `vendor_token` - The Equinix Fabric Token the connection was created with. Applicable if the
connection was created with a `service_token` (a-side) or `zside_service_token` (z-side).
* `secondary_connection`:
* `zside_port_uuid`
* `zside_vlan_stag`
* `zside_vlan_ctag`
* `redundancy_type`
* `redundancy_group`
* `vendor_token`

## Update operation behavior

Expand All @@ -266,15 +292,20 @@ options:

## Import

-> **NOTE:** Connections created with a Service Token (both a-side/z-side), will populate the token
into `vendor_token` but `service_token` and `zside_service_token` will remain empty.

Equinix L2 connections can be imported using an existing `id`:

```sh
existing_connection_id='example-uuid-1'
terraform import equinix_ecx_l2_connection.example ${existing_connection_id}
```

**Please Note** that to import a redundant connection you must concatenate `id` of both connections
(primary and secondary) into a single string separated by `:`, e.g.,
-> **NOTE:** To import a redundant connection you must concatenate `id` of both connections
(primary and secondary) into a single string separated by `:`.

To import a redundant Equinix L2 connection:

```sh
existing_primary_connection_id='example-uuid-1'
Expand Down
60 changes: 56 additions & 4 deletions docs/resources/equinix_metal_connection.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,68 @@ Use this resource to request the creation an Interconnection asset to connect wi

## Example Usage

### Shared Connection with a_side token - Redundant Connection from Equinix Metal to a Cloud Service Provider

```hcl
resource "equinix_metal_connection" "test" {
name = "My Interconnection"
project_id = equinix_metal_project.test.id
resource "equinix_metal_connection" "example" {
name = "tf-metal-to-azure"
project_id = local.project_id
type = "shared"
redundancy = "redundant"
metro = "sv"
speed = "50Mbps"
speed = "1000Mbps"
service_token_type = "a_side"
}
data "equinix_ecx_l2_sellerprofile" "example" {
name = "Azure ExpressRoute"
organization_global_name = "Microsoft"
}
resource "equinix_ecx_l2_connection" "example" {
name = "tf-metal-to-azure"
profile_uuid = data.equinix_ecx_l2_sellerprofile.example.uuid
speed = azurerm_express_route_circuit.example.bandwidth_in_mbps
speed_unit = "MB"
notifications = ["example@equinix.com"]
service_token = equinix_metal_connection.example.service_tokens.0.id
seller_metro_code = "AM"
authorization_key = azurerm_express_route_circuit.example.service_key
named_tag = "PRIVATE"
secondary_connection {
name = "tf-metal-to-azure"-sec"
service_token = equinix_metal_connection.example.service_tokens.1.id
}
}
```

### Shared Connection with z_side token - Non-redundant Connection from your own Equinix Fabric Port to Equinix Metal

```hcl
resource "equinix_metal_connection" "example" {
name = "tf-port-to-metal"
project_id = local.project_id
type = "shared"
redundancy = "primary"
metro = "FR"
speed = "200Mbps"
service_token_type = "z_side"
}
data "equinix_ecx_port" "example" {
name = "CX-FR5-NL-Dot1q-BO-1G-PRI"
}
resource "equinix_ecx_l2_connection" "example" {
name = "tf-port-to-metal"
zside_service_token = equinix_metal_connection.example.service_tokens.0.id
speed = "200"
speed_unit = "MB"
notifications = ["example@equinix.com"]
seller_metro_code = "FR"
port_uuid = data.equinix_ecx_port.example.id
vlan_stag = 1020
}
```

## Argument Reference
Expand Down
68 changes: 61 additions & 7 deletions equinix/resource_ecx_l2_connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ var ecxL2ConnectionSchemaNames = map[string]string{
"NamedTag": "named_tag",
"AdditionalInfo": "additional_info",
"ZSidePortUUID": "zside_port_uuid",
"ZSideServiceToken": "zside_service_token",
"ZSideVlanSTag": "zside_vlan_stag",
"ZSideVlanCTag": "zside_vlan_ctag",
"SellerRegion": "seller_region",
Expand All @@ -44,6 +45,7 @@ var ecxL2ConnectionSchemaNames = map[string]string{
"SecondaryConnection": "secondary_connection",
"Actions": "actions",
"ServiceToken": "service_token",
"VendorToken": "vendor_token",
}

var ecxL2ConnectionDescriptions = map[string]string{
Expand All @@ -64,6 +66,7 @@ var ecxL2ConnectionDescriptions = map[string]string{
"NamedTag": "The type of peering to set up in case when connecting to Azure Express Route. One of PRIVATE, MICROSOFT, MANUAL, PUBLIC (MANUAL and PUBLIC are deprecated and not available for new connections)",
"AdditionalInfo": "One or more additional information key-value objects",
"ZSidePortUUID": "Unique identifier of the port on the remote side (z-side)",
"ZSideServiceToken": "Unique Equinix Fabric key given by a provider that grants you authorization to enable connectivity to a shared multi-tenant port (z-side)",
"ZSideVlanSTag": "S-Tag/Outer-Tag of the connection on the remote side (z-side)",
"ZSideVlanCTag": "C-Tag/Inner-Tag of the connection on the remote side (z-side)",
"SellerRegion": "The region in which the seller port resides",
Expand All @@ -75,6 +78,7 @@ var ecxL2ConnectionDescriptions = map[string]string{
"SecondaryConnection": "Definition of secondary connection for redundant, HA connectivity",
"Actions": "One or more pending actions to complete connection provisioning",
"ServiceToken": "Unique Equinix Fabric key given by a provider that grants you authorization to enable connectivity from a shared multi-tenant port (a-side)",
"VendorToken": "The Equinix Fabric Token the connection was created with. Applicable if the connection was created with a ServiceToken (a-side) or ZSideServiceToken (z-side)",
}

var ecxL2ConnectionAdditionalInfoSchemaNames = map[string]string{
Expand Down Expand Up @@ -166,7 +170,11 @@ func createECXL2ConnectionResourceSchema() map[string]*schema.Schema {
Optional: true,
Computed: true,
ForceNew: true,
AtLeastOneOf: []string{ecxL2ConnectionSchemaNames["ProfileUUID"], ecxL2ConnectionSchemaNames["ZSidePortUUID"]},
AtLeastOneOf: []string{
ecxL2ConnectionSchemaNames["ProfileUUID"],
ecxL2ConnectionSchemaNames["ZSidePortUUID"],
ecxL2ConnectionSchemaNames["ZSideServiceToken"],
},
ValidateFunc: validation.StringIsNotEmpty,
Description: ecxL2ConnectionDescriptions["ProfileUUID"],
},
Expand Down Expand Up @@ -365,6 +373,25 @@ func createECXL2ConnectionResourceSchema() map[string]*schema.Schema {
ConflictsWith: []string{ecxL2ConnectionSchemaNames["PortUUID"], ecxL2ConnectionSchemaNames["DeviceUUID"]},
Description: ecxL2ConnectionDescriptions["ServiceToken"],
},
ecxL2ConnectionSchemaNames["ZSideServiceToken"]: {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringIsNotEmpty,
ConflictsWith: []string{
ecxL2ConnectionSchemaNames["ServiceToken"],
ecxL2ConnectionSchemaNames["ProfileUUID"],
ecxL2ConnectionSchemaNames["ZSidePortUUID"],
ecxL2ConnectionSchemaNames["AuthorizationKey"],
ecxL2ConnectionSchemaNames["SecondaryConnection"],
},
Description: ecxL2ConnectionDescriptions["ZSideServiceToken"],
},
ecxL2ConnectionSchemaNames["VendorToken"]: {
Type: schema.TypeString,
Computed: true,
Description: ecxL2ConnectionDescriptions["VendorToken"],
},
}
}

Expand Down Expand Up @@ -592,6 +619,11 @@ func createECXL2ConnectionSecondaryResourceSchema() map[string]*schema.Schema {
},
Description: ecxL2ConnectionDescriptions["ServiceToken"],
},
ecxL2ConnectionSchemaNames["VendorToken"]: {
Type: schema.TypeString,
Computed: true,
Description: ecxL2ConnectionDescriptions["VendorToken"],
},
}
}

Expand Down Expand Up @@ -828,6 +860,9 @@ func createECXL2Connections(d *schema.ResourceData) (*ecx.L2Connection, *ecx.L2C
if v, ok := d.GetOk(ecxL2ConnectionSchemaNames["ServiceToken"]); ok {
primary.ServiceToken = ecx.String(v.(string))
}
if v, ok := d.GetOk(ecxL2ConnectionSchemaNames["ZSideServiceToken"]); ok {
primary.ZSideServiceToken = ecx.String(v.(string))
}
if v, ok := d.GetOk(ecxL2ConnectionSchemaNames["AuthorizationKey"]); ok {
primary.AuthorizationKey = ecx.String(v.(string))
}
Expand Down Expand Up @@ -907,8 +942,22 @@ func updateECXL2ConnectionResource(primary *ecx.L2Connection, secondary *ecx.L2C
if err := d.Set(ecxL2ConnectionSchemaNames["RedundancyGroup"], primary.RedundancyGroup); err != nil {
return fmt.Errorf("error reading RedundancyGroup: %s", err)
}
if err := d.Set(ecxL2ConnectionSchemaNames["ServiceToken"], primary.ServiceToken); err != nil {
return fmt.Errorf("error reading ServiceToken: %s", err)
if err := d.Set(ecxL2ConnectionSchemaNames["VendorToken"], primary.VendorToken); err != nil {
return fmt.Errorf("error reading VendorToken: %s", err)
}
if v, ok := d.GetOk(ecxL2ConnectionSchemaNames["ServiceToken"]); ok {
if ecx.StringValue(primary.VendorToken) != v.(string){
if err := d.Set(ecxL2ConnectionSchemaNames["ServiceToken"], primary.VendorToken); err != nil {
return fmt.Errorf("error reading ServiceToken: %s", err)
}
}
}
if v, ok := d.GetOk(ecxL2ConnectionSchemaNames["ZSideServiceToken"]); ok {
if ecx.StringValue(primary.VendorToken) != v.(string){
if err := d.Set(ecxL2ConnectionSchemaNames["ZSideServiceToken"], primary.VendorToken); err != nil {
return fmt.Errorf("error reading ZSideServiceToken: %s", err)
}
}
}
if err := d.Set(ecxL2ConnectionSchemaNames["Actions"], flattenECXL2ConnectionActions(primary.Actions)); err != nil {
return fmt.Errorf("error reading Actions: %s", err)
Expand Down Expand Up @@ -937,9 +986,6 @@ func flattenECXL2ConnectionSecondary(previous, conn *ecx.L2Connection) interface
transformed[ecxL2ConnectionSchemaNames["PortUUID"]] = conn.PortUUID
transformed[ecxL2ConnectionSchemaNames["DeviceUUID"]] = conn.DeviceUUID
transformed[ecxL2ConnectionSchemaNames["DeviceInterfaceID"]] = conn.DeviceInterfaceID
if previous != nil {
transformed[ecxL2ConnectionSchemaNames["DeviceInterfaceID"]] = previous.DeviceInterfaceID
}
transformed[ecxL2ConnectionSchemaNames["VlanSTag"]] = conn.VlanSTag
transformed[ecxL2ConnectionSchemaNames["VlanCTag"]] = conn.VlanCTag
transformed[ecxL2ConnectionSchemaNames["ZSidePortUUID"]] = conn.ZSidePortUUID
Expand All @@ -951,7 +997,15 @@ func flattenECXL2ConnectionSecondary(previous, conn *ecx.L2Connection) interface
transformed[ecxL2ConnectionSchemaNames["RedundancyType"]] = conn.RedundancyType
transformed[ecxL2ConnectionSchemaNames["RedundancyGroup"]] = conn.RedundancyGroup
transformed[ecxL2ConnectionSchemaNames["Actions"]] = flattenECXL2ConnectionActions(conn.Actions)
transformed[ecxL2ConnectionSchemaNames["ServiceToken"]] = conn.ServiceToken
transformed[ecxL2ConnectionSchemaNames["VendorToken"]] = conn.VendorToken
if previous != nil {
transformed[ecxL2ConnectionSchemaNames["DeviceInterfaceID"]] = previous.DeviceInterfaceID
transformed[ecxL2ConnectionSchemaNames["ServiceToken"]] = previous.ServiceToken
prevSToken := ecx.StringValue(previous.ServiceToken)
if prevSToken != "" && ecx.StringValue(conn.VendorToken) != prevSToken {
transformed[ecxL2ConnectionSchemaNames["ServiceToken"]] = conn.VendorToken
}
}
return []interface{}{transformed}
}

Expand Down
Loading

0 comments on commit 28170ac

Please sign in to comment.