Skip to content

Commit

Permalink
feat: (CXF 90011) Updating Metal & Fabric Provider with NIMF function…
Browse files Browse the repository at this point in the history
…ality (#626)

- Added authorization_code to metal_interconnection schema.
- Added buildSharedPortVCVLANCreateRequest() function for the connection
type shared_port_vlan request.
- Added DataSource and Resource Acc Tests for Vlan Port Share
functionality.
- Added "METAL_NETWORK" to Fabric connection Access Point Type schema
- Updated Fabric Go SDK Version to 0.9.0
  • Loading branch information
srushti-patl committed Apr 1, 2024
2 parents 4d0b305 + b225209 commit d63009a
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 50 deletions.
2 changes: 1 addition & 1 deletion equinix/resource_fabric_connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ func accessPointSch() *schema.Resource {
"type": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{"COLO", "VD", "VG", "SP", "IGW", "SUBNET", "CLOUD_ROUTER", "NETWORK"}, true),
ValidateFunc: validation.StringInSlice([]string{"COLO", "VD", "VG", "SP", "IGW", "SUBNET", "CLOUD_ROUTER", "NETWORK", "METAL_NETWORK"}, true),
Description: "Access point type - COLO, VD, VG, SP, IGW, SUBNET, CLOUD_ROUTER, NETWORK",
},
"account": {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.21

require (
github.com/antihax/optional v1.0.0
github.com/equinix-labs/fabric-go v0.7.1
github.com/equinix-labs/fabric-go v0.9.0
github.com/equinix/ecx-go/v2 v2.3.1
github.com/equinix/equinix-sdk-go v0.35.0
github.com/equinix/ne-go v1.16.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,8 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
github.com/equinix-labs/fabric-go v0.7.1 h1:4yk0IKXMcc72rkRVbcYHokAEc1uUB06t6NXK+DtSsbs=
github.com/equinix-labs/fabric-go v0.7.1/go.mod h1:oqgGS3GOI8hHGPJKsAwDOEX0qRHl52sJGvwA/zMSd90=
github.com/equinix-labs/fabric-go v0.9.0 h1:BDJlVNaxpn1cSvjkTgy2zNr7srf8rF+7qOnLd2JxofU=
github.com/equinix-labs/fabric-go v0.9.0/go.mod h1:b/fvMHgVruNItuBIs7nZbcKc2ie4ZatkDHPM47DCF08=
github.com/equinix/ecx-go/v2 v2.3.1 h1:gFcAIeyaEUw7S8ebqApmT7E/S7pC7Ac3wgScp89fkPU=
github.com/equinix/ecx-go/v2 v2.3.1/go.mod h1:FvCdZ3jXU8Z4CPKig2DT+4J2HdwgRK17pIcznM7RXyk=
github.com/equinix/equinix-sdk-go v0.35.0 h1:p/uwA8QPBAuNnKGc3mQkwjw+6++qUadLNnKFQ8jw+wg=
Expand Down
4 changes: 4 additions & 0 deletions internal/resources/metal/connection/datasource_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ func dataSourceSchema(ctx context.Context) schema.Schema {
ElementType: fwtypes.NewObjectTypeOf[ServiceTokenModel](ctx),
Computed: true,
},
"authorization_code": schema.StringAttribute{
Description: "Only used with Fabric Shared connection. Fabric uses this token to be able to give more detailed information about the Metal end of the network, when viewing resources from within Fabric.",
Computed: true,
},
},
}
}
55 changes: 55 additions & 0 deletions internal/resources/metal/connection/datasource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,61 @@ func testDataSourceMetalConnectionConfig_withVlans(r int) string {
r, r, r, r)
}

func TestAccDataSourceMetalConnection_sharedPort(t *testing.T) {
rInt := acctest.RandInt()

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acceptance.TestAccPreCheckMetal(t) },
ExternalProviders: acceptance.TestExternalProviders,
ProtoV5ProviderFactories: acceptance.ProtoV5ProviderFactories,
CheckDestroy: testAccMetalConnectionCheckDestroyed,
Steps: []resource.TestStep{
{
Config: testAccDataSourceMetalConnectionConfig_SharedPort(rInt),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.equinix_metal_connection.test", "metro", "sv"),
resource.TestCheckResourceAttr(
"data.equinix_metal_connection.test", "contact_email", "tfacc@example.com"),
resource.TestCheckResourceAttrSet("data.equinix_metal_connection.test", "authorization_code"),
resource.TestCheckResourceAttrSet("data.equinix_metal_connection.test", "redundancy"),
),
},
},
})
}

func testAccDataSourceMetalConnectionConfig_SharedPort(r int) string {
return fmt.Sprintf(`
resource "equinix_metal_project" "test" {
name = "tfacc-conn-pro-%d"
}
resource "equinix_metal_vlan" "test1" {
description = "tfacc-conn-vlan1-%d"
metro = "sv"
project_id = equinix_metal_project.test.id
}
resource "equinix_metal_connection" "test" {
name = "tfacc-conn-%d"
project_id = equinix_metal_project.test.id
type = "shared_port_vlan"
redundancy = "primary"
metro = "sv"
speed = "50Mbps"
contact_email = "tfacc@example.com"
vlans = [
equinix_metal_vlan.test1.vxlan,
]
}
data "equinix_metal_connection" "test" {
connection_id = equinix_metal_connection.test.id
}`,
r, r, r)
}

// Test to verify that switching from SDKv2 to the Framework has not affected provider's behavior
// TODO (ocobles): once migrated, this test may be removed
func TestAccDataSourceMetalConnection_withVlans_upgradeFromVersion(t *testing.T) {
Expand Down
91 changes: 47 additions & 44 deletions internal/resources/metal/connection/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,50 +15,52 @@ import (
)

type ResourceModel struct {
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Facility types.String `tfsdk:"facility"`
Metro types.String `tfsdk:"metro"`
Redundancy types.String `tfsdk:"redundancy"`
ContactEmail types.String `tfsdk:"contact_email"`
Type types.String `tfsdk:"type"`
ProjectID types.String `tfsdk:"project_id"`
Speed types.String `tfsdk:"speed"`
Description types.String `tfsdk:"description"`
Mode types.String `tfsdk:"mode"`
Tags types.List `tfsdk:"tags"` // List of strings
Vlans types.List `tfsdk:"vlans"` // List of ints
Vrfs types.List `tfsdk:"vrfs"` // List of strings
ServiceTokenType types.String `tfsdk:"service_token_type"`
OrganizationID types.String `tfsdk:"organization_id"`
Status types.String `tfsdk:"status"`
Token types.String `tfsdk:"token"`
Ports fwtypes.ListNestedObjectValueOf[PortModel] `tfsdk:"ports"` // List of Port
ServiceTokens fwtypes.ListNestedObjectValueOf[ServiceTokenModel] `tfsdk:"service_tokens"` // List of ServiceToken
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Facility types.String `tfsdk:"facility"`
Metro types.String `tfsdk:"metro"`
Redundancy types.String `tfsdk:"redundancy"`
ContactEmail types.String `tfsdk:"contact_email"`
Type types.String `tfsdk:"type"`
ProjectID types.String `tfsdk:"project_id"`
AuthorizationCode types.String `tfsdk:"authorization_code"`
Speed types.String `tfsdk:"speed"`
Description types.String `tfsdk:"description"`
Mode types.String `tfsdk:"mode"`
Tags types.List `tfsdk:"tags"` // List of strings
Vlans types.List `tfsdk:"vlans"` // List of ints
Vrfs types.List `tfsdk:"vrfs"` // List of strings
ServiceTokenType types.String `tfsdk:"service_token_type"`
OrganizationID types.String `tfsdk:"organization_id"`
Status types.String `tfsdk:"status"`
Token types.String `tfsdk:"token"`
Ports fwtypes.ListNestedObjectValueOf[PortModel] `tfsdk:"ports"` // List of Port
ServiceTokens fwtypes.ListNestedObjectValueOf[ServiceTokenModel] `tfsdk:"service_tokens"` // List of ServiceToken
}

type DataSourceModel struct {
ID types.String `tfsdk:"id"`
ConnectionID types.String `tfsdk:"connection_id"`
Name types.String `tfsdk:"name"`
Facility types.String `tfsdk:"facility"`
Metro types.String `tfsdk:"metro"`
Redundancy types.String `tfsdk:"redundancy"`
ContactEmail types.String `tfsdk:"contact_email"`
Type types.String `tfsdk:"type"`
ProjectID types.String `tfsdk:"project_id"`
Speed types.String `tfsdk:"speed"`
Description types.String `tfsdk:"description"`
Mode types.String `tfsdk:"mode"`
Tags types.List `tfsdk:"tags"` // List of strings
Vlans types.List `tfsdk:"vlans"` // List of ints
Vrfs types.List `tfsdk:"vrfs"` // List of strings
ServiceTokenType types.String `tfsdk:"service_token_type"`
OrganizationID types.String `tfsdk:"organization_id"`
Status types.String `tfsdk:"status"`
Token types.String `tfsdk:"token"`
Ports fwtypes.ListNestedObjectValueOf[PortModel] `tfsdk:"ports"` // List of Port
ServiceTokens fwtypes.ListNestedObjectValueOf[ServiceTokenModel] `tfsdk:"service_tokens"` // List of ServiceToken
ID types.String `tfsdk:"id"`
ConnectionID types.String `tfsdk:"connection_id"`
Name types.String `tfsdk:"name"`
Facility types.String `tfsdk:"facility"`
Metro types.String `tfsdk:"metro"`
Redundancy types.String `tfsdk:"redundancy"`
ContactEmail types.String `tfsdk:"contact_email"`
Type types.String `tfsdk:"type"`
ProjectID types.String `tfsdk:"project_id"`
AuthorizationCode types.String `tfsdk:"authorization_code"`
Speed types.String `tfsdk:"speed"`
Description types.String `tfsdk:"description"`
Mode types.String `tfsdk:"mode"`
Tags types.List `tfsdk:"tags"` // List of strings
Vlans types.List `tfsdk:"vlans"` // List of ints
Vrfs types.List `tfsdk:"vrfs"` // List of strings
ServiceTokenType types.String `tfsdk:"service_token_type"`
OrganizationID types.String `tfsdk:"organization_id"`
Status types.String `tfsdk:"status"`
Token types.String `tfsdk:"token"`
Ports fwtypes.ListNestedObjectValueOf[PortModel] `tfsdk:"ports"` // List of Port
ServiceTokens fwtypes.ListNestedObjectValueOf[ServiceTokenModel] `tfsdk:"service_tokens"` // List of ServiceToken
}

type PortModel struct {
Expand Down Expand Up @@ -89,7 +91,7 @@ func (m *DataSourceModel) parse(ctx context.Context, conn *metalv1.Interconnecti
&m.ID, &m.OrganizationID, &m.Name, &m.Facility, &m.Metro,
&m.Description, &m.ContactEmail, &m.Status, &m.Redundancy,
&m.Token, &m.Type, &m.Mode, &m.ServiceTokenType, &m.Speed,
&m.ProjectID, &m.Vlans, &m.Vrfs, &m.Ports, &m.ServiceTokens,
&m.ProjectID, &m.AuthorizationCode, &m.Vlans, &m.Vrfs, &m.Ports, &m.ServiceTokens,
)

connTags, diags := types.ListValueFrom(ctx, types.StringType, conn.Tags)
Expand All @@ -108,7 +110,7 @@ func (m *ResourceModel) parse(ctx context.Context, conn *metalv1.Interconnection
&m.ID, &m.OrganizationID, &m.Name, &m.Facility, &m.Metro,
&m.Description, &m.ContactEmail, &m.Status, &m.Redundancy,
&m.Token, &m.Type, &m.Mode, &m.ServiceTokenType, &m.Speed,
&m.ProjectID, &m.Vlans, &m.Vrfs, &m.Ports, &m.ServiceTokens,
&m.ProjectID, &m.AuthorizationCode, &m.Vlans, &m.Vrfs, &m.Ports, &m.ServiceTokens,
)

connTags, diags := types.ListValueFrom(ctx, types.StringType, conn.Tags)
Expand Down Expand Up @@ -136,7 +138,7 @@ func parseConnection(
ctx context.Context,
conn *metalv1.Interconnection,
id, orgID, name, facility, metro, description, contactEmail, status, redundancy,
token, typ, mode, serviceTokenType, speed, projectID *basetypes.StringValue,
token, typ, mode, serviceTokenType, speed, projectID, authorizationCode *basetypes.StringValue,
vlans *basetypes.ListValue,
vrfs *basetypes.ListValue,
ports *fwtypes.ListNestedObjectValueOf[PortModel],
Expand All @@ -154,6 +156,7 @@ func parseConnection(
*redundancy = types.StringValue(string(conn.GetRedundancy()))
*token = types.StringValue(conn.GetToken())
*typ = types.StringValue(string(conn.GetType()))
*authorizationCode = types.StringValue(conn.GetAuthorizationCode())

// TODO(ocobles) we were using "StateFunc: converters.ToLowerIf" for "metro" field in the sdkv2
// version of this resource. StateFunc doesn't exist in terraform and it requires implementation
Expand Down
44 changes: 43 additions & 1 deletion internal/resources/metal/connection/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (r *Resource) Create(
var err error
var conn *metalv1.Interconnection

if plan.Type.ValueString() == string(metalv1.INTERCONNECTIONTYPE_SHARED) {
if plan.Type.ValueString() == string(metalv1.INTERCONNECTIONTYPE_SHARED) || plan.Type.ValueString() == string(metalv1.INTERCONNECTIONTYPE_SHARED_PORT_VLAN) {
request := client.InterconnectionsApi.CreateProjectInterconnection(ctx, projectID).
CreateOrganizationInterconnectionRequest(createRequest)

Expand Down Expand Up @@ -377,6 +377,36 @@ func buildVRFFabricVCCreateRequest(ctx context.Context, plan ResourceModel, req
return diags
}

func buildSharedPortVCVLANCreateRequest(ctx context.Context, plan ResourceModel, req *metalv1.CreateOrganizationInterconnectionRequest) diag.Diagnostics {
diags := validateSharedConnection(plan)

project := plan.ProjectID.ValueString()

req.SharedPortVCVlanCreateInput = &metalv1.SharedPortVCVlanCreateInput{
Type: metalv1.SHAREDPORTVCVLANCREATEINPUTTYPE_SHARED_PORT_VLAN,

Name: plan.Name.ValueString(),
Project: project,
Metro: plan.Metro.ValueString(),
Speed: plan.Speed.ValueStringPointer(),
}

if email := plan.ContactEmail.ValueString(); email != "" {
req.SharedPortVCVlanCreateInput.ContactEmail = &email
}
if description := plan.Description.ValueString(); description != "" {
req.SharedPortVCVlanCreateInput.Description = &description
}

vlansDiags := plan.Vlans.ElementsAs(ctx, &req.SharedPortVCVlanCreateInput.Vlans, true)
diags.Append(vlansDiags...)

tagDiags := getPlanTags(ctx, plan, &req.SharedPortVCVlanCreateInput.Tags)
diags.Append(tagDiags...)

return diags
}

func getPlanTags(ctx context.Context, plan ResourceModel, tags *[]string) diag.Diagnostics {
if len(plan.Tags.Elements()) != 0 {
return plan.Tags.ElementsAs(context.Background(), tags, false)
Expand Down Expand Up @@ -432,6 +462,7 @@ func validateSharedConnection(plan ResourceModel) (diags diag.Diagnostics) {
func buildCreateRequest(ctx context.Context, plan ResourceModel) (request metalv1.CreateOrganizationInterconnectionRequest, diags diag.Diagnostics) {
hasVlans := len(plan.Vlans.Elements()) != 0
hasVrfs := len(plan.Vrfs.Elements()) != 0

connType := metalv1.InterconnectionType(plan.Type.ValueString())

if hasVlans && hasVrfs {
Expand All @@ -458,6 +489,14 @@ func buildCreateRequest(ctx context.Context, plan ResourceModel) (request metalv
"Shared connections must specify either vlans or vrfs",
)

return
} else if connType == metalv1.INTERCONNECTIONTYPE_SHARED_PORT_VLAN && !(hasVlans) {
diags.AddAttributeError(
path.Root("type"),
"Must specify vlans",
"Shared port connections must specify vlans",
)

return
}

Expand All @@ -475,6 +514,9 @@ func buildCreateRequest(ctx context.Context, plan ResourceModel) (request metalv
var requestFunc func(context.Context, ResourceModel, *metalv1.CreateOrganizationInterconnectionRequest) diag.Diagnostics

switch {
case hasVlans && connType == metalv1.INTERCONNECTIONTYPE_SHARED_PORT_VLAN:
requestFunc = buildSharedPortVCVLANCreateRequest

case hasVlans:
requestFunc = buildVLANFabricVCCreateRequest

Expand Down
7 changes: 6 additions & 1 deletion internal/resources/metal/connection/resource_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func resourceSchema(ctx context.Context) schema.Schema {
},
},
"type": schema.StringAttribute{
Description: "Connection type - dedicated or shared",
Description: "Connection type - dedicated, shared or shared_port_vlan",
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
Expand All @@ -82,6 +82,7 @@ func resourceSchema(ctx context.Context) schema.Schema {
stringvalidator.OneOf(
string(metalv1.INTERCONNECTIONTYPE_DEDICATED),
string(metalv1.INTERCONNECTIONTYPE_SHARED),
string(metalv1.INTERCONNECTIONTYPE_SHARED_PORT_VLAN),
),
},
},
Expand Down Expand Up @@ -194,6 +195,10 @@ func resourceSchema(ctx context.Context) schema.Schema {
listplanmodifier.UseStateForUnknown(),
},
},
"authorization_code": schema.StringAttribute{
Description: "Only used with Fabric Shared connection. Fabric uses this token to be able to give more detailed information about the Metal end of the network, when viewing resources from within Fabric.",
Computed: true,
},
},
}
}
Loading

0 comments on commit d63009a

Please sign in to comment.