-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: migrate resource and datasource equinix_metal_project to fr…
…amework (#604) Part of #612 --------- Signed-off-by: ocobleseqx <oscar.cobles@eu.equinix.com> Signed-off-by: Óscar Cobles <68897552+ocobles@users.noreply.github.com> Co-authored-by: Charles Treatman <ctreatman@equinix.com>
- Loading branch information
Showing
16 changed files
with
1,169 additions
and
459 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package planmodifiers | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
) | ||
|
||
func ImmutableInt64() planmodifier.Int64 { | ||
return &immutableInt64PlanModifier{} | ||
} | ||
|
||
type immutableInt64PlanModifier struct{} | ||
|
||
func (d *immutableInt64PlanModifier) PlanModifyInt64(ctx context.Context, request planmodifier.Int64Request, response *planmodifier.Int64Response) { | ||
if request.StateValue.IsNull() && request.PlanValue.IsUnknown() { | ||
return | ||
} | ||
|
||
oldValue := request.StateValue.ValueInt64() | ||
newValue := request.PlanValue.ValueInt64() | ||
|
||
if oldValue != 0 && newValue != oldValue { | ||
response.Diagnostics.AddAttributeError( | ||
request.Path, | ||
"Change not allowed", | ||
fmt.Sprintf( | ||
"Cannot modify the value of the `%s` field. Resource recreation would be required.", | ||
request.Path.String(), | ||
), | ||
) | ||
return | ||
} | ||
|
||
response.PlanValue = types.Int64Value(newValue) | ||
} | ||
|
||
func (d *immutableInt64PlanModifier) Description(ctx context.Context) string { | ||
return "Prevents modification of a int64 value if the old value is not null." | ||
} | ||
|
||
func (d *immutableInt64PlanModifier) MarkdownDescription(ctx context.Context) string { | ||
return d.Description(ctx) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package planmodifiers | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/path" | ||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
) | ||
|
||
func TestImmutableStringSet(t *testing.T) { | ||
testCases := []struct { | ||
Old, New, Expected int64 | ||
ExpectError bool | ||
}{ | ||
{ | ||
Old: 0, | ||
New: 1234, | ||
Expected: 1234, | ||
ExpectError: false, | ||
}, | ||
{ | ||
Old: 1234, | ||
New: 4321, | ||
Expected: 0, | ||
ExpectError: true, | ||
}, | ||
} | ||
|
||
testPlanModifier := ImmutableInt64() | ||
|
||
for i, testCase := range testCases { | ||
stateValue := types.Int64Value(testCase.Old) | ||
planValue := types.Int64Value(testCase.New) | ||
expectedValue := types.Int64Null() | ||
if testCase.Expected != 0 { | ||
expectedValue = types.Int64Value(testCase.Expected) | ||
} | ||
|
||
req := planmodifier.Int64Request{ | ||
StateValue: stateValue, | ||
PlanValue: planValue, | ||
Path: path.Root("test"), | ||
} | ||
|
||
var resp planmodifier.Int64Response | ||
|
||
testPlanModifier.PlanModifyInt64(context.Background(), req, &resp) | ||
|
||
if resp.Diagnostics.HasError() { | ||
if testCase.ExpectError == false { | ||
t.Fatalf("%d: got error modifying plan: %v", i, resp.Diagnostics.Errors()) | ||
} | ||
} | ||
|
||
if !resp.PlanValue.Equal(expectedValue) { | ||
t.Fatalf("%d: output plan value does not equal expected. Want %d plan value, got %d", i, expectedValue, resp.PlanValue.ValueInt64()) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package planmodifiers | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" | ||
) | ||
|
||
func ImmutableList() planmodifier.List { | ||
return &immutableListPlanModifier{} | ||
} | ||
|
||
type immutableListPlanModifier struct{} | ||
|
||
func (d *immutableListPlanModifier) PlanModifyList(ctx context.Context, request planmodifier.ListRequest, response *planmodifier.ListResponse) { | ||
|
||
if request.StateValue.IsNull() && request.PlanValue.IsNull() { | ||
return | ||
} | ||
|
||
if request.PlanValue.IsNull() && len(request.StateValue.Elements()) > 0 { | ||
response.Diagnostics.AddAttributeError( | ||
request.Path, | ||
"Change not allowed", | ||
fmt.Sprintf( | ||
"Elements of the `%s` list field can not be removed. Resource recreation would be required.", | ||
request.Path.String(), | ||
), | ||
) | ||
return | ||
} | ||
|
||
response.PlanValue = request.PlanValue | ||
} | ||
|
||
func (d *immutableListPlanModifier) Description(ctx context.Context) string { | ||
return "Allows adding elements to a list if it was initially empty and permits modifications, but disallows removals, requiring resource recreation." | ||
} | ||
|
||
func (d *immutableListPlanModifier) MarkdownDescription(ctx context.Context) string { | ||
return d.Description(ctx) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package planmodifiers | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/path" | ||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
) | ||
|
||
func TestImmutableListSet(t *testing.T) { | ||
testCases := []struct { | ||
Old, New, Expected []string | ||
ExpectError bool | ||
}{ | ||
{ | ||
Old: []string{}, | ||
New: []string{"test"}, | ||
Expected: []string{"test"}, | ||
ExpectError: false, | ||
}, | ||
{ | ||
Old: []string{"test"}, | ||
New: []string{}, | ||
Expected: []string{}, | ||
ExpectError: true, | ||
}, | ||
{ | ||
Old: []string{"foo"}, | ||
New: []string{"bar"}, | ||
Expected: []string{"bar"}, | ||
ExpectError: true, | ||
}, | ||
} | ||
|
||
testPlanModifier := ImmutableList() | ||
|
||
for i, testCase := range testCases { | ||
stateValue, _ := types.ListValueFrom(context.Background(), types.StringType, testCase.Old) | ||
planValue, _ := types.ListValueFrom(context.Background(), types.StringType, testCase.New) | ||
expectedValue, _ := types.ListValueFrom(context.Background(), types.StringType, testCase.Expected) | ||
|
||
req := planmodifier.ListRequest{ | ||
StateValue: stateValue, | ||
PlanValue: planValue, | ||
Path: path.Root("test"), | ||
} | ||
|
||
var resp planmodifier.ListResponse | ||
|
||
testPlanModifier.PlanModifyList(context.Background(), req, &resp) | ||
|
||
if resp.Diagnostics.HasError() { | ||
if testCase.ExpectError == false { | ||
t.Fatalf("%d: got error modifying plan: %v", i, resp.Diagnostics.Errors()) | ||
} | ||
} | ||
|
||
if !resp.PlanValue.Equal(expectedValue) { | ||
value, _ := resp.PlanValue.ToListValue(context.Background()) | ||
t.Fatalf("%d: output plan value does not equal expected. Want %v plan value, got %v", i, expectedValue, value) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package project | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/equinix/equinix-sdk-go/services/metalv1" | ||
equinix_errors "github.com/equinix/terraform-provider-equinix/internal/errors" | ||
fwtypes "github.com/equinix/terraform-provider-equinix/internal/framework/types" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/diag" | ||
) | ||
|
||
func fetchBGPConfig(ctx context.Context, client *metalv1.APIClient, projectID string) (*metalv1.BgpConfig, diag.Diagnostics) { | ||
var diags diag.Diagnostics | ||
|
||
bgpConfig, _, err := client.BGPApi.FindBgpConfigByProject(ctx, projectID).Execute() | ||
if err != nil { | ||
friendlyErr := equinix_errors.FriendlyError(err) | ||
diags.AddError( | ||
"Error reading BGP configuration", | ||
"Could not read BGP configuration for project with ID "+projectID+": "+friendlyErr.Error(), | ||
) | ||
return nil, diags | ||
} | ||
|
||
return bgpConfig, diags | ||
} | ||
|
||
func expandBGPConfig(ctx context.Context, bgpConfig fwtypes.ListNestedObjectValueOf[BGPConfigModel]) (*metalv1.BgpConfigRequestInput, error) { | ||
bgpConfigModel, _ := bgpConfig.ToSlice(ctx) | ||
bgpDeploymentType, err := metalv1.NewBgpConfigRequestInputDeploymentTypeFromValue(bgpConfigModel[0].DeploymentType.ValueString()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
bgpCreateRequest := metalv1.BgpConfigRequestInput{ | ||
DeploymentType: *bgpDeploymentType, | ||
Asn: int32(bgpConfigModel[0].ASN.ValueInt64()), | ||
} | ||
if !bgpConfigModel[0].MD5.IsNull() { | ||
bgpCreateRequest.Md5 = bgpConfigModel[0].MD5.ValueStringPointer() | ||
} | ||
|
||
return &bgpCreateRequest, nil | ||
} | ||
|
||
func handleBGPConfigChanges(ctx context.Context, client *metalv1.APIClient, plan, state *ResourceModel, projectID string) (*metalv1.BgpConfig, diag.Diagnostics) { | ||
var diags diag.Diagnostics | ||
var bgpConfig *metalv1.BgpConfig | ||
|
||
if plan.BGPConfig.IsNull() && state.BGPConfig.IsNull() { | ||
return bgpConfig, nil | ||
} | ||
|
||
bgpAdded := !plan.BGPConfig.IsNull() && state.BGPConfig.IsNull() | ||
bgpChanged := !plan.BGPConfig.IsNull() && !state.BGPConfig.IsNull() && !plan.BGPConfig.Equal(state.BGPConfig) | ||
|
||
if bgpAdded || bgpChanged { | ||
// Create BGP Config | ||
bgpCreateRequest, err := expandBGPConfig(ctx, plan.BGPConfig) | ||
if err != nil { | ||
diags.AddError( | ||
"Error creating project", | ||
"Could not validate BGP Config: "+err.Error(), | ||
) | ||
return nil, diags | ||
} | ||
createResp, err := client.BGPApi.RequestBgpConfig(ctx, projectID).BgpConfigRequestInput(*bgpCreateRequest).Execute() | ||
if err != nil { | ||
err = equinix_errors.FriendlyErrorForMetalGo(err, createResp) | ||
diags.AddError( | ||
"Error creating BGP configuration", | ||
"Could not create BGP configuration for project: "+err.Error(), | ||
) | ||
return nil, diags | ||
} | ||
// Fetch the newly created BGP Config | ||
bgpConfig, diags = fetchBGPConfig(ctx, client, projectID) | ||
diags.Append(diags...) | ||
} else { // assuming already exists | ||
// Fetch the existing BGP Config | ||
bgpConfig, diags = fetchBGPConfig(ctx, client, projectID) | ||
diags.Append(diags...) | ||
} | ||
|
||
return bgpConfig, diags | ||
} |
Oops, something went wrong.