Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add switch name validation to rack_type resource #936

Merged
merged 1 commit into from
Oct 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 19 additions & 18 deletions apstra/design/rack_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package design
import (
"context"
"fmt"
"sort"
"strings"

"github.com/Juniper/apstra-go-sdk/apstra"
"github.com/Juniper/terraform-provider-apstra/apstra/utils"
"github.com/hashicorp/terraform-plugin-framework-validators/mapvalidator"
Expand All @@ -16,8 +19,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"sort"
"strings"
)

type RackType struct {
Expand Down Expand Up @@ -270,17 +271,17 @@ func (o *RackType) Request(ctx context.Context, diags *diag.Diagnostics) *apstra
return nil
}

leafSwitches := o.leafSwitches(ctx, diags)
leafSwitches := o.LeafSwitchMap(ctx, diags)
if diags.HasError() {
return nil
}

accessSwitches := o.accessSwitches(ctx, diags)
accessSwitches := o.AccessSwitchMap(ctx, diags)
if diags.HasError() {
return nil
}

genericSystems := o.genericSystems(ctx, diags)
genericSystems := o.GenericSystemMap(ctx, diags)
if diags.HasError() {
return nil
}
Expand Down Expand Up @@ -397,7 +398,7 @@ func ValidateRackType(ctx context.Context, in *apstra.RackType, diags *diag.Diag
}
}

func (o *RackType) leafSwitches(ctx context.Context, diags *diag.Diagnostics) map[string]LeafSwitch {
func (o *RackType) LeafSwitchMap(ctx context.Context, diags *diag.Diagnostics) map[string]LeafSwitch {
leafSwitches := make(map[string]LeafSwitch, len(o.LeafSwitches.Elements()))
d := o.LeafSwitches.ElementsAs(ctx, &leafSwitches, false)
diags.Append(d...)
Expand All @@ -409,7 +410,7 @@ func (o *RackType) leafSwitches(ctx context.Context, diags *diag.Diagnostics) ma
}

func (o *RackType) leafSwitchByName(ctx context.Context, requested string, diags *diag.Diagnostics) *LeafSwitch {
leafSwitches := o.leafSwitches(ctx, diags)
leafSwitches := o.LeafSwitchMap(ctx, diags)
if diags.HasError() {
return nil
}
Expand All @@ -421,7 +422,7 @@ func (o *RackType) leafSwitchByName(ctx context.Context, requested string, diags
return nil
}

func (o *RackType) accessSwitches(ctx context.Context, diags *diag.Diagnostics) map[string]AccessSwitch {
func (o *RackType) AccessSwitchMap(ctx context.Context, diags *diag.Diagnostics) map[string]AccessSwitch {
accessSwitches := make(map[string]AccessSwitch, len(o.AccessSwitches.Elements()))
d := o.AccessSwitches.ElementsAs(ctx, &accessSwitches, false)
diags.Append(d...)
Expand All @@ -433,7 +434,7 @@ func (o *RackType) accessSwitches(ctx context.Context, diags *diag.Diagnostics)
}

func (o *RackType) accessSwitchByName(ctx context.Context, requested string, diags *diag.Diagnostics) *AccessSwitch {
accessSwitches := o.accessSwitches(ctx, diags)
accessSwitches := o.AccessSwitchMap(ctx, diags)
if diags.HasError() {
return nil
}
Expand All @@ -445,7 +446,7 @@ func (o *RackType) accessSwitchByName(ctx context.Context, requested string, dia
return nil
}

func (o *RackType) genericSystems(ctx context.Context, diags *diag.Diagnostics) map[string]GenericSystem {
func (o *RackType) GenericSystemMap(ctx context.Context, diags *diag.Diagnostics) map[string]GenericSystem {
genericSystems := make(map[string]GenericSystem, len(o.GenericSystems.Elements()))
d := o.GenericSystems.ElementsAs(ctx, &genericSystems, true)
diags.Append(d...)
Expand All @@ -457,12 +458,12 @@ func (o *RackType) genericSystems(ctx context.Context, diags *diag.Diagnostics)
}

//func (o *RackType) genericSystemByName(ctx context.Context, requested string, diags *diag.Diagnostics) *GenericSystem {
// genericSystems := o.genericSystems(ctx, diags)
// GenericSystemMap := o.GenericSystemMap(ctx, diags)
// if diags.HasError() {
// return nil
// }
//
// if gs, ok := genericSystems[requested]; ok {
// if gs, ok := GenericSystemMap[requested]; ok {
// return &gs
// }
//
Expand All @@ -474,13 +475,13 @@ func (o *RackType) genericSystems(ctx context.Context, diags *diag.Diagnostics)
// RackType to be used as state.
func (o *RackType) CopyWriteOnlyElements(ctx context.Context, src *RackType, diags *diag.Diagnostics) {
// first extract native go structs from the TF set of objects
dstLeafSwitches := o.leafSwitches(ctx, diags)
dstAccessSwitches := o.accessSwitches(ctx, diags)
dstGenericSystems := o.genericSystems(ctx, diags)
dstLeafSwitches := o.LeafSwitchMap(ctx, diags)
dstAccessSwitches := o.AccessSwitchMap(ctx, diags)
dstGenericSystems := o.GenericSystemMap(ctx, diags)

// invoke the CopyWriteOnlyElements on every leaf switch object
for name, dstLeafSwitch := range dstLeafSwitches {
srcLeafSwitch, ok := src.leafSwitches(ctx, diags)[name]
srcLeafSwitch, ok := src.LeafSwitchMap(ctx, diags)[name]
if !ok {
continue
}
Expand All @@ -497,7 +498,7 @@ func (o *RackType) CopyWriteOnlyElements(ctx context.Context, src *RackType, dia

// invoke the CopyWriteOnlyElements on every access switch object
for name, dstAccessSwitch := range dstAccessSwitches {
srcAccessSwitch, ok := src.accessSwitches(ctx, diags)[name]
srcAccessSwitch, ok := src.AccessSwitchMap(ctx, diags)[name]
if !ok {
continue
}
Expand All @@ -514,7 +515,7 @@ func (o *RackType) CopyWriteOnlyElements(ctx context.Context, src *RackType, dia

// invoke the CopyWriteOnlyElements on every generic system object
for name, dstGenericSystem := range dstGenericSystems {
srcGenericSystem, ok := src.genericSystems(ctx, diags)[name]
srcGenericSystem, ok := src.GenericSystemMap(ctx, diags)[name]
if !ok {
continue
}
Expand Down
92 changes: 89 additions & 3 deletions apstra/resource_rack_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@ package tfapstra

import (
"context"
"fmt"

"github.com/Juniper/apstra-go-sdk/apstra"
"github.com/Juniper/terraform-provider-apstra/apstra/design"
"github.com/Juniper/terraform-provider-apstra/apstra/utils"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
)

var _ resource.ResourceWithConfigure = &resourceRackType{}
var _ resourceWithSetClient = &resourceRackType{}
var (
_ resource.ResourceWithConfigure = &resourceRackType{}
_ resource.ResourceWithValidateConfig = &resourceRackType{}
_ resourceWithSetClient = &resourceRackType{}
)

type resourceRackType struct {
client *apstra.Client
Expand All @@ -32,6 +38,87 @@ func (o *resourceRackType) Schema(_ context.Context, _ resource.SchemaRequest, r
}
}

func (o *resourceRackType) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) {
// Retrieve values from config
var config design.RackType
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
}

if config.LeafSwitches.IsUnknown() || config.AccessSwitches.IsUnknown() || config.GenericSystems.IsUnknown() {
return // cannot proceed
}

leafSwitches := config.LeafSwitchMap(ctx, &resp.Diagnostics)
accessSwitches := config.AccessSwitchMap(ctx, &resp.Diagnostics)
genericSystems := config.GenericSystemMap(ctx, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}

for accessSwitchName, accessSwitch := range accessSwitches {
if _, ok := leafSwitches[accessSwitchName]; ok {
resp.Diagnostics.AddAttributeError(
path.Root("access_switches").AtMapKey(accessSwitchName),
errInvalidConfig,
fmt.Sprintf("switch names must be unique - cannot have leaf and switches named %q", accessSwitchName),
)
}

if accessSwitch.Links.IsUnknown() {
return // cannot proceed
}

links := accessSwitch.GetLinks(ctx, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}

for linkName, link := range links {
if link.TargetSwitchName.IsUnknown() {
return // cannot proceed
}

_, leafSwitchExists := leafSwitches[link.TargetSwitchName.ValueString()]
if !leafSwitchExists {
resp.Diagnostics.AddAttributeError(
path.Root("access_switches").AtMapKey(accessSwitchName).AtName("links").AtMapKey(linkName),
errInvalidConfig,
fmt.Sprintf("switch named %q is not among the declared leaf switches", link.TargetSwitchName.ValueString()),
)
}
}
}

for genericSystemName, genericSystem := range genericSystems {
if genericSystem.Links.IsUnknown() {
return // cannot proceed
}

links := genericSystem.GetLinks(ctx, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}

for linkName, link := range links {
if link.TargetSwitchName.IsUnknown() {
return // cannot proceed
}

_, leafSwitchExists := leafSwitches[link.TargetSwitchName.ValueString()]
_, accessSwitchExists := accessSwitches[link.TargetSwitchName.ValueString()]
if !leafSwitchExists && !accessSwitchExists {
resp.Diagnostics.AddAttributeError(
path.Root("generic_systems").AtMapKey(genericSystemName).AtName("links").AtMapKey(linkName),
errInvalidConfig,
fmt.Sprintf("switch named %q is not among the declared leaf or access switches", link.TargetSwitchName.ValueString()),
)
}
}
}
}

func (o *resourceRackType) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
// Retrieve values from plan
var plan design.RackType
Expand Down Expand Up @@ -186,7 +273,6 @@ func (o *resourceRackType) Delete(ctx context.Context, req resource.DeleteReques
resp.Diagnostics.AddError("error deleting Rack Type", err.Error())
return
}

}

func (o *resourceRackType) setClient(client *apstra.Client) {
Expand Down
Loading