Skip to content

Commit

Permalink
Merge pull request #925 from Juniper/922-support-to-get-the-config-di…
Browse files Browse the repository at this point in the history
…ff-between-active-and-staging-configuration-of-all-the-devices

Introduce `apstra_blueprint_device_rendered_config` data source
  • Loading branch information
chrismarget-j authored Oct 18, 2024
2 parents a416159 + 11fb9c5 commit 904fd00
Show file tree
Hide file tree
Showing 12 changed files with 720 additions and 5 deletions.
57 changes: 57 additions & 0 deletions apstra/blueprint/device_rendered_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package blueprint

import (
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
dataSourceSchema "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)

type RenderedConfig struct {
BlueprintId types.String `tfsdk:"blueprint_id"`
SystemId types.String `tfsdk:"system_id"`
NodeId types.String `tfsdk:"node_id"`
StagedCfg types.String `tfsdk:"staged_config"`
DeployedCfg types.String `tfsdk:"deployed_config"`
Incremental types.String `tfsdk:"incremental_config"`
}

func (o RenderedConfig) DataSourceAttributes() map[string]dataSourceSchema.Attribute {
return map[string]dataSourceSchema.Attribute{
"blueprint_id": dataSourceSchema.StringAttribute{
MarkdownDescription: "Apstra Blueprint ID.",
Required: true,
Validators: []validator.String{stringvalidator.LengthAtLeast(1)},
},
"system_id": dataSourceSchema.StringAttribute{
MarkdownDescription: "Apstra ID (serial number) for the System (Managed Device), as found in " +
"Devices -> Managed Devices in the GUI. Required when `node_id` is omitted.",
Optional: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
stringvalidator.ExactlyOneOf(
path.MatchRoot("system_id"),
path.MatchRoot("node_id"),
),
},
},
"node_id": dataSourceSchema.StringAttribute{
MarkdownDescription: "Apstra ID of the System (spine, leaf, etc...) node. Required when `system_id` is omitted.",
Optional: true,
Validators: []validator.String{stringvalidator.LengthAtLeast(1)},
},
"staged_config": dataSourceSchema.StringAttribute{
MarkdownDescription: "Staged device configuration.",
Computed: true,
},
"deployed_config": dataSourceSchema.StringAttribute{
MarkdownDescription: "Deployed device configuration.",
Computed: true,
},
"incremental_config": dataSourceSchema.StringAttribute{
MarkdownDescription: "Incremental device configuration.",
Computed: true,
},
}
}
127 changes: 127 additions & 0 deletions apstra/data_source_blueprint_device_rendered_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package tfapstra

import (
"context"
"errors"
"fmt"

"github.com/Juniper/apstra-go-sdk/apstra"
"github.com/Juniper/apstra-go-sdk/apstra/enum"
"github.com/Juniper/terraform-provider-apstra/apstra/blueprint"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
)

var (
_ datasource.DataSourceWithConfigure = &dataSourceBlueprintNodeConfig{}
_ datasourceWithSetClient = &dataSourceBlueprintNodeConfig{}
)

type dataSourceBlueprintNodeConfig struct {
client *apstra.Client
}

func (o *dataSourceBlueprintNodeConfig) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_blueprint_device_rendered_config"
}

func (o *dataSourceBlueprintNodeConfig) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
configureDataSource(ctx, o, req, resp)
}

func (o *dataSourceBlueprintNodeConfig) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: docCategoryRefDesignAny +
"This data source retrieves rendered device configuration for a system in a Blueprint.",
Attributes: blueprint.RenderedConfig{}.DataSourceAttributes(),
}
}

func (o *dataSourceBlueprintNodeConfig) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
// Retrieve values from config.
var config blueprint.RenderedConfig
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
}

addNodeDiag := func(err error) {
var ace apstra.ClientErr
if errors.As(err, &ace) && ace.Type() == apstra.ErrNotfound {
resp.Diagnostics.AddError(
"Not Found",
fmt.Sprintf("Node %s in blueprint %s not found", config.NodeId, config.BlueprintId),
)
} else {
resp.Diagnostics.AddError("Failed to fetch config", err.Error())
}
}

addSysDiag := func(err error) {
var ace apstra.ClientErr
if errors.As(err, &ace) && ace.Type() == apstra.ErrNotfound {
resp.Diagnostics.AddError(
"Not Found",
fmt.Sprintf("System %s in blueprint %s not found", config.SystemId, config.BlueprintId),
)
} else {
resp.Diagnostics.AddError("Failed to fetch config", err.Error())
}
}

bpId := apstra.ObjectId(config.BlueprintId.ValueString())

var err error
var deployed, staged, incremental string

switch {
case !config.NodeId.IsNull():
node := apstra.ObjectId(config.NodeId.ValueString())
deployed, err = o.client.GetNodeRenderedConfig(ctx, bpId, node, enum.RenderedConfigTypeDeployed)
if err != nil {
addNodeDiag(err)
return
}
staged, err = o.client.GetNodeRenderedConfig(ctx, bpId, node, enum.RenderedConfigTypeStaging)
if err != nil {
addNodeDiag(err)
return
}
diff, err := o.client.GetNodeRenderedConfigDiff(ctx, bpId, node)
if err != nil {
addNodeDiag(err)
return
}
incremental = diff.Config
case !config.SystemId.IsNull():
system := apstra.ObjectId(config.SystemId.ValueString())
deployed, err = o.client.GetSystemRenderedConfig(ctx, bpId, system, enum.RenderedConfigTypeDeployed)
if err != nil {
addSysDiag(err)
return
}
staged, err = o.client.GetSystemRenderedConfig(ctx, bpId, system, enum.RenderedConfigTypeStaging)
if err != nil {
addSysDiag(err)
return
}
diff, err := o.client.GetSystemRenderedConfigDiff(ctx, bpId, system)
if err != nil {
addSysDiag(err)
return
}
incremental = diff.Config
}

config.DeployedCfg = types.StringValue(deployed)
config.StagedCfg = types.StringValue(staged)
config.Incremental = types.StringValue(incremental)

// set state
resp.Diagnostics.Append(resp.State.Set(ctx, &config)...)
}

func (o *dataSourceBlueprintNodeConfig) setClient(client *apstra.Client) {
o.client = client
}
Loading

0 comments on commit 904fd00

Please sign in to comment.