Skip to content

Commit

Permalink
Merge pull request #919 from Juniper/912-allow-vn-creation-with-no-bi…
Browse files Browse the repository at this point in the history
…ndings-when-apstra-5x

Support virtual network resource without bindings; Improve config version constraints
  • Loading branch information
chrismarget-j authored Oct 16, 2024
2 parents 8170777 + 9b491df commit ffca275
Show file tree
Hide file tree
Showing 22 changed files with 698 additions and 627 deletions.
37 changes: 0 additions & 37 deletions apstra/api_versions/constraints.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package apiversions

import (
"github.com/hashicorp/go-version"
"github.com/hashicorp/terraform-plugin-framework/path"
)

var (
Expand All @@ -11,39 +10,3 @@ var (
Ge420 = version.MustConstraints(version.NewConstraint(">=" + Apstra420))
Ge421 = version.MustConstraints(version.NewConstraint(">=" + Apstra421))
)

type AttributeConstraint struct {
Path path.Path
Constraints version.Constraints
}

type OtherConstraint struct {
Message string
Constraints version.Constraints
}

type Constraints struct {
attributeConstraints []AttributeConstraint
otherConstraints []OtherConstraint
}

// AddAttributeConstraints should be used to add version constraints imposed by
// the presence of an attribute or attribute value in the configuration.
func (o *Constraints) AddAttributeConstraints(in AttributeConstraint) {
o.attributeConstraints = append(o.attributeConstraints, in)
}

// AddOtherConstraints should be used to add non-attribute-value-based version
// constraints, like those imposed by the absence of an attribute in the
// configuration.
func (o *Constraints) AddOtherConstraints(in OtherConstraint) {
o.otherConstraints = append(o.otherConstraints, in)
}

func (o *Constraints) AttributeConstraints() []AttributeConstraint {
return o.attributeConstraints
}

func (o *Constraints) OtherConstraints() []OtherConstraint {
return o.otherConstraints
}
44 changes: 0 additions & 44 deletions apstra/api_versions/validate.go

This file was deleted.

62 changes: 0 additions & 62 deletions apstra/blueprint/blueprint.go
Original file line number Diff line number Diff line change
Expand Up @@ -645,68 +645,6 @@ func (o *Blueprint) SetName(ctx context.Context, bpClient *apstra.TwoStageL3Clos
}
}

func (o Blueprint) VersionConstraints() apiversions.Constraints {
var response apiversions.Constraints

if utils.HasValue(o.FabricAddressing) {
response.AddAttributeConstraints(apiversions.AttributeConstraint{
Path: path.Root("fabric_addressing"),
Constraints: apiversions.Ge411,
})
}

if utils.HasValue(o.DefaultSviL3Mtu) {
response.AddAttributeConstraints(apiversions.AttributeConstraint{
Path: path.Root("default_svi_l3_mtu"),
Constraints: apiversions.Ge420,
})
}

if utils.HasValue(o.FabricMtu) {
response.AddAttributeConstraints(apiversions.AttributeConstraint{
Path: path.Root("fabric_mtu"),
Constraints: apiversions.Ge420,
})
}

if utils.HasValue(o.JunosEvpnMaxNexthopAndInterfaceNumber) {
response.AddAttributeConstraints(apiversions.AttributeConstraint{
Path: path.Root("junos_evpn_max_nexthop_and_interface_number"),
Constraints: apiversions.Ge420,
})
}

if utils.HasValue(o.JunosEvpnRoutingInstanceModeMacVrf) {
response.AddAttributeConstraints(apiversions.AttributeConstraint{
Path: path.Root("junos_evpn_routing_instance_mode_mac_vrf"),
Constraints: apiversions.Ge420,
})
}

if utils.HasValue(o.JunosExOverlayEcmp) {
response.AddAttributeConstraints(apiversions.AttributeConstraint{
Path: path.Root("junos_ex_overlay_ecmp"),
Constraints: apiversions.Ge420,
})
}

if utils.HasValue(o.JunosGracefulRestart) {
response.AddAttributeConstraints(apiversions.AttributeConstraint{
Path: path.Root("junos_graceful_restart"),
Constraints: apiversions.Ge420,
})
}

if utils.HasValue(o.OptimizeRoutingZoneFootprint) {
response.AddAttributeConstraints(apiversions.AttributeConstraint{
Path: path.Root("optimize_routing_zone_footprint"),
Constraints: apiversions.Ge420,
})
}

return response
}

func (o *Blueprint) GetFabricSettings(ctx context.Context, bp *apstra.TwoStageL3ClosClient, diags *diag.Diagnostics) {
fabricSettings, err := bp.GetFabricSettings(ctx)
if err != nil {
Expand Down
32 changes: 0 additions & 32 deletions apstra/blueprint/datacenter_generic_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,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"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
)

type DatacenterGenericSystem struct {
Expand Down Expand Up @@ -1101,34 +1100,3 @@ func (o *DatacenterGenericSystem) ClearConnectivityTemplatesFromLinks(ctx contex
return
}
}

func (o DatacenterGenericSystem) VersionConstraints(ctx context.Context, diags *diag.Diagnostics) apiversions.Constraints {
var result apiversions.Constraints

// cannot determine version constraints while links are unknown
if o.Links.IsUnknown() {
return result
}

for _, linkAV := range o.Links.Elements() {
if linkAV.IsUnknown() {
continue // skip unknown links
}

var dcgsl DatacenterGenericSystemLink
diags.Append(linkAV.(types.Object).As(ctx, &dcgsl, basetypes.ObjectAsOptions{})...)
if diags.HasError() {
return result
}

linkConstraints := dcgsl.versionConstraintsAsGenericSystemLink(ctx, path.Root("links").AtSetValue(linkAV), diags)
for _, ac := range linkConstraints.AttributeConstraints() {
result.AddAttributeConstraints(ac)
}
for _, oc := range linkConstraints.OtherConstraints() {
result.AddOtherConstraints(oc)
}
}

return result
}
17 changes: 0 additions & 17 deletions apstra/blueprint/datacenter_generic_system_link.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,12 @@ import (
"fmt"

"github.com/Juniper/apstra-go-sdk/apstra"
apiversions "github.com/Juniper/terraform-provider-apstra/apstra/api_versions"
"github.com/Juniper/terraform-provider-apstra/apstra/utils"
"github.com/hashicorp/go-version"
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
"github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
resourceSchema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
Expand Down Expand Up @@ -198,17 +195,3 @@ func (o *DatacenterGenericSystemLink) updateTransformId(ctx context.Context, sta
}
}
}

func (o *DatacenterGenericSystemLink) versionConstraintsAsGenericSystemLink(_ context.Context, path path.Path, _ *diag.Diagnostics) apiversions.Constraints {
var result apiversions.Constraints

// can't use tags in 4.1.1 or earlier because the API endpoint we use in Read() doesn't return them
if utils.HasValue(o.Tags) {
result.AddAttributeConstraints(apiversions.AttributeConstraint{
Path: path.AtName("tags"),
Constraints: version.MustConstraints(version.NewConstraint("> " + apiversions.Apstra411)),
})
}

return result
}
28 changes: 15 additions & 13 deletions apstra/blueprint/datacenter_virtual_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import (
"github.com/Juniper/apstra-go-sdk/apstra"
apiversions "github.com/Juniper/terraform-provider-apstra/apstra/api_versions"
apstravalidator "github.com/Juniper/terraform-provider-apstra/apstra/apstra_validator"
"github.com/Juniper/terraform-provider-apstra/apstra/compatibility"
"github.com/Juniper/terraform-provider-apstra/apstra/constants"
"github.com/Juniper/terraform-provider-apstra/apstra/design"
"github.com/Juniper/terraform-provider-apstra/apstra/utils"
"github.com/hashicorp/go-version"
"github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatordiag"
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
"github.com/hashicorp/terraform-plugin-framework-validators/mapvalidator"
Expand Down Expand Up @@ -370,13 +370,14 @@ func (o DatacenterVirtualNetwork) ResourceAttributes() map[string]resourceSchema
},
"bindings": resourceSchema.MapNestedAttribute{
MarkdownDescription: "Bindings make a Virtual Network available on Leaf Switches and Access Switches. " +
"At least one binding entry is required. The value is a map keyed by graph db node IDs of *either* " +
"Leaf Switches (non-redundant Leaf Switches) or Leaf Switch redundancy groups (redundant Leaf " +
"Switches). Practitioners are encouraged to consider using the " +
"At least one binding entry is required with Apstra 4.x. With Apstra 5.x, a Virtual Network with " +
"no bindings can be created by omitting (or setting `null`) this attribute. The value is a map " +
"keyed by graph db node IDs of *either* Leaf Switches (non-redundant Leaf Switches) or Leaf Switch " +
"redundancy groups (redundant Leaf Switches). Practitioners are encouraged to consider using the " +
"[`apstra_datacenter_virtual_network_binding_constructor`]" +
"(../data-sources/datacenter_virtual_network_binding_constructor) data source to populate " +
"this map.",
Required: true,
Optional: true,
Validators: []validator.Map{
mapvalidator.SizeAtLeast(1),
apstravalidator.WhenValueAtMustBeMap(
Expand Down Expand Up @@ -571,9 +572,10 @@ func (o *DatacenterVirtualNetwork) Request(ctx context.Context, diags *diag.Diag
}

if o.Type.ValueString() == apstra.VnTypeVlan.String() {
// Exactly one binding is required when type==vlan.
// Maximum of one binding is required when type==vlan.
// Apstra requires vlan == vni when creating a "vlan" type VN.
if vnBindings[0].VlanId != nil {
// VNI attribute is forbidden when type == VLAN
if len(vnBindings) > 0 && vnBindings[0].VlanId != nil {
v := apstra.VNI(*vnBindings[0].VlanId)
vnId = &v
}
Expand Down Expand Up @@ -917,14 +919,14 @@ func (o DatacenterVirtualNetwork) ValidateConfigBindingsReservation(ctx context.
}
}

func (o DatacenterVirtualNetwork) VersionConstraints() apiversions.Constraints {
var response apiversions.Constraints
func (o DatacenterVirtualNetwork) VersionConstraints() compatibility.ConfigConstraints {
var response compatibility.ConfigConstraints

if utils.HasValue(o.L3Mtu) {
if len(o.Bindings.Elements()) == 0 {
response.AddAttributeConstraints(
apiversions.AttributeConstraint{
Path: path.Root("l3_mtu"),
Constraints: version.MustConstraints(version.NewConstraint(">=" + apiversions.Apstra420)),
compatibility.AttributeConstraint{
Path: path.Root("bindings"),
Constraints: compatibility.VnEmptyBindingsOk,
},
)
}
Expand Down
12 changes: 8 additions & 4 deletions apstra/blueprint/vn_binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type VnBinding struct {
AccessIds types.Set `tfsdk:"access_ids"`
}

func (o VnBinding) attrTypes() map[string]attr.Type {
func (o VnBinding) AttrTypes() map[string]attr.Type {
return map[string]attr.Type{
"vlan_id": types.Int64Type,
"access_ids": types.SetType{ElemType: types.StringType},
Expand Down Expand Up @@ -105,20 +105,24 @@ func (o *VnBinding) LoadApiData(ctx context.Context, in apstra.VnBinding, diags
}

func newBindingMap(ctx context.Context, in []apstra.VnBinding, diags *diag.Diagnostics) types.Map {
if len(in) == 0 {
return types.MapNull(types.ObjectType{AttrTypes: VnBinding{}.AttrTypes()})
}

bindings := make(map[string]attr.Value)
for i := range in {
var b VnBinding
b.LoadApiData(ctx, in[i], diags)
if diags.HasError() {
return types.MapNull(types.ObjectType{AttrTypes: VnBinding{}.attrTypes()})
return types.MapNull(types.ObjectType{AttrTypes: VnBinding{}.AttrTypes()})
}
bindings[in[i].SystemId.String()] = types.ObjectValueMust(
VnBinding{}.attrTypes(),
VnBinding{}.AttrTypes(),
map[string]attr.Value{
"vlan_id": b.VlanId,
"access_ids": b.AccessIds,
},
)
}
return types.MapValueMust(types.ObjectType{AttrTypes: VnBinding{}.attrTypes()}, bindings)
return types.MapValueMust(types.ObjectType{AttrTypes: VnBinding{}.AttrTypes()}, bindings)
}
5 changes: 3 additions & 2 deletions apstra/blueprint/vn_binding_constructor.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package blueprint
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"
Expand Down Expand Up @@ -240,14 +241,14 @@ func (o *VnBindingConstructor) Compute(ctx context.Context, bpClient *apstra.Two
}

var d diag.Diagnostics
bindings[k], d = types.ObjectValueFrom(ctx, VnBinding{}.attrTypes(), b)
bindings[k], d = types.ObjectValueFrom(ctx, VnBinding{}.AttrTypes(), b)
diags.Append(d...)
if diags.HasError() {
return
}
}

o.Bindings = types.MapValueMust(types.ObjectType{AttrTypes: VnBinding{}.attrTypes()}, bindings)
o.Bindings = types.MapValueMust(types.ObjectType{AttrTypes: VnBinding{}.AttrTypes()}, bindings)
}

// accessSwitchIdsToParentLeafIds returns a map keyed by graph db 'system' node
Expand Down
Loading

0 comments on commit ffca275

Please sign in to comment.