diff --git a/internal/planmodifiers/caseinsensitive.go b/internal/planmodifiers/caseinsensitive.go index 88f3be6bb..7a9d8df1f 100644 --- a/internal/planmodifiers/caseinsensitive.go +++ b/internal/planmodifiers/caseinsensitive.go @@ -15,12 +15,17 @@ func CaseInsensitiveString() planmodifier.String { type caseInsensitivePlanModifier struct{} func (d *caseInsensitivePlanModifier) PlanModifyString(ctx context.Context, request planmodifier.StringRequest, response *planmodifier.StringResponse) { + if request.StateValue.IsNull() && request.PlanValue.IsUnknown() { + return + } + oldValue := request.StateValue.ValueString() newValue := request.PlanValue.ValueString() result := oldValue - if !strings.EqualFold(strings.ToLower(newValue), strings.ToLower(oldValue)) { + if !strings.EqualFold(newValue, oldValue) { result = newValue + response.RequiresReplace = true } response.PlanValue = types.StringValue(result) diff --git a/internal/resources/metal/vlan/datasource.go b/internal/resources/metal/vlan/datasource.go index 1fa0353d2..9a751d450 100644 --- a/internal/resources/metal/vlan/datasource.go +++ b/internal/resources/metal/vlan/datasource.go @@ -3,6 +3,7 @@ package vlan import ( "context" "fmt" + "strings" equinix_errors "github.com/equinix/terraform-provider-equinix/internal/errors" "github.com/equinix/terraform-provider-equinix/internal/framework" @@ -115,10 +116,10 @@ func MatchingVlan(vlans []packngo.VirtualNetwork, vxlan int, projectID, facility if vxlan != 0 && v.VXLAN != vxlan { continue } - if facility != "" && v.FacilityCode != facility { + if facility != "" && !strings.EqualFold(v.FacilityCode, facility) { continue } - if metro != "" && v.MetroCode != metro { + if metro != "" && !strings.EqualFold(v.MetroCode, metro) { continue } matches = append(matches, v) @@ -128,7 +129,7 @@ func MatchingVlan(vlans []packngo.VirtualNetwork, vxlan int, projectID, facility } if len(matches) == 0 { - return nil, equinix_errors.FriendlyError(fmt.Errorf("Project %s does not have matching VLANs", projectID)) + return nil, equinix_errors.FriendlyError(fmt.Errorf("Project %s does not have matching VLANs for vlan [%d] and metro [%s]", projectID, vxlan, metro)) } return &matches[0], nil } diff --git a/internal/resources/metal/vlan/datasource_test.go b/internal/resources/metal/vlan/datasource_test.go index 6688f46e0..cae8a7deb 100644 --- a/internal/resources/metal/vlan/datasource_test.go +++ b/internal/resources/metal/vlan/datasource_test.go @@ -8,10 +8,10 @@ import ( "github.com/equinix/terraform-provider-equinix/internal/acceptance" "github.com/equinix/terraform-provider-equinix/internal/config" "github.com/equinix/terraform-provider-equinix/internal/resources/metal/vlan" - "github.com/hashicorp/terraform-plugin-testing/plancheck" "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/packethost/packngo" ) diff --git a/internal/resources/metal/vlan/models.go b/internal/resources/metal/vlan/models.go index bb4e61286..92da521d6 100644 --- a/internal/resources/metal/vlan/models.go +++ b/internal/resources/metal/vlan/models.go @@ -27,20 +27,26 @@ func (m *DataSourceModel) parse(vlan *packngo.VirtualNetwork) diag.Diagnostics { } m.VlanID = types.StringValue(vlan.ID) - - m.Facility = types.StringNull() - if vlan.FacilityCode != "" { - m.Facility = types.StringValue(vlan.FacilityCode) - } - m.Description = types.StringValue(vlan.Description) m.Vxlan = types.Int64Value(int64(vlan.VXLAN)) + var metroCode, facilityCode types.String + if vlan.Facility != nil { + facilityCode = types.StringValue(vlan.Facility.Code) + metroCode = types.StringValue(strings.ToLower(vlan.Facility.Metro.Code)) + } // version of this resource. StateFunc doesn't exist in terraform and it requires implementation // of bespoke logic before storing state. To ensure backward compatibility we ignore lower/upper // case diff for now, but we may want to require input upper case - if !strings.EqualFold(m.Metro.ValueString(), vlan.MetroCode) { - m.Metro = types.StringValue(vlan.MetroCode) + if !strings.EqualFold(m.Facility.ValueString(), facilityCode.ValueString()) { + m.Facility = facilityCode + } + + if vlan.Metro != nil { + metroCode = types.StringValue(strings.ToLower(vlan.Metro.Code)) + } + if !strings.EqualFold(m.Metro.ValueString(), metroCode.ValueString()) { + m.Metro = metroCode } deviceIds := make([]types.String, 0, len(vlan.Instances)) diff --git a/internal/resources/metal/vlan/resource.go b/internal/resources/metal/vlan/resource.go index 23028f6a2..6adf064bf 100644 --- a/internal/resources/metal/vlan/resource.go +++ b/internal/resources/metal/vlan/resource.go @@ -6,6 +6,8 @@ import ( "fmt" equinix_errors "github.com/equinix/terraform-provider-equinix/internal/errors" "github.com/equinix/terraform-provider-equinix/internal/framework" + "github.com/hashicorp/terraform-plugin-framework/types" + "strings" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -72,7 +74,7 @@ func (r *Resource) Create(ctx context.Context, request resource.CreateRequest, r Description: data.Description.ValueString(), } if !data.Metro.IsNull() { - createRequest.Metro = data.Metro.ValueString() + createRequest.Metro = strings.ToLower(data.Metro.ValueString()) createRequest.VXLAN = int(data.Vxlan.ValueInt64()) } if !data.Facility.IsNull() { @@ -99,7 +101,6 @@ func (r *Resource) Create(ctx context.Context, request resource.CreateRequest, r // Set state to fully populated data response.Diagnostics.Append(response.State.Set(ctx, &data)...) - return } func (r *Resource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) { @@ -145,6 +146,7 @@ func (r *Resource) Update(ctx context.Context, req resource.UpdateRequest, resp return } + data.Metro = types.StringValue(strings.ToLower(data.Metro.ValueString())) if diag := resp.State.Set(ctx, &data); diag.HasError() { resp.Diagnostics.Append(diag...) return diff --git a/internal/resources/metal/vlan/resource_schema.go b/internal/resources/metal/vlan/resource_schema.go index 3ad6f5261..11405c340 100644 --- a/internal/resources/metal/vlan/resource_schema.go +++ b/internal/resources/metal/vlan/resource_schema.go @@ -40,7 +40,6 @@ func resourceSchema(ctx context.Context) schema.Schema { Description: "Facility where to create the VLAN", DeprecationMessage: "Use metro instead of facility. For more information, read the migration guide: https://registry.terraform.io/providers/equinix/equinix/latest/docs/guides/migration_guide_facilities_to_metros_devices", Optional: true, - Computed: true, Validators: []validator.String{ stringvalidator.ConflictsWith(path.MatchRoot("metro")), }, @@ -54,11 +53,10 @@ func resourceSchema(ctx context.Context) schema.Schema { Optional: true, Computed: true, PlanModifiers: []planmodifier.String{ - //stringplanmodifier.RequiresReplace(), + stringplanmodifier.UseStateForUnknown(), equinixplanmodifiers.CaseInsensitiveString(), }, Validators: []validator.String{ - stringvalidator.ConflictsWith(path.MatchRoot("facility")), stringvalidator.ExactlyOneOf(path.MatchRoot("facility"), path.MatchRoot("metro")), }, @@ -66,6 +64,7 @@ func resourceSchema(ctx context.Context) schema.Schema { "vxlan": schema.Int64Attribute{ Description: "VLAN ID, must be unique in metro", PlanModifiers: []planmodifier.Int64{ + int64planmodifier.UseStateForUnknown(), int64planmodifier.RequiresReplace(), }, Optional: true,