Skip to content

Commit

Permalink
Merge branch 'main' into 829-implement-freeform-group-generators
Browse files Browse the repository at this point in the history
  • Loading branch information
bwJuniper authored Aug 28, 2024
2 parents 6e8c226 + d9d5e8c commit a48b9e5
Show file tree
Hide file tree
Showing 8 changed files with 274 additions and 30 deletions.
12 changes: 12 additions & 0 deletions apstra/data_source_freeform_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,18 @@ func (o *dataSourceFreeformResource) Read(ctx context.Context, req datasource.Re
return
}

// Read the resource assignments
assignedTo, err := bp.ListResourceAssignments(ctx, api.Id)
if err != nil {
resp.Diagnostics.AddError("error reading Resource Assignments", err.Error())
return
}

config.AssignedTo = utils.SetValueOrNull(ctx, types.StringType, assignedTo, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}

// Set state
resp.Diagnostics.Append(resp.State.Set(ctx, &config)...)
}
Expand Down
36 changes: 35 additions & 1 deletion apstra/freeform/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
apstravalidator "github.com/Juniper/terraform-provider-apstra/apstra/apstra_validator"
"github.com/Juniper/terraform-provider-apstra/apstra/utils"
"github.com/hashicorp/terraform-plugin-framework-nettypes/cidrtypes"
"github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
dataSourceSchema "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/diag"
Expand All @@ -33,6 +34,7 @@ type Resource struct {
Ipv4Value cidrtypes.IPv4Prefix `tfsdk:"ipv4_value"`
Ipv6Value cidrtypes.IPv6Prefix `tfsdk:"ipv6_value"`
GeneratorId types.String `tfsdk:"generator_id"`
AssignedTo types.Set `tfsdk:"assigned_to"`
}

func (o Resource) DataSourceAttributes() map[string]dataSourceSchema.Attribute {
Expand Down Expand Up @@ -62,7 +64,7 @@ func (o Resource) DataSourceAttributes() map[string]dataSourceSchema.Attribute {
Validators: []validator.String{stringvalidator.LengthAtLeast(1)},
},
"group_id": dataSourceSchema.StringAttribute{
MarkdownDescription: "Resource Group the Resource belongs to",
MarkdownDescription: "Resource Group the Resource belongs to.",
Computed: true,
},
"type": dataSourceSchema.StringAttribute{
Expand Down Expand Up @@ -108,6 +110,11 @@ func (o Resource) DataSourceAttributes() map[string]dataSourceSchema.Attribute {
MarkdownDescription: "ID of the group generator that created the group, if any.",
Computed: true,
},
"assigned_to": dataSourceSchema.SetAttribute{
ElementType: types.StringType,
Computed: true,
MarkdownDescription: "Set of node IDs to which the resource is assigned.",
},
}
}

Expand Down Expand Up @@ -202,6 +209,12 @@ func (o Resource) ResourceAttributes() map[string]resourceSchema.Attribute {
"Always `null` because groups created via resource declaration were not generated.",
Computed: true,
},
"assigned_to": resourceSchema.SetAttribute{
ElementType: types.StringType,
Optional: true,
MarkdownDescription: "Set of node IDs to which the resource is assigned",
Validators: []validator.Set{setvalidator.SizeAtLeast(1)},
},
}
}

Expand Down Expand Up @@ -280,3 +293,24 @@ func (o *Resource) LoadApiData(_ context.Context, in *apstra.FreeformRaResourceD
}
}
}

func (o Resource) NeedsUpdate(state Resource) bool {
switch {
case !o.Type.Equal(state.Type):
return true
case !o.Name.Equal(state.Name):
return true
case !o.AllocatedFrom.Equal(state.AllocatedFrom):
return true
case !o.GroupId.Equal(state.GroupId):
return true
case !o.IntValue.Equal(state.IntValue):
return true
case !o.Ipv4Value.Equal(state.Ipv4Value):
return true
case !o.Ipv6Value.Equal(state.Ipv6Value):
return true
}

return false
}
75 changes: 67 additions & 8 deletions apstra/resource_freeform_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,28 @@ func (o *resourceFreeformResource) Create(ctx context.Context, req resource.Crea
return
}

// record the id and provisionally set the state
plan.Id = types.StringValue(id.String())
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}

// set the resource assignments, if any
if !plan.AssignedTo.IsNull() {
var assignments []apstra.ObjectId
resp.Diagnostics.Append(plan.AssignedTo.ElementsAs(ctx, &assignments, false)...)
if resp.Diagnostics.HasError() {
return
}

err = bp.UpdateResourceAssignments(ctx, id, assignments)
if err != nil {
resp.Diagnostics.AddError("error updating Resource Assignments", err.Error())
return
}
}

// Read the resource back from Apstra to get computed values
api, err := bp.GetRaResource(ctx, id)
if err != nil {
Expand All @@ -176,7 +198,6 @@ func (o *resourceFreeformResource) Create(ctx context.Context, req resource.Crea
}

// load state objects
plan.Id = types.StringValue(id.String())
plan.LoadApiData(ctx, api.Data, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
Expand Down Expand Up @@ -219,6 +240,18 @@ func (o *resourceFreeformResource) Read(ctx context.Context, req resource.ReadRe
return
}

// Read the resource assignments
assignedTo, err := bp.ListResourceAssignments(ctx, api.Id)
if err != nil {
resp.Diagnostics.AddError("error reading Resource Assignments", err.Error())
return
}

state.AssignedTo = utils.SetValueOrNull(ctx, types.StringType, assignedTo, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}

// Set state
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}
Expand All @@ -231,6 +264,13 @@ func (o *resourceFreeformResource) Update(ctx context.Context, req resource.Upda
return
}

// Get state values
var state freeform.Resource
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

// get a client for the Freeform reference design
bp, err := o.getBpClientFunc(ctx, plan.BlueprintId.ValueString())
if err != nil {
Expand All @@ -251,17 +291,36 @@ func (o *resourceFreeformResource) Update(ctx context.Context, req resource.Upda
return
}

// Convert the plan into an API Request
request := plan.Request(ctx, &resp.Diagnostics)
// Update the resource if necessary
if plan.NeedsUpdate(state) {
// Convert the plan into an API Request
request := plan.Request(ctx, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}

// Update the Resource
err = bp.UpdateRaResource(ctx, apstra.ObjectId(plan.Id.ValueString()), request)
if err != nil {
resp.Diagnostics.AddError("error updating Freeform Resource", err.Error())
return
}
}

var planAssignments, stateAssignments []apstra.ObjectId
resp.Diagnostics.Append(plan.AssignedTo.ElementsAs(ctx, &planAssignments, false)...)
resp.Diagnostics.Append(state.AssignedTo.ElementsAs(ctx, &stateAssignments, false)...)
if resp.Diagnostics.HasError() {
return
}

// Update the Resource
err = bp.UpdateRaResource(ctx, apstra.ObjectId(plan.Id.ValueString()), request)
if err != nil {
resp.Diagnostics.AddError("error updating Freeform Resource", err.Error())
return
// update the assignments if necessary
if !utils.SlicesAreEqualSets(planAssignments, stateAssignments) {
err = bp.UpdateResourceAssignments(ctx, apstra.ObjectId(plan.Id.ValueString()), planAssignments)
if err != nil {
resp.Diagnostics.AddError("error updating Resource Assignments", err.Error())
return
}
}

// Read the resource back from Apstra to get computed values
Expand Down
Loading

0 comments on commit a48b9e5

Please sign in to comment.