Skip to content

Commit

Permalink
Add support for iba widget data source
Browse files Browse the repository at this point in the history
  • Loading branch information
rajagopalans committed Oct 3, 2023
1 parent 98b7ca6 commit 661b25d
Show file tree
Hide file tree
Showing 12 changed files with 587 additions and 3 deletions.
59 changes: 59 additions & 0 deletions apstra/blueprint/iba_widget.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package blueprint

import (
"context"
"github.com/Juniper/apstra-go-sdk/apstra"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
dataSourceSchema "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)

type IbaWidget struct {
BlueprintId types.String `tfsdk:"blueprint_id"`
Id types.String `tfsdk:"id"`
Label types.String `tfsdk:"label"`
Description types.String `tfsdk:"description"`
}

func (o IbaWidget) DataSourceAttributes() map[string]dataSourceSchema.Attribute {
return map[string]dataSourceSchema.Attribute{
"blueprint_id": dataSourceSchema.StringAttribute{
MarkdownDescription: "Apstra Blueprint ID. Used to identify the Blueprint that the IBA Widget belongs to.",
Required: true,
Validators: []validator.String{stringvalidator.LengthAtLeast(1)},
},
"id": dataSourceSchema.StringAttribute{
MarkdownDescription: "Populate this field to look up a IBA Widget by ID. Required when `name` is omitted.",
Optional: true,
Computed: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
stringvalidator.ExactlyOneOf(path.Expressions{
path.MatchRelative(),
path.MatchRoot("label"),
}...),
},
},
"label": dataSourceSchema.StringAttribute{
MarkdownDescription: "Populate this field to look up a IBA Widget by name. Required when `id` is omitted.",
Optional: true,
Computed: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
},
"description": dataSourceSchema.StringAttribute{
MarkdownDescription: "Description of the IBA Widget",
Computed: true,
},
}
}

func (o *IbaWidget) LoadApiData(ctx context.Context, in *apstra.IbaWidget, _ *diag.Diagnostics) {
o.Id = types.StringValue(in.Id.String())
o.Label = types.StringValue(in.Data.Label)
o.Description = types.StringValue(in.Data.Description)
}
96 changes: 96 additions & 0 deletions apstra/data_source_datacenter_iba_widget.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package tfapstra

import (
"context"
"fmt"
"github.com/Juniper/apstra-go-sdk/apstra"
"github.com/Juniper/terraform-provider-apstra/apstra/blueprint"
"github.com/Juniper/terraform-provider-apstra/apstra/utils"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/path"
)

var _ datasource.DataSourceWithConfigure = &dataSourceDatacenterIbaWidget{}

type dataSourceDatacenterIbaWidget struct {
client *apstra.Client
}

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

func (o *dataSourceDatacenterIbaWidget) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
o.client = DataSourceGetClient(ctx, req, resp)
}

func (o *dataSourceDatacenterIbaWidget) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "This data source provides details of a specific IBA Widget in a Blueprint." +
"\n\n" +
"At least one optional attribute is required.",
Attributes: blueprint.IbaWidget{}.DataSourceAttributes(),
}
}

func (o *dataSourceDatacenterIbaWidget) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var config blueprint.IbaWidget
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
}

bpClient, err := o.client.NewTwoStageL3ClosClient(ctx, apstra.ObjectId(config.BlueprintId.ValueString()))
if err != nil {
if utils.IsApstra404(err) {
resp.Diagnostics.AddError(fmt.Sprintf("blueprint %s not found",
config.BlueprintId), err.Error())
return
}
resp.Diagnostics.AddError("failed to create blueprint client", err.Error())
return
}

var api *apstra.IbaWidget
switch {
case !config.Label.IsNull():
api, err = bpClient.GetIbaWidgetByLabel(ctx, config.Label.ValueString())
if err != nil {
if utils.IsApstra404(err) {
resp.Diagnostics.AddAttributeError(
path.Root("name"),
"IBA widget not found",
fmt.Sprintf("IBA Widget with label %s not found", config.Label))
return
}
resp.Diagnostics.AddAttributeError(
path.Root("name"), "Failed reading IBA Widget", err.Error(),
)
return
}
case !config.Id.IsNull():
api, err = bpClient.GetIbaWidget(ctx, apstra.ObjectId(config.Id.ValueString()))
if err != nil {
if utils.IsApstra404(err) {
resp.Diagnostics.AddAttributeError(
path.Root("id"),
"IbaWidget not found",
fmt.Sprintf("IbaWidget with ID %s not found", config.Id))
return
}
resp.Diagnostics.AddAttributeError(
path.Root("name"), "Failed reading IBA Widgett", err.Error(),
)
return
}
}

config.LoadApiData(ctx, api, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}

// Set state
resp.Diagnostics.Append(resp.State.Set(ctx, &config)...)
}
81 changes: 81 additions & 0 deletions apstra/data_source_datacenter_iba_widget_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package tfapstra

import (
"context"
"errors"
"fmt"
testutils "github.com/Juniper/terraform-provider-apstra/apstra/test_utils"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"testing"
)

const (
dataSourceDatacenterIbaWidgetTemplateByNameHCL = `
data "apstra_datacenter_iba_widget" "test" {
blueprint_id = "%s"
label = "%s"
}
`

dataSourceDatacenterIbaWidgetTemplateByIdHCL = `
data "apstra_datacenter_iba_widget" "test" {
blueprint_id = "%s"
id = "%s"
}
`
)

func TestAccDataSourceDatacenterIbaWidget(t *testing.T) {
ctx := context.Background()

bpClient, bpDelete, err := testutils.MakeOrFindBlueprint(ctx, "BPA", testutils.BlueprintA)

if err != nil {
t.Fatal(errors.Join(err, bpDelete(ctx)))
}
defer func() {
err = bpDelete(ctx)
if err != nil {
t.Error(err)
}
}()

// Set up Widgets
widgetIdA, widgetDataA, _, _, cleanup := testutils.TestWidgetsAB(ctx, t, bpClient)
if err != nil {
t.Fatal(err)
}
defer func() {
err = cleanup()
if err != nil {
t.Error(err)
}
}()

resource.Test(t, resource.TestCase{
// PreCheck: setup,
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
// Read by ID
{
Config: insecureProviderConfigHCL + fmt.Sprintf(dataSourceDatacenterIbaWidgetTemplateByIdHCL,
string(bpClient.Id()), string(widgetIdA)),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("data.apstra_datacenter_iba_widget.test", "id", widgetIdA.String()),
resource.TestCheckResourceAttr("data.apstra_datacenter_iba_widget.test", "label",
widgetDataA.Label),
),
},
// Read by Name
{
Config: insecureProviderConfigHCL + fmt.Sprintf(dataSourceDatacenterIbaWidgetTemplateByNameHCL,
string(bpClient.Id()), widgetDataA.Label),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("data.apstra_datacenter_iba_widget.test", "id", widgetIdA.String()),
resource.TestCheckResourceAttr("data.apstra_datacenter_iba_widget.test", "label",
widgetDataA.Label),
),
},
},
})
}
98 changes: 98 additions & 0 deletions apstra/data_source_datacenter_iba_widgets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package tfapstra

import (
"context"
"fmt"
"github.com/Juniper/apstra-go-sdk/apstra"
"github.com/Juniper/terraform-provider-apstra/apstra/utils"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)

var _ datasource.DataSourceWithConfigure = &dataSourceDatacenterIbaWidgets{}

type dataSourceDatacenterIbaWidgets struct {
client *apstra.Client
}

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

func (o *dataSourceDatacenterIbaWidgets) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
o.client = DataSourceGetClient(ctx, req, resp)
}

func (o *dataSourceDatacenterIbaWidgets) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "This data source returns the ID numbers of all IBA Widgets in a Blueprint.",
Attributes: map[string]schema.Attribute{
"blueprint_id": schema.StringAttribute{
MarkdownDescription: "Apstra Blueprint ID. " +
"Used to identify the Blueprint that the IBA Widgets belongs to.",
Required: true,
Validators: []validator.String{stringvalidator.LengthAtLeast(1)},
},
"ids": schema.SetAttribute{
MarkdownDescription: "A set of Apstra object ID numbers representing the IBA Widgets in the blueprint.",
Computed: true,
ElementType: types.StringType,
},
},
}
}

func (o *dataSourceDatacenterIbaWidgets) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var config struct {
BlueprintId types.String `tfsdk:"blueprint_id"`
Ids types.Set `tfsdk:"ids"`
}

// get the configuration
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return
}
bpClient, err := o.client.NewTwoStageL3ClosClient(ctx, apstra.ObjectId(config.BlueprintId.ValueString()))
if err != nil {
if utils.IsApstra404(err) {
resp.Diagnostics.AddError(fmt.Sprintf("blueprint %s not found",
config.BlueprintId), err.Error())
return
}
resp.Diagnostics.AddError("failed to create blueprint client", err.Error())
return
}

ws, err := bpClient.GetAllIbaWidgets(ctx)
if err != nil {
resp.Diagnostics.AddError("error retrieving IBA Widgets", err.Error())
return
}

ids := make([]apstra.ObjectId, len(ws))
for i, j := range ws {
ids[i] = j.Id
}

idSet, diags := types.SetValueFrom(ctx, types.StringType, ids)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

// create new state object
state := struct {
BlueprintId types.String `tfsdk:"blueprint_id"`
Ids types.Set `tfsdk:"ids"`
}{
BlueprintId: config.BlueprintId,
Ids: idSet,
}

// set state
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}
2 changes: 2 additions & 0 deletions apstra/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,8 @@ func (p *Provider) DataSources(_ context.Context) []func() datasource.DataSource
func() datasource.DataSource { return &dataSourceDatacenterCtStaticRoute{} },
func() datasource.DataSource { return &dataSourceDatacenterCtVnSingle{} },
func() datasource.DataSource { return &dataSourceDatacenterCtVnMultiple{} },
func() datasource.DataSource { return &dataSourceDatacenterIbaWidget{} },
func() datasource.DataSource { return &dataSourceDatacenterIbaWidgets{} },
func() datasource.DataSource { return &dataSourceDatacenterPropertySet{} },
func() datasource.DataSource { return &dataSourceDatacenterPropertySets{} },
func() datasource.DataSource { return &dataSourceDatacenterRoutingPolicy{} },
Expand Down
Loading

0 comments on commit 661b25d

Please sign in to comment.