Skip to content

Commit

Permalink
Add validations for pagerduty_service properties inside blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
cjgajard committed Apr 12, 2024
1 parent 4befe31 commit 2aeff7a
Show file tree
Hide file tree
Showing 6 changed files with 437 additions and 39 deletions.
78 changes: 45 additions & 33 deletions pagerdutyplugin/resource_pagerduty_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import (

"github.com/PagerDuty/go-pagerduty"
"github.com/PagerDuty/terraform-provider-pagerduty/util"
"github.com/PagerDuty/terraform-provider-pagerduty/util/enumtypes"
"github.com/PagerDuty/terraform-provider-pagerduty/util/rangetypes"
"github.com/PagerDuty/terraform-provider-pagerduty/util/tztypes"
"github.com/PagerDuty/terraform-provider-pagerduty/util/validate"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
Expand Down Expand Up @@ -128,24 +131,18 @@ func (r *resourceService) Schema(ctx context.Context, req resource.SchemaRequest
listvalidator.SizeBetween(1, 1),
listvalidator.ConflictsWith(path.MatchRoot("alert_grouping")),
listvalidator.ConflictsWith(path.MatchRoot("alert_grouping_timeout")),
// util.ValidateAlertGroupingParametersType("time", "intelligent", "rules"),
// util.ValidateAlertGroupingParametersConfigAggregate("all", "any"),
// util.ValidateAlertGroupingParametersConfigTimeWindow(300, 3600),
},
ElementType: types.ObjectType{
AttrTypes: map[string]attr.Type{
"type": types.StringType,
// Validators: []validator.String{ stringvalidator.OneOf("time", "intelligent", "rules"), },
"type": alertGroupingParametersTypeType,
"config": types.ListType{
// Validators: []validator.List{listvalidator.SizeAtMost(1)},
ElemType: types.ObjectType{
AttrTypes: map[string]attr.Type{
"timeout": types.Int64Type,
"fields": types.ListType{ElemType: types.StringType},
"aggregate": types.StringType,
// Validators: []validator.String{ stringvalidator.OneOf("all", "any"), },
"time_window": types.Int64Type,
// Validators: []validator.Int64{ int64validator.Between(300, 3600), },
"timeout": types.Int64Type,
"fields": types.ListType{ElemType: types.StringType},
"aggregate": alertGroupingParametersConfigAggregateType,
"time_window": alertGroupingParametersConfigTimeWindowType,
},
},
},
Expand All @@ -163,8 +160,7 @@ func (r *resourceService) Schema(ctx context.Context, req resource.SchemaRequest
ElementType: types.ObjectType{
AttrTypes: map[string]attr.Type{
"enabled": types.BoolType,
"timeout": types.Int64Type,
// Validators: []validator.Int64{ int64validator.OneOf(120, 180, 300, 600, 900), },
"timeout": autoPauseNotificationsParametersTimeoutType,
},
},
},
Expand Down Expand Up @@ -241,8 +237,7 @@ func (r *resourceService) Schema(ctx context.Context, req resource.SchemaRequest
"type": types.StringType,
"start_time": types.StringType,
"end_time": types.StringType,
"time_zone": types.StringType,
// Validators: []validator.String{util.ValidateTimezone()},
"time_zone": tztypes.StringType{},
"days_of_week": types.ListType{
// Validators: []validator.List{ listvalidator.SizeAtMost(7), },
ElemType: types.StringType,
Expand Down Expand Up @@ -277,8 +272,6 @@ func (r *resourceService) Create(ctx context.Context, req resource.CreateRequest
return
}

log.Printf("[CG] %#v", service)

err = retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
serviceResponse, err := r.client.GetServiceWithContext(ctx, service.ID, &pagerduty.GetServiceOptions{
Includes: []string{"auto_pause_notifications_parameters"},
Expand All @@ -289,7 +282,6 @@ func (r *resourceService) Create(ctx context.Context, req resource.CreateRequest
}
return retry.RetryableError(err)
}
log.Printf("[CG] serviceResponse: %#v", serviceResponse)
model = flattenService(ctx, serviceResponse, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return retry.NonRetryableError(fmt.Errorf("%#v", resp.Diagnostics))
Expand All @@ -301,7 +293,6 @@ func (r *resourceService) Create(ctx context.Context, req resource.CreateRequest
return
}

log.Printf("[CG] Model: %#v", service)
resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
}

Expand Down Expand Up @@ -595,7 +586,6 @@ func buildSupportHours(ctx context.Context, list types.List, diags *diag.Diagnos

if !obj.DaysOfWeek.IsNull() {
daysOfWeekStr := []string{}
log.Printf("[CG] %#v", obj.DaysOfWeek)
if d := obj.DaysOfWeek.ElementsAs(ctx, &daysOfWeekStr, false); d.HasError() {
diags.Append(d...)
return nil
Expand All @@ -613,6 +603,17 @@ func buildSupportHours(ctx context.Context, list types.List, diags *diag.Diagnos
return supportHours
}

var (
alertGroupingParametersTypeType = enumtypes.StringType{
OneOf: []string{"time", "intelligent", "rules"}}
alertGroupingParametersConfigAggregateType = enumtypes.StringType{
OneOf: []string{"all", "any"}}
alertGroupingParametersConfigTimeWindowType = rangetypes.Int64Type{
Start: 300, End: 3600}
autoPauseNotificationsParametersTimeoutType = enumtypes.Int64Type{
OneOf: []int64{120, 180, 300, 600, 900}}
)

func flattenService(ctx context.Context, service *pagerduty.Service, diags *diag.Diagnostics) resourceServiceModel {
model := resourceServiceModel{
ID: types.StringValue(service.ID),
Expand Down Expand Up @@ -663,18 +664,19 @@ func flattenService(ctx context.Context, service *pagerduty.Service, diags *diag
func flattenAlertGroupingParameters(ctx context.Context, params *pagerduty.AlertGroupingParameters, diags *diag.Diagnostics) types.List {
alertGroupParamsConfigObjectType := types.ObjectType{
AttrTypes: map[string]attr.Type{
"aggregate": types.StringType,
"aggregate": alertGroupingParametersConfigAggregateType,
"fields": types.ListType{ElemType: types.StringType},
"timeout": types.Int64Type,
"time_window": types.Int64Type,
"time_window": alertGroupingParametersConfigTimeWindowType,
},
}
alertGroupingParametersObjectType := types.ObjectType{
AttrTypes: map[string]attr.Type{
"type": types.StringType,
"type": alertGroupingParametersTypeType,
"config": types.ListType{ElemType: alertGroupParamsConfigObjectType},
},
}

nullList := types.ListNull(alertGroupingParametersObjectType)
if params == nil {
return nullList
Expand All @@ -693,9 +695,9 @@ func flattenAlertGroupingParameters(ctx context.Context, params *pagerduty.Alert
timeout = types.Int64Value(int64(*params.Config.Timeout))
}

aggregate := types.StringNull()
aggregate := enumtypes.NewStringNull(alertGroupingParametersConfigAggregateType)
if params.Config.Aggregate != "" {
aggregate = types.StringValue(params.Config.Aggregate)
aggregate = enumtypes.NewStringValue(params.Config.Aggregate, alertGroupingParametersConfigAggregateType)
}

configObj, d := types.ObjectValue(alertGroupParamsConfigObjectType.AttrTypes, map[string]attr.Value{
Expand All @@ -716,32 +718,42 @@ func flattenAlertGroupingParameters(ctx context.Context, params *pagerduty.Alert
}

obj, d := types.ObjectValue(alertGroupingParametersObjectType.AttrTypes, map[string]attr.Value{
"type": types.StringValue(params.Type),
"type": enumtypes.NewStringValue(params.Type, alertGroupingParametersTypeType),
"config": configList,
})
diags.Append(d...)
if d.HasError() {
diags.Append(d...)
return nullList
}

return types.ListValueMust(alertGroupingParametersObjectType, []attr.Value{obj})
list, d := types.ListValue(alertGroupingParametersObjectType, []attr.Value{obj})
diags.Append(d...)
if d.HasError() {
return nullList
}

return list
}

func flattenAutoPauseNotificationsParameters(params *pagerduty.AutoPauseNotificationsParameters, diags *diag.Diagnostics) types.List {
autoPauseNotificationsParametersObjectType := types.ObjectType{
AttrTypes: map[string]attr.Type{
"enabled": types.BoolType,
"timeout": types.Int64Type,
"timeout": autoPauseNotificationsParametersTimeoutType,
},
}

nullList := types.ListNull(autoPauseNotificationsParametersObjectType)
if params == nil {
return nullList
}

timeout := types.Int64Null()
timeout := enumtypes.NewInt64Null(autoPauseNotificationsParametersTimeoutType)
if params.Enabled {
timeout = types.Int64Value(int64(params.Timeout))
timeout = enumtypes.NewInt64Value(
int64(params.Timeout),
autoPauseNotificationsParametersTimeoutType,
)
}

obj, d := types.ObjectValue(autoPauseNotificationsParametersObjectType.AttrTypes, map[string]attr.Value{
Expand Down Expand Up @@ -886,7 +898,7 @@ func flattenSupportHours(hours *pagerduty.SupportHours, diags *diag.Diagnostics)
"type": types.StringType,
"start_time": types.StringType,
"end_time": types.StringType,
"time_zone": types.StringType,
"time_zone": tztypes.StringType{},
"days_of_week": types.ListType{ElemType: types.StringType},
},
}
Expand All @@ -908,7 +920,7 @@ func flattenSupportHours(hours *pagerduty.SupportHours, diags *diag.Diagnostics)
"type": types.StringValue(hours.Type),
"start_time": types.StringValue(hours.StartTime),
"end_time": types.StringValue(hours.EndTime),
"time_zone": types.StringValue(hours.Timezone),
"time_zone": tztypes.NewStringValue(hours.Timezone),
"days_of_week": dowList,
})
if d.HasError() {
Expand Down
105 changes: 105 additions & 0 deletions util/enumtypes/int64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package enumtypes

import (
"context"
"fmt"
"math/big"
"slices"

Check failure on line 7 in util/enumtypes/int64.go

View workflow job for this annotation

GitHub Actions / test

package slices is not in GOROOT (/opt/hostedtoolcache/go/1.20.14/x64/src/slices)

"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/types/basetypes"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)

type Int64Value struct {
basetypes.Int64Value
EnumType Int64Type
}

func NewInt64Null(t Int64Type) Int64Value {
return Int64Value{Int64Value: basetypes.NewInt64Null(), EnumType: t}
}

func NewInt64Value(v int64, t Int64Type) Int64Value {
return Int64Value{Int64Value: basetypes.NewInt64Value(v), EnumType: t}
}

func (s Int64Value) Type(_ context.Context) attr.Type {
return s.EnumType
}

type Int64Type struct {
basetypes.Int64Type
OneOf []int64
}

func (t Int64Type) Int64() string {
return "enumtypes.Int64Type"
}

func (t Int64Type) Equal(o attr.Type) bool {
if t2, ok := o.(Int64Type); ok {
return slices.Equal(t.OneOf, t2.OneOf)
}
return t.Int64Type.Equal(o)
}

func (t Int64Type) Validate(ctx context.Context, in tftypes.Value, path path.Path) (diags diag.Diagnostics) {
if in.Type() == nil {
return
}

if !in.Type().Is(tftypes.Number) {
err := fmt.Errorf("expected Int64 value, received %T with value: %v", in, in)
diags.AddAttributeError(
path,
"Type Validation Error",
"An unexpected error was encountered trying to validate an attribute value. This is always an error in the provider. "+
"Please report the following to the provider developer:\n\n"+err.Error(),
)
return diags
}

if !in.IsKnown() || in.IsNull() {
return diags
}

var valueFloat big.Float
if err := in.As(&valueFloat); err != nil {
diags.AddAttributeError(
path,
"Type Validation Error",
"An unexpected error was encountered trying to validate an attribute value. This is always an error in the provider. "+
"Please report the following to the provider developer:\n\n"+err.Error(),
)
return
}
valueInt64, _ := valueFloat.Int64()

found := false
for _, v := range t.OneOf {
if v == valueInt64 {
found = true
break
}
}

if !found {
diags.AddAttributeError(
path,
"Invalid Int64 Value",
fmt.Sprintf(
"A string value was provided that is not valid.\n"+
"Given Value: %v\n"+
"Expecting One Of: %v",
valueInt64,
t.OneOf,
),
)
return
}

return
}
Loading

0 comments on commit 2aeff7a

Please sign in to comment.