Skip to content

Commit

Permalink
fix(r/trigger): handle dynamic evaluation schedule
Browse files Browse the repository at this point in the history
  • Loading branch information
jharley committed Aug 31, 2024
1 parent 0ab7e83 commit a15f182
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 70 deletions.
8 changes: 4 additions & 4 deletions internal/models/notification_recipients.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ type NotificationRecipientModel struct {
Details types.List `tfsdk:"notification_details"` // NotificationRecipientDetailsModel
}

type NotificationRecipientDetailsModel struct {
PDSeverity types.String `tfsdk:"pagerduty_severity"`
}

var NotificationRecipientAttrType = map[string]attr.Type{
"id": types.StringType,
"type": types.StringType,
Expand All @@ -25,6 +21,10 @@ var NotificationRecipientAttrType = map[string]attr.Type{
}},
}

type NotificationRecipientDetailsModel struct {
PDSeverity types.String `tfsdk:"pagerduty_severity"`
}

var NotificationRecipientDetailsAttrType = map[string]attr.Type{
"pagerduty_severity": types.StringType,
}
41 changes: 28 additions & 13 deletions internal/models/triggers.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
package models

import "github.com/hashicorp/terraform-plugin-framework/types"
import (
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/types"
)

type TriggerResourceModel struct {
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Dataset types.String `tfsdk:"dataset"`
Description types.String `tfsdk:"description"`
Disabled types.Bool `tfsdk:"disabled"`
QueryID types.String `tfsdk:"query_id"`
QueryJson types.String `tfsdk:"query_json"`
AlertType types.String `tfsdk:"alert_type"`
Frequency types.Int64 `tfsdk:"frequency"`
Threshold []TriggerThresholdModel `tfsdk:"threshold"`
Recipients types.Set `tfsdk:"recipient"` // NotificationRecipientModel
EvaluationSchedule []TriggerEvaluationScheduleModel `tfsdk:"evaluation_schedule"`
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Dataset types.String `tfsdk:"dataset"`
Description types.String `tfsdk:"description"`
Disabled types.Bool `tfsdk:"disabled"`
QueryID types.String `tfsdk:"query_id"`
QueryJson types.String `tfsdk:"query_json"`
AlertType types.String `tfsdk:"alert_type"`
Frequency types.Int64 `tfsdk:"frequency"`
Threshold types.List `tfsdk:"threshold"` // TriggerThresholdModel
Recipients types.Set `tfsdk:"recipient"` // NotificationRecipientModel
EvaluationSchedule types.List `tfsdk:"evaluation_schedule"` // TriggerEvaluationScheduleModel
}

type TriggerThresholdModel struct {
Expand All @@ -23,8 +26,20 @@ type TriggerThresholdModel struct {
ExceededLimit types.Int64 `tfsdk:"exceeded_limit"`
}

var TriggerThresholdAttrType = map[string]attr.Type{
"op": types.StringType,
"value": types.Float64Type,
"exceeded_limit": types.Int64Type,
}

type TriggerEvaluationScheduleModel struct {
DaysOfWeek []types.String `tfsdk:"days_of_week"`
StartTime types.String `tfsdk:"start_time"`
EndTime types.String `tfsdk:"end_time"`
}

var TriggerEvaluationScheduleAttrType = map[string]attr.Type{
"days_of_week": types.ListType{ElemType: types.StringType},
"start_time": types.StringType,
"end_time": types.StringType,
}
1 change: 0 additions & 1 deletion internal/provider/notification_recipients.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,6 @@ func notificationRecipientDetailsToList(ctx context.Context, details *client.Not
diags.Append(d...)
result, d = types.ListValueFrom(ctx, types.ObjectType{AttrTypes: models.NotificationRecipientDetailsAttrType}, []attr.Value{objVal})
diags.Append(d...)

} else {
result = types.ListNull(types.ObjectType{AttrTypes: models.NotificationRecipientDetailsAttrType})
}
Expand Down
166 changes: 114 additions & 52 deletions internal/provider/trigger_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
Expand Down Expand Up @@ -241,10 +243,13 @@ func (r *triggerResource) Create(ctx context.Context, req resource.CreateRequest
Description: plan.Description.ValueString(),
Disabled: plan.Disabled.ValueBool(),
AlertType: client.TriggerAlertType(plan.AlertType.ValueString()),
Threshold: expandTriggerThreshold(plan.Threshold),
Threshold: expandTriggerThreshold(ctx, plan.Threshold, &resp.Diagnostics),
Frequency: int(plan.Frequency.ValueInt64()),
Recipients: expandNotificationRecipients(ctx, plan.Recipients, &resp.Diagnostics),
EvaluationSchedule: expandTriggerEvaluationSchedule(plan.EvaluationSchedule),
EvaluationSchedule: expandTriggerEvaluationSchedule(ctx, plan.EvaluationSchedule, &resp.Diagnostics),
}
if resp.Diagnostics.HasError() {
return
}

specifiedByID := !plan.QueryID.IsNull()
Expand All @@ -265,7 +270,7 @@ func (r *triggerResource) Create(ctx context.Context, req resource.CreateRequest
newTrigger.Query = &q
}

if plan.EvaluationSchedule != nil {
if !plan.EvaluationSchedule.IsNull() {
newTrigger.EvaluationScheduleType = client.TriggerEvaluationScheduleWindow
}

Expand All @@ -281,9 +286,9 @@ func (r *triggerResource) Create(ctx context.Context, req resource.CreateRequest
state.Description = types.StringValue(trigger.Description)
state.Disabled = types.BoolValue(trigger.Disabled)
state.AlertType = types.StringValue(string(trigger.AlertType))
state.Threshold = flattenTriggerThreshold(trigger.Threshold)
state.Threshold = flattenTriggerThreshold(ctx, trigger.Threshold, &resp.Diagnostics)
state.Frequency = types.Int64Value(int64(trigger.Frequency))
state.EvaluationSchedule = flattenTriggerEvaluationSchedule(trigger)
state.EvaluationSchedule = flattenTriggerEvaluationSchedule(ctx, trigger.EvaluationSchedule, &resp.Diagnostics)
// we created them as authored so to avoid matching type-target or ID we can just use the same value
state.Recipients = config.Recipients

Expand Down Expand Up @@ -343,9 +348,9 @@ func (r *triggerResource) Read(ctx context.Context, req resource.ReadRequest, re
state.Description = types.StringValue(trigger.Description)
state.Disabled = types.BoolValue(trigger.Disabled)
state.AlertType = types.StringValue(string(trigger.AlertType))
state.Threshold = flattenTriggerThreshold(trigger.Threshold)
state.Threshold = flattenTriggerThreshold(ctx, trigger.Threshold, &resp.Diagnostics)
state.Frequency = types.Int64Value(int64(trigger.Frequency))
state.EvaluationSchedule = flattenTriggerEvaluationSchedule(trigger)
state.EvaluationSchedule = flattenTriggerEvaluationSchedule(ctx, trigger.EvaluationSchedule, &resp.Diagnostics)
state.Recipients = reconcileReadNotificationRecipientState(ctx, trigger.Recipients, state.Recipients, &resp.Diagnostics)

specifiedByID := !state.QueryID.IsNull()
Expand Down Expand Up @@ -385,9 +390,12 @@ func (r *triggerResource) Update(ctx context.Context, req resource.UpdateRequest
Disabled: plan.Disabled.ValueBool(),
AlertType: client.TriggerAlertType(plan.AlertType.ValueString()),
Frequency: int(plan.Frequency.ValueInt64()),
Threshold: expandTriggerThreshold(plan.Threshold),
Threshold: expandTriggerThreshold(ctx, plan.Threshold, &resp.Diagnostics),
Recipients: expandNotificationRecipients(ctx, plan.Recipients, &resp.Diagnostics),
EvaluationSchedule: expandTriggerEvaluationSchedule(plan.EvaluationSchedule),
EvaluationSchedule: expandTriggerEvaluationSchedule(ctx, plan.EvaluationSchedule, &resp.Diagnostics),
}
if resp.Diagnostics.HasError() {
return
}

specifiedByID := !plan.QueryID.IsNull()
Expand Down Expand Up @@ -432,8 +440,8 @@ func (r *triggerResource) Update(ctx context.Context, req resource.UpdateRequest
state.Disabled = types.BoolValue(trigger.Disabled)
state.AlertType = types.StringValue(string(trigger.AlertType))
state.Frequency = types.Int64Value(int64(trigger.Frequency))
state.Threshold = flattenTriggerThreshold(trigger.Threshold)
state.EvaluationSchedule = flattenTriggerEvaluationSchedule(trigger)
state.Threshold = flattenTriggerThreshold(ctx, trigger.Threshold, &resp.Diagnostics)
state.EvaluationSchedule = flattenTriggerEvaluationSchedule(ctx, trigger.EvaluationSchedule, &resp.Diagnostics)
// we created them as authored so to avoid matching type-target or ID we can just use the same value
state.Recipients = config.Recipients

Expand Down Expand Up @@ -497,11 +505,13 @@ func (r *triggerResource) ImportState(ctx context.Context, req resource.ImportSt
}

resp.Diagnostics.Append(resp.State.Set(ctx, &models.TriggerResourceModel{
ID: types.StringValue(id),
Dataset: types.StringValue(dataset),
QueryID: types.StringNull(),
QueryJson: types.StringUnknown(), // favor QueryJSON on import
Recipients: types.SetUnknown(types.ObjectType{AttrTypes: models.NotificationRecipientAttrType}),
ID: types.StringValue(id),
Dataset: types.StringValue(dataset),
QueryID: types.StringNull(),
QueryJson: types.StringUnknown(), // favor QueryJSON on import
Recipients: types.SetUnknown(types.ObjectType{AttrTypes: models.NotificationRecipientAttrType}),
Threshold: types.ListUnknown(types.ObjectType{AttrTypes: models.TriggerThresholdAttrType}),
EvaluationSchedule: types.ListUnknown(types.ObjectType{AttrTypes: models.TriggerEvaluationScheduleAttrType}),
})...)
}

Expand Down Expand Up @@ -600,8 +610,18 @@ func (r *triggerResource) ValidateConfig(ctx context.Context, req resource.Valid
}
}

func expandTriggerThreshold(t []models.TriggerThresholdModel) *client.TriggerThreshold {
if len(t) != 1 {
func expandTriggerThreshold(
ctx context.Context,
l types.List,
diags *diag.Diagnostics,
) *client.TriggerThreshold {
if l.IsNull() || l.IsUnknown() {
return nil
}

var t []models.TriggerThresholdModel
diags.Append(l.ElementsAs(ctx, &t, false)...)
if diags.HasError() {
return nil
}

Expand All @@ -612,48 +632,90 @@ func expandTriggerThreshold(t []models.TriggerThresholdModel) *client.TriggerThr
}
}

func flattenTriggerThreshold(t *client.TriggerThreshold) []models.TriggerThresholdModel {
return []models.TriggerThresholdModel{{
Op: types.StringValue(string(t.Op)),
Value: types.Float64Value(t.Value),
ExceededLimit: types.Int64Value(int64(t.ExceededLimit)),
}}
func flattenTriggerThreshold(
ctx context.Context,
t *client.TriggerThreshold,
diags *diag.Diagnostics,
) types.List {
if t == nil {
return types.ListNull(types.ObjectType{AttrTypes: models.TriggerThresholdAttrType})
}

thresholdObj, d := types.ObjectValue(models.TriggerThresholdAttrType, map[string]attr.Value{
"op": types.StringValue(string(t.Op)),
"value": types.Float64Value(t.Value),
"exceeded_limit": types.Int64Value(int64(t.ExceededLimit)),
})
diags.Append(d...)

result, d := types.ListValueFrom(
ctx,
types.ObjectType{AttrTypes: models.TriggerThresholdAttrType},
[]attr.Value{thresholdObj},
)
diags.Append(d...)

return result
}

func expandTriggerEvaluationSchedule(s []models.TriggerEvaluationScheduleModel) *client.TriggerEvaluationSchedule {
if s != nil {
days := make([]string, len(s[0].DaysOfWeek))
for i, d := range s[0].DaysOfWeek {
days[i] = d.ValueString()
}
func expandTriggerEvaluationSchedule(
ctx context.Context,
l types.List,
diags *diag.Diagnostics,
) *client.TriggerEvaluationSchedule {
if l.IsNull() || l.IsUnknown() {
return nil
}

return &client.TriggerEvaluationSchedule{
Window: client.TriggerEvaluationWindow{
StartTime: s[0].StartTime.ValueString(),
EndTime: s[0].EndTime.ValueString(),
DaysOfWeek: days,
},
}
var s []models.TriggerEvaluationScheduleModel
diags.Append(l.ElementsAs(ctx, &s, false)...)
if diags.HasError() {
return nil
}

days := make([]string, len(s[0].DaysOfWeek))
for i, d := range s[0].DaysOfWeek {
days[i] = d.ValueString()
}

return nil
return &client.TriggerEvaluationSchedule{
Window: client.TriggerEvaluationWindow{
StartTime: s[0].StartTime.ValueString(),
EndTime: s[0].EndTime.ValueString(),
DaysOfWeek: days,
},
}
}

func flattenTriggerEvaluationSchedule(t *client.Trigger) []models.TriggerEvaluationScheduleModel {
if t.EvaluationScheduleType == client.TriggerEvaluationScheduleWindow {
days := make([]basetypes.StringValue, len(t.EvaluationSchedule.Window.DaysOfWeek))
for i, d := range t.EvaluationSchedule.Window.DaysOfWeek {
days[i] = types.StringValue(d)
}
func flattenTriggerEvaluationSchedule(
ctx context.Context,
w *client.TriggerEvaluationSchedule,
diags *diag.Diagnostics,
) types.List {
if w == nil {
return types.ListNull(types.ObjectType{AttrTypes: models.TriggerEvaluationScheduleAttrType})
}

return []models.TriggerEvaluationScheduleModel{
{
StartTime: types.StringValue(t.EvaluationSchedule.Window.StartTime),
EndTime: types.StringValue(t.EvaluationSchedule.Window.EndTime),
DaysOfWeek: days,
},
}
days := make([]basetypes.StringValue, len(w.Window.DaysOfWeek))
for i, d := range w.Window.DaysOfWeek {
days[i] = types.StringValue(d)
}
daysObj, d := types.ListValueFrom(ctx, types.StringType, days)
diags.Append(d...)

scheduleObj, d := types.ObjectValue(models.TriggerEvaluationScheduleAttrType, map[string]attr.Value{
"days_of_week": daysObj,
"start_time": types.StringValue(w.Window.StartTime),
"end_time": types.StringValue(w.Window.EndTime),
})
diags.Append(d...)

result, d := types.ListValueFrom(
ctx,
types.ObjectType{AttrTypes: models.TriggerEvaluationScheduleAttrType},
[]attr.Value{scheduleObj},
)
diags.Append(d...)

return nil
return result
}
Loading

0 comments on commit a15f182

Please sign in to comment.