Skip to content

Commit

Permalink
Dashboards: Add support for widgets field (#80)
Browse files Browse the repository at this point in the history
supersedes the `widget_tokens` field

- Use codegen / add tests
- Small refactor of virtual tag test
  • Loading branch information
conner authored Dec 30, 2024
1 parent 2622f6a commit 328e902
Show file tree
Hide file tree
Showing 11 changed files with 3,258 additions and 325 deletions.
29 changes: 29 additions & 0 deletions generator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,26 @@ resources:
description: The token of the business metric
aliases:
business_metric_token: token
dashboard:
create:
path: /dashboards
method: POST
read:
path: /dashboards/{dashboard_token}
method: GET
update:
path: /dashboards/{dashboard_token}
method: PUT
delete:
path: /dashboards/{dashboard_token}
method: DELETE
schema:
attributes:
overrides:
token:
description: The token of the dashboard
aliases:
dashboard_token: token
kubernetes_efficiency_report:
create:
path: /kubernetes_efficiency_reports
Expand Down Expand Up @@ -185,6 +205,15 @@ data_sources:
- limit
- links
- page
dashboards:
read:
path: /dashboards
method: GET
schema:
ignores:
- limit
- links
- page
managed_accounts:
read:
path: /managed_accounts
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ require (
github.com/hashicorp/terraform-plugin-docs v0.14.1
github.com/hashicorp/terraform-plugin-framework v1.5.0
github.com/hashicorp/terraform-plugin-testing v1.6.0
github.com/vantage-sh/vantage-go v0.0.45
github.com/vantage-sh/vantage-go v0.0.46
)

// replace github.com/vantage-sh/vantage-go v0.0.44 => ../vantage-go
// replace github.com/vantage-sh/vantage-go => ../vantage-go

require (
github.com/Masterminds/goutils v1.1.1 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/vantage-sh/vantage-go v0.0.45 h1:Tzfuu8JHCtqtYU5jWnWLetilGpLRtW5mggFlqxtYWG4=
github.com/vantage-sh/vantage-go v0.0.45/go.mod h1:MsSI4gX/Wvkzo9kqWphZfE6puolmnbHcXSaoGkDCmXg=
github.com/vantage-sh/vantage-go v0.0.46 h1:qJJ0mXtscPsL68nqB0M1xJ43elxnRt0uockd1471jRA=
github.com/vantage-sh/vantage-go v0.0.46/go.mod h1:MsSI4gX/Wvkzo9kqWphZfE6puolmnbHcXSaoGkDCmXg=
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
Expand Down
215 changes: 44 additions & 171 deletions vantage/dashboard_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
modelsv2 "github.com/vantage-sh/vantage-go/vantagev2/models"
"github.com/vantage-sh/terraform-provider-vantage/vantage/resource_dashboard"
dashboardsv2 "github.com/vantage-sh/vantage-go/vantagev2/vantage/dashboards"
)

Expand All @@ -27,127 +26,46 @@ func NewDashboardResource() resource.Resource {
return &DashboardResource{}
}

type DashboardResourceModel struct {
Token types.String `tfsdk:"token"`
Title types.String `tfsdk:"title"`
WidgetTokens types.List `tfsdk:"widget_tokens"`
DateBin types.String `tfsdk:"date_bin"`
DateInterval types.String `tfsdk:"date_interval"`
StartDate types.String `tfsdk:"start_date"`
EndDate types.String `tfsdk:"end_date"`
WorkspaceToken types.String `tfsdk:"workspace_token"`
SavedFilterTokens types.List `tfsdk:"saved_filter_tokens"`
}

func (r *DashboardResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_dashboard"
}

func (r DashboardResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"token": schema.StringAttribute{
Computed: true,
MarkdownDescription: "Unique dashboard identifier",
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"title": schema.StringAttribute{
MarkdownDescription: "Title of the dashboard",
Required: true,
},
"widget_tokens": schema.ListAttribute{
ElementType: types.StringType,
MarkdownDescription: "Tokens for widgets present in the dashboard. Currently only cost report tokens are supported.",
Required: true,
},
"date_bin": schema.StringAttribute{
MarkdownDescription: "Determines how to group costs in the Dashboard.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"date_interval": schema.StringAttribute{
MarkdownDescription: "Determines the date range in the Dashboard. Guaranteed to be set to 'custom' if 'start_date' and 'end_date' are set.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"start_date": schema.StringAttribute{
MarkdownDescription: "The start date for the date range for CostReports in the Dashboard. ISO 8601 Formatted. Overwrites 'date_interval' if set.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"end_date": schema.StringAttribute{
MarkdownDescription: "The end date for the date range for CostReports in the Dashboard. ISO 8601 Formatted. Overwrites 'date_interval' if set.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"workspace_token": schema.StringAttribute{
MarkdownDescription: "The token for the Workspace the Dashboard is a part of.",
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"saved_filter_tokens": schema.ListAttribute{
ElementType: types.StringType,
MarkdownDescription: "Tokens of the saved filters used in the Dashboard.",
Optional: true,
},
s := resource_dashboard.DashboardResourceSchema(ctx)
attrs := s.GetAttributes()
s.Attributes["end_date"] = schema.StringAttribute{
Computed: true,
Optional: true,
MarkdownDescription: attrs["end_date"].GetMarkdownDescription(),
}
s.Attributes["title"] = schema.StringAttribute{
Computed: true,
Optional: true,
MarkdownDescription: attrs["title"].GetMarkdownDescription(),
}
s.Attributes["token"] = schema.StringAttribute{
Computed: true,
MarkdownDescription: attrs["token"].GetMarkdownDescription(),
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
MarkdownDescription: "Manages a Dashboard.",
}
resp.Schema = s
}

func (r DashboardResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data *DashboardResourceModel
var data *dashboardModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

widgetTokens := []types.String{}
if !data.WidgetTokens.IsNull() && !data.WidgetTokens.IsUnknown() {
widgetTokens = make([]types.String, 0, len(data.WidgetTokens.Elements()))
resp.Diagnostics.Append(data.WidgetTokens.ElementsAs(ctx, &widgetTokens, false)...)
if resp.Diagnostics.HasError() {
return
}
}

savedFilterTokens := []types.String{}
if !data.SavedFilterTokens.IsNull() && !data.SavedFilterTokens.IsUnknown() {
savedFilterTokens = make([]types.String, 0, len(data.SavedFilterTokens.Elements()))
resp.Diagnostics.Append(data.SavedFilterTokens.ElementsAs(ctx, &savedFilterTokens, false)...)
if resp.Diagnostics.HasError() {
return
}
body := data.toCreate(ctx, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}

params := dashboardsv2.NewCreateDashboardParams()
body := &modelsv2.CreateDashboard{
Title: data.Title.ValueStringPointer(),
WidgetTokens: fromStringsValue(widgetTokens),
DateBin: data.DateBin.ValueString(),
DateInterval: data.DateInterval.ValueString(),
StartDate: data.StartDate.ValueString(),
EndDate: data.EndDate.ValueStringPointer(),
WorkspaceToken: data.WorkspaceToken.ValueString(),
SavedFilterTokens: fromStringsValue(savedFilterTokens),
}
params.WithCreateDashboard(body)
params := dashboardsv2.NewCreateDashboardParams().WithCreateDashboard(body)
out, err := r.client.V2.Dashboards.CreateDashboard(params, r.client.Auth)
if err != nil {
if e, ok := err.(*dashboardsv2.CreateDashboardBadRequest); ok {
Expand All @@ -158,27 +76,23 @@ func (r DashboardResource) Create(ctx context.Context, req resource.CreateReques
return
}

data.Token = types.StringValue(out.Payload.Token)
data.Title = types.StringValue(out.Payload.Title)
data.WorkspaceToken = types.StringValue(out.Payload.WorkspaceToken)
data.StartDate = types.StringValue(out.Payload.StartDate)
data.EndDate = types.StringValue(out.Payload.EndDate)
data.DateBin = types.StringValue(out.Payload.DateBin)
data.DateInterval = types.StringValue(out.Payload.DateInterval)
if diag := data.applyPayload(ctx, out.Payload); diag.HasError() {
resp.Diagnostics.Append(diag...)
return
}

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r DashboardResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var state *DashboardResourceModel
var state *dashboardModel
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

params := dashboardsv2.NewGetDashboardParams()
params.SetDashboardToken(state.Token.ValueString())
params := dashboardsv2.NewGetDashboardParams().WithDashboardToken(state.Token.ValueString())
out, err := r.client.V2.Dashboards.GetDashboard(params, r.client.Auth)
if err != nil {
if _, ok := err.(*dashboardsv2.GetDashboardNotFound); ok {
Expand All @@ -190,25 +104,11 @@ func (r DashboardResource) Read(ctx context.Context, req resource.ReadRequest, r
return
}

state.Token = types.StringValue(out.Payload.Token)
state.Title = types.StringValue(out.Payload.Title)
state.WorkspaceToken = types.StringValue(out.Payload.WorkspaceToken)
state.StartDate = types.StringValue(out.Payload.StartDate)
state.EndDate = types.StringValue(out.Payload.EndDate)
state.DateBin = types.StringValue(out.Payload.DateBin)
state.DateInterval = types.StringValue(out.Payload.DateInterval)
widgets, diag := types.ListValueFrom(ctx, types.StringType, out.Payload.WidgetTokens)
diag := state.applyPayload(ctx, out.Payload)
if diag.HasError() {
resp.Diagnostics.Append(diag...)
return
}
state.WidgetTokens = widgets
saved_filters, diag := types.ListValueFrom(ctx, types.StringType, out.Payload.SavedFilterTokens)
if diag.HasError() {
resp.Diagnostics.Append(diag...)
return
}
state.SavedFilterTokens = saved_filters

resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}
Expand All @@ -218,45 +118,20 @@ func (r DashboardResource) ImportState(ctx context.Context, req resource.ImportS
}

func (r DashboardResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data *DashboardResourceModel
var data *dashboardModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

widgetTokens := []types.String{}
if !data.WidgetTokens.IsNull() && !data.WidgetTokens.IsUnknown() {
widgetTokens = make([]types.String, 0, len(data.WidgetTokens.Elements()))
resp.Diagnostics.Append(data.WidgetTokens.ElementsAs(ctx, &widgetTokens, false)...)
if resp.Diagnostics.HasError() {
return
}
}

savedFilterTokens := []types.String{}
if !data.SavedFilterTokens.IsNull() && !data.SavedFilterTokens.IsUnknown() {
savedFilterTokens = make([]types.String, 0, len(data.SavedFilterTokens.Elements()))
resp.Diagnostics.Append(data.SavedFilterTokens.ElementsAs(ctx, &savedFilterTokens, false)...)
if resp.Diagnostics.HasError() {
return
}
body := data.toUpdate(ctx, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
params := dashboardsv2.NewUpdateDashboardParams().
WithDashboardToken(data.Token.ValueString()).
WithUpdateDashboard(body)

params := dashboardsv2.NewUpdateDashboardParams()
body := &modelsv2.UpdateDashboard{
Title: data.Title.ValueString(),
WidgetTokens: fromStringsValue(widgetTokens),
SavedFilterTokens: fromStringsValue(savedFilterTokens),
DateBin: data.DateBin.ValueString(),
}
if data.DateInterval.ValueString() == "" || data.DateInterval.ValueString() == "custom" {
body.StartDate = data.StartDate.ValueString()
body.EndDate = data.EndDate.ValueStringPointer()
} else {
body.DateInterval = data.DateInterval.ValueString()
}
params.WithDashboardToken(data.Token.ValueString())
params.WithUpdateDashboard(body)
out, err := r.client.V2.Dashboards.UpdateDashboard(params, r.client.Auth)
if err != nil {
if e, ok := err.(*dashboardsv2.UpdateDashboardBadRequest); ok {
Expand All @@ -267,19 +142,17 @@ func (r DashboardResource) Update(ctx context.Context, req resource.UpdateReques
return
}

data.Token = types.StringValue(out.Payload.Token)
data.Title = types.StringValue(out.Payload.Title)
data.WorkspaceToken = types.StringValue(out.Payload.WorkspaceToken)
data.StartDate = types.StringValue(out.Payload.StartDate)
data.EndDate = types.StringValue(out.Payload.EndDate)
data.DateBin = types.StringValue(out.Payload.DateBin)
data.DateInterval = types.StringValue(out.Payload.DateInterval)
diag := data.applyPayload(ctx, out.Payload)
if diag.HasError() {
resp.Diagnostics.Append(diag...)
return
}

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r DashboardResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var state *DashboardResourceModel
var state *dashboardModel
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
Expand Down
Loading

0 comments on commit 328e902

Please sign in to comment.