Skip to content

Commit

Permalink
Merge pull request #459 from Juniper/task/458-cenralize-get-set-deplo…
Browse files Browse the repository at this point in the history
…y-mode

Task/458: Centralize get/set deploy mode
  • Loading branch information
chrismarget-j authored Nov 21, 2023
2 parents 2681c03 + fa16db5 commit 118e813
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 103 deletions.
69 changes: 0 additions & 69 deletions apstra/blueprint/device_allocation.go
Original file line number Diff line number Diff line change
Expand Up @@ -642,72 +642,3 @@ func (o *DeviceAllocation) deviceProfileNodeIdFromDeviceKey(ctx context.Context,

o.DeviceProfileNodeId = types.StringValue(result.Items[0].DeviceProfile.Id)
}

func (o *DeviceAllocation) SetNodeDeployMode(ctx context.Context, client *apstra.Client, diags *diag.Diagnostics) {
if o.DeployMode.IsNull() {
return
}

if o.DeployMode.IsUnknown() {
o.GetNodeDeployMode(ctx, client, diags)
return
}

var deployMode apstra.NodeDeployMode
err := utils.ApiStringerFromFriendlyString(&deployMode, o.DeployMode.ValueString())
if err != nil {
diags.AddError(fmt.Sprintf("error parsing deploy mode %q", o.DeployMode.ValueString()), err.Error())
return
}

type patch struct {
Id string `json:"id"`
DeployMode *string `json:"deploy_mode"`
}

if err != nil {
diags.AddError(fmt.Sprintf("error parsing deploy mode %q", o.DeployMode.ValueString()), err.Error())
return
}

var stringPtr *string
if deployMode == apstra.NodeDeployModeNone {
stringPtr = nil
} else {
s := deployMode.String()
stringPtr = &s
}

setDeployMode := patch{
Id: o.NodeId.ValueString(),
DeployMode: stringPtr,
}
deployModeResponse := patch{}

err = client.PatchNode(ctx, apstra.ObjectId(o.BlueprintId.ValueString()), apstra.ObjectId(o.NodeId.ValueString()), &setDeployMode, &deployModeResponse)
if err != nil {
diags.AddError("error setting deploy mode", err.Error())
return
}
}

func (o *DeviceAllocation) GetNodeDeployMode(ctx context.Context, client *apstra.Client, diags *diag.Diagnostics) {
var node struct {
Id string `json:"id"`
Type string `json:"type"`
DeployMode string `json:"deploy_mode"`
}
err := client.GetNode(ctx, apstra.ObjectId(o.BlueprintId.ValueString()), apstra.ObjectId(o.NodeId.ValueString()), &node)
if err != nil {
diags.AddError("failed to fetch blueprint node", err.Error())
}

var deployMode apstra.NodeDeployMode
err = deployMode.FromString(node.DeployMode)
if err != nil {
diags.AddError(fmt.Sprintf("error parsing deploy mode %q", node.DeployMode), err.Error())
return
}

o.DeployMode = types.StringValue(utils.StringersToFriendlyString(deployMode))
}
89 changes: 68 additions & 21 deletions apstra/resource_datacenter_device_allocation.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tfapstra

import (
"context"
"errors"
"fmt"
"github.com/Juniper/apstra-go-sdk/apstra"
"github.com/Juniper/terraform-provider-apstra/apstra/blueprint"
Expand Down Expand Up @@ -44,19 +45,19 @@ func (o *resourceDeviceAllocation) Create(ctx context.Context, req resource.Crea
return
}

// Ensure the blueprint exists.
if !utils.BlueprintExists(ctx, o.client, apstra.ObjectId(plan.BlueprintId.ValueString()), &resp.Diagnostics) {
if resp.Diagnostics.HasError() {
// create a client for the datacenter reference design
bp, err := o.client.NewTwoStageL3ClosClient(ctx, apstra.ObjectId(plan.BlueprintId.ValueString()))
if err != nil {
if utils.IsApstra404(err) {
resp.Diagnostics.AddError(fmt.Sprintf("blueprint %s not found", plan.BlueprintId), err.Error())
return
}
resp.Diagnostics.AddError("no such blueprint", fmt.Sprintf("blueprint %s not found", plan.BlueprintId))
}
if resp.Diagnostics.HasError() {
resp.Diagnostics.AddError(fmt.Sprintf(blueprint.ErrDCBlueprintCreate, plan.BlueprintId), err.Error())
return
}

// Lock the blueprint mutex.
err := o.lockFunc(ctx, plan.BlueprintId.ValueString())
err = o.lockFunc(ctx, plan.BlueprintId.ValueString())
if err != nil {
resp.Diagnostics.AddError(
fmt.Sprintf("error locking blueprint %q mutex", plan.BlueprintId.ValueString()),
Expand Down Expand Up @@ -92,7 +93,22 @@ func (o *resourceDeviceAllocation) Create(ctx context.Context, req resource.Crea
}
}

plan.SetNodeDeployMode(ctx, o.client, &resp.Diagnostics)
switch {
case plan.DeployMode.IsNull(): // not expected with Optional+Computed, nothing to do here
case plan.DeployMode.IsUnknown(): // config is null, get the Computed value
deployMode, err := utils.GetNodeDeployMode(ctx, bp, plan.NodeId.ValueString())
if err != nil {
resp.Diagnostics.AddError("failed to fetch node deploy mode", err.Error())
return
}
plan.DeployMode = types.StringValue(deployMode)
default: // value provided via config
err = utils.SetNodeDeployMode(ctx, bp, plan.NodeId.ValueString(), plan.DeployMode.ValueString())
if err != nil {
resp.Diagnostics.AddError("failed while setting node deploy mode", err.Error())
return
}
}
if resp.Diagnostics.HasError() {
return
}
Expand All @@ -112,15 +128,14 @@ func (o *resourceDeviceAllocation) Read(ctx context.Context, req resource.ReadRe
previousInterfaceMapCatalogId := state.InitialInterfaceMapId
previousInterfaceMapName := state.InterfaceMapName

// Ensure the blueprint still exists.
if !utils.BlueprintExists(ctx, o.client, apstra.ObjectId(state.BlueprintId.ValueString()), &resp.Diagnostics) {
if resp.Diagnostics.HasError() {
// create a client for the datacenter reference design
bp, err := o.client.NewTwoStageL3ClosClient(ctx, apstra.ObjectId(state.BlueprintId.ValueString()))
if err != nil {
if utils.IsApstra404(err) {
resp.State.RemoveResource(ctx)
return
}
resp.State.RemoveResource(ctx)
return
}
if resp.Diagnostics.HasError() {
resp.Diagnostics.AddError(fmt.Sprintf(blueprint.ErrDCBlueprintCreate, state.BlueprintId), err.Error())
return
}

Expand Down Expand Up @@ -151,10 +166,15 @@ func (o *resourceDeviceAllocation) Read(ctx context.Context, req resource.ReadRe
return
}

state.GetNodeDeployMode(ctx, o.client, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
deployMode, err := utils.GetNodeDeployMode(ctx, bp, state.NodeId.ValueString())
if err != nil {
var ace apstra.ClientErr
if errors.As(err, &ace) && ace.Type() == apstra.ErrNotfound {
resp.State.RemoveResource(ctx)
return
}
}
state.DeployMode = types.StringValue(deployMode)

state.GetInterfaceMapName(ctx, o.client, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
Expand Down Expand Up @@ -200,20 +220,47 @@ func (o *resourceDeviceAllocation) Update(ctx context.Context, req resource.Upda
return
}

// create a client for the datacenter reference design
bp, err := o.client.NewTwoStageL3ClosClient(ctx, apstra.ObjectId(plan.BlueprintId.ValueString()))
if err != nil {
if utils.IsApstra404(err) {
resp.State.RemoveResource(ctx)
return
}
resp.Diagnostics.AddError(fmt.Sprintf(blueprint.ErrDCBlueprintCreate, plan.BlueprintId), err.Error())
return
}

// Lock the blueprint mutex.
err := o.lockFunc(ctx, plan.BlueprintId.ValueString())
err = o.lockFunc(ctx, plan.BlueprintId.ValueString())
if err != nil {
resp.Diagnostics.AddError(
fmt.Sprintf("error locking blueprint %q mutex", plan.BlueprintId.ValueString()),
err.Error())
return
}

state.DeployMode = plan.DeployMode
state.SetNodeDeployMode(ctx, o.client, &resp.Diagnostics)
switch {
case plan.DeployMode.IsNull(): // not expected with Optional+Computed, nothing to do here
case plan.DeployMode.IsUnknown(): // config is null, get the Computed value
deployMode, err := utils.GetNodeDeployMode(ctx, bp, plan.NodeId.ValueString())
if err != nil {
resp.Diagnostics.AddError("failed reading node deploy mode", err.Error())
return
}

plan.DeployMode = types.StringValue(deployMode)
default: // value provided via config
err := utils.SetNodeDeployMode(ctx, bp, plan.NodeId.ValueString(), plan.DeployMode.ValueString())
if err != nil {
resp.Diagnostics.AddError("failed setting node deploy mode", err.Error())
return
}
}
if resp.Diagnostics.HasError() {
return
}
state.DeployMode = plan.DeployMode

if !plan.DeviceKey.Equal(state.DeviceKey) {
// device key has changed
Expand Down
69 changes: 69 additions & 0 deletions apstra/utils/node.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package utils

import (
"context"
"github.com/Juniper/apstra-go-sdk/apstra"
)

func AllNodeDeployModes() []string {
modes := apstra.AllNodeDeployModes()
result := make([]string, len(modes))
for i := range modes {
result[i] = StringersToFriendlyString(modes[i])
}

return result
}

func GetNodeDeployMode(ctx context.Context, client *apstra.TwoStageL3ClosClient, nodeId string) (string, error) {
var node struct {
Id string `json:"id"`
Type string `json:"type"`
DeployMode string `json:"deploy_mode"`
}
err := client.Client().GetNode(ctx, client.Id(), apstra.ObjectId(nodeId), &node)
if err != nil {
return "", err
}

var deployMode apstra.NodeDeployMode
err = deployMode.FromString(node.DeployMode)
if err != nil {
return "", err
}

return StringersToFriendlyString(deployMode), nil
}

func SetNodeDeployMode(ctx context.Context, client *apstra.TwoStageL3ClosClient, nodeId string, modeString string) error {
var modeIota apstra.NodeDeployMode
err := ApiStringerFromFriendlyString(&modeIota, modeString)
if err != nil {
return err
}

type patch struct {
Id string `json:"id"`
DeployMode *string `json:"deploy_mode"`
}

var stringPtr *string
if modeIota == apstra.NodeDeployModeNone {
stringPtr = nil
} else {
s := modeIota.String()
stringPtr = &s
}

setDeployMode := patch{
Id: nodeId,
DeployMode: stringPtr,
}

err = client.Client().PatchNode(ctx, client.Id(), apstra.ObjectId(nodeId), &setDeployMode, nil)
if err != nil {
return err
}

return nil
}
13 changes: 0 additions & 13 deletions apstra/utils/system_agents.go

This file was deleted.

0 comments on commit 118e813

Please sign in to comment.