Skip to content

Commit 0349c88

Browse files
authored
[on_call] update validation and documentation (#3077)
Fixes #3055. Due to hashicorp/terraform-plugin-framework#740, and hashicorp/terraform-plugin-docs#363, we have to manually validate and update the docs.
1 parent 4797ffc commit 0349c88

File tree

6 files changed

+129
-21
lines changed

6 files changed

+129
-21
lines changed

datadog/fwprovider/resource_datadog_on_call_escalation_policy.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55

66
"github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
77
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
8+
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
89
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
910
"github.com/hashicorp/terraform-plugin-framework/attr"
1011
"github.com/hashicorp/terraform-plugin-framework/diag"
@@ -101,6 +102,10 @@ func (r *onCallEscalationPolicyResource) Schema(_ context.Context, _ resource.Sc
101102
Blocks: map[string]schema.Block{
102103
"step": schema.ListNestedBlock{
103104
Description: "List of steps for the escalation policy.",
105+
Validators: []validator.List{
106+
listvalidator.IsRequired(),
107+
listvalidator.SizeBetween(1, 10),
108+
},
104109
NestedObject: schema.NestedBlockObject{
105110
Attributes: map[string]schema.Attribute{
106111
"id": schema.StringAttribute{
@@ -124,6 +129,10 @@ func (r *onCallEscalationPolicyResource) Schema(_ context.Context, _ resource.Sc
124129
Blocks: map[string]schema.Block{
125130
"target": schema.ListNestedBlock{
126131
Description: "List of targets for the step.",
132+
Validators: []validator.List{
133+
listvalidator.IsRequired(),
134+
listvalidator.SizeBetween(1, 10),
135+
},
127136
NestedObject: schema.NestedBlockObject{
128137
Attributes: map[string]schema.Attribute{
129138
"user": schema.StringAttribute{

datadog/fwprovider/resource_datadog_on_call_schedule.go

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,30 @@ func NewOnCallScheduleResource() resource.Resource {
6767
return &onCallScheduleResource{}
6868
}
6969

70+
func (m *onCallScheduleModel) Validate() diag.Diagnostics {
71+
diags := diag.Diagnostics{}
72+
73+
for i, layer := range m.Layers {
74+
root := frameworkPath.Root("layer").AtListIndex(i)
75+
76+
if layer.Interval == nil {
77+
diags.AddAttributeError(root.AtName("interval"), "missing interval", "schedules must specify an interval")
78+
} else {
79+
if layer.Interval.Seconds.IsNull() && layer.Interval.Days.IsNull() {
80+
diags.AddAttributeError(root.AtName("interval"), "missing interval", "interval must specify at least one of `days` or `seconds`")
81+
}
82+
if layer.Interval.Days.ValueInt32() < 0 {
83+
diags.AddAttributeError(root.AtName("interval").AtName("days"), "invalid value", "days must be a positive integer")
84+
}
85+
if layer.Interval.Seconds.ValueInt64() < 0 {
86+
diags.AddAttributeError(root.AtName("interval").AtName("seconds"), "invalid value", "seconds must be a positive integer")
87+
}
88+
}
89+
}
90+
91+
return diags
92+
}
93+
7094
func (r *onCallScheduleResource) Configure(_ context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) {
7195
providerData, _ := request.ProviderData.(*FrameworkProvider)
7296
r.Api = providerData.DatadogApiInstances.GetOnCallApiV2()
@@ -102,6 +126,10 @@ func (r *onCallScheduleResource) Schema(_ context.Context, _ resource.SchemaRequ
102126
Blocks: map[string]schema.Block{
103127
"layer": schema.ListNestedBlock{
104128
Description: "List of layers for the schedule.",
129+
Validators: []validator.List{
130+
listvalidator.IsRequired(),
131+
listvalidator.SizeAtLeast(1),
132+
},
105133
NestedObject: schema.NestedBlockObject{
106134
Attributes: map[string]schema.Attribute{
107135
"id": schema.StringAttribute{
@@ -126,7 +154,7 @@ func (r *onCallScheduleResource) Schema(_ context.Context, _ resource.SchemaRequ
126154
},
127155
"rotation_start": schema.StringAttribute{
128156
CustomType: timetypes.RFC3339Type{},
129-
Optional: true,
157+
Required: true,
130158
Description: "The date/time when the rotation for this layer starts (in ISO 8601).",
131159
Validators: []validator.String{validators.TimeFormatValidator(time.RFC3339)},
132160
},
@@ -143,21 +171,21 @@ func (r *onCallScheduleResource) Schema(_ context.Context, _ resource.SchemaRequ
143171
NestedObject: schema.NestedBlockObject{
144172
Attributes: map[string]schema.Attribute{
145173
"end_day": schema.StringAttribute{
146-
Optional: true,
147174
Validators: []validator.String{validators.NewEnumValidator[validator.String](datadogV2.NewWeekdayFromValue)},
175+
Required: true,
148176
Description: "The weekday when the restriction period ends.",
149177
},
150178
"end_time": schema.StringAttribute{
151-
Optional: true,
179+
Required: true,
152180
Description: "The time of day when the restriction ends (hh:mm:ss).",
153181
},
154182
"start_day": schema.StringAttribute{
155-
Optional: true,
156183
Validators: []validator.String{validators.NewEnumValidator[validator.String](datadogV2.NewWeekdayFromValue)},
184+
Required: true,
157185
Description: "The weekday when the restriction period starts.",
158186
},
159187
"start_time": schema.StringAttribute{
160-
Optional: true,
188+
Required: true,
161189
Description: "The time of day when the restriction begins (hh:mm:ss).",
162190
},
163191
},
@@ -228,6 +256,11 @@ func (r *onCallScheduleResource) Create(ctx context.Context, request resource.Cr
228256
return
229257
}
230258

259+
response.Diagnostics.Append(plan.Validate()...)
260+
if response.Diagnostics.HasError() {
261+
return
262+
}
263+
231264
body, diags := r.buildOnCallScheduleRequestBody(ctx, &plan)
232265
response.Diagnostics.Append(diags...)
233266
if response.Diagnostics.HasError() {
@@ -260,6 +293,11 @@ func (r *onCallScheduleResource) Update(ctx context.Context, request resource.Up
260293
return
261294
}
262295

296+
response.Diagnostics.Append(plan.Validate()...)
297+
if response.Diagnostics.HasError() {
298+
return
299+
}
300+
263301
id := plan.ID.ValueString()
264302

265303
if id == "" {
@@ -498,15 +536,17 @@ func (r *onCallScheduleResource) buildOnCallScheduleRequestBody(ctx context.Cont
498536

499537
layersDDItem := datadogV2.NewScheduleCreateRequestDataAttributesLayersItems(
500538
effectiveDate,
501-
datadogV2.LayerAttributesInterval{
502-
Days: layersTFItem.Interval.Days.ValueInt32Pointer(),
503-
Seconds: layersTFItem.Interval.Seconds.ValueInt64Pointer(),
504-
},
539+
datadogV2.LayerAttributesInterval{},
505540
[]datadogV2.ScheduleRequestDataAttributesLayersItemsMembersItems{},
506541
layersTFItem.Name.ValueString(),
507542
rotationStart,
508543
)
509544

545+
if layersTFItem.Interval != nil {
546+
layersDDItem.Interval.Days = layersTFItem.Interval.Days.ValueInt32Pointer()
547+
layersDDItem.Interval.Seconds = layersTFItem.Interval.Seconds.ValueInt64Pointer()
548+
}
549+
510550
if !layersTFItem.EndDate.IsNull() {
511551
endDate, err := parseTime(layersTFItem.EndDate.ValueString())
512552
if err != nil {

datadog/fwprovider/resource_datadog_on_call_team_routing_rules.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,53 @@ type teamsMessageModel struct {
6060
Channel types.String `tfsdk:"channel"`
6161
}
6262

63+
func (m *onCallTeamRoutingRulesModel) Validate() diag.Diagnostics {
64+
diags := diag.Diagnostics{}
65+
66+
for i, rule := range m.Rules {
67+
root := path.Root("rule").AtListIndex(i)
68+
69+
if rule.TimeRestrictions != nil {
70+
if rule.TimeRestrictions.TimeZone.IsNull() {
71+
diags.AddAttributeError(root.AtName("time_restrictions"), "missing time_zone", "time_restrictions must specify time_zone")
72+
}
73+
if len(rule.TimeRestrictions.Restrictions) == 0 {
74+
diags.AddAttributeError(root.AtName("time_restrictions"), "missing restrictions", "time_restrictions must specify at least one restriction")
75+
}
76+
}
77+
78+
for actionIdx, action := range rule.Actions {
79+
actionPath := root.AtName("action").AtListIndex(actionIdx)
80+
if action.Teams == nil && action.Slack == nil {
81+
diags.AddAttributeError(actionPath, "missing actions", "action must specify one of send_slack_message or send_teams_message")
82+
}
83+
if action.Teams != nil {
84+
teamsPath := actionPath.AtName("send_teams_message")
85+
if action.Teams.Team.IsNull() {
86+
diags.AddAttributeError(teamsPath, "missing team", "team is required")
87+
}
88+
if action.Teams.Channel.IsNull() {
89+
diags.AddAttributeError(teamsPath, "missing channel", "channel is required")
90+
}
91+
if action.Teams.Tenant.IsNull() {
92+
diags.AddAttributeError(teamsPath, "missing tenant", "tenant is required")
93+
}
94+
}
95+
if action.Slack != nil {
96+
teamsPath := actionPath.AtName("send_slack_message")
97+
if action.Slack.Workspace.IsNull() {
98+
diags.AddAttributeError(teamsPath, "missing workspace", "workspace is required")
99+
}
100+
if action.Slack.Channel.IsNull() {
101+
diags.AddAttributeError(teamsPath, "missing channel", "channel is required")
102+
}
103+
}
104+
}
105+
}
106+
107+
return diags
108+
}
109+
63110
func NewOnCallTeamRoutingRulesResource() resource.Resource {
64111
return &onCallTeamRoutingRulesResource{}
65112
}
@@ -231,6 +278,11 @@ func (r *onCallTeamRoutingRulesResource) Create(ctx context.Context, request res
231278
return
232279
}
233280

281+
response.Diagnostics.Append(plan.Validate()...)
282+
if response.Diagnostics.HasError() {
283+
return
284+
}
285+
234286
body, diags := r.teamRoutingRulesRequestFromModel(&plan)
235287
response.Diagnostics.Append(diags...)
236288
if response.Diagnostics.HasError() {
@@ -263,6 +315,11 @@ func (r *onCallTeamRoutingRulesResource) Update(ctx context.Context, request res
263315
return
264316
}
265317

318+
response.Diagnostics.Append(plan.Validate()...)
319+
if response.Diagnostics.HasError() {
320+
return
321+
}
322+
266323
body, diags := r.teamRoutingRulesRequestFromModel(&plan)
267324
response.Diagnostics.Append(diags...)
268325
if response.Diagnostics.HasError() {

docs/resources/on_call_schedule.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ resource "datadog_on_call_schedule" "test" {
4242

4343
### Required
4444

45+
- `layer` (Block List) List of layers for the schedule. (see [below for nested schema](#nestedblock--layer))
4546
- `name` (String) A human-readable name for the new schedule.
4647
- `time_zone` (String) The time zone in which the schedule is defined.
4748

4849
### Optional
4950

50-
- `layer` (Block List) List of layers for the schedule. (see [below for nested schema](#nestedblock--layer))
5151
- `teams` (List of String) A list of team ids associated with the schedule.
5252

5353
### Read-Only
@@ -60,15 +60,15 @@ resource "datadog_on_call_schedule" "test" {
6060
Required:
6161

6262
- `effective_date` (String) The date/time when this layer should become active (in ISO 8601).
63+
- `interval` (Block List) Rotation interval for this layer. (see [below for nested schema](#nestedblock--layer--interval))
6364
- `name` (String) The name of this layer. Should be unique within the schedule.
65+
- `rotation_start` (String) The date/time when the rotation for this layer starts (in ISO 8601).
6466
- `users` (List of String) List of user IDs for the layer. Can either be a valid user id or null
6567

6668
Optional:
6769

6870
- `end_date` (String) The date/time after which this layer no longer applies (in ISO 8601).
69-
- `interval` (Block, Optional) (see [below for nested schema](#nestedblock--layer--interval))
7071
- `restriction` (Block List) List of restrictions for the layer. (see [below for nested schema](#nestedblock--layer--restriction))
71-
- `rotation_start` (String) The date/time when the rotation for this layer starts (in ISO 8601).
7272

7373
Read-Only:
7474

@@ -86,7 +86,7 @@ Optional:
8686
<a id="nestedblock--layer--restriction"></a>
8787
### Nested Schema for `layer.restriction`
8888

89-
Optional:
89+
Required:
9090

9191
- `end_day` (String) The weekday when the restriction period ends. Valid values are `monday`, `tuesday`, `wednesday`, `thursday`, `friday`, `saturday`, `sunday`.
9292
- `end_time` (String) The time of day when the restriction ends (hh:mm:ss).

docs/resources/on_call_team_routing_rules.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ Optional:
6060
- `action` (Block List) Specifies the list of actions to perform when the routing rule is matched. (see [below for nested schema](#nestedblock--rule--action))
6161
- `escalation_policy` (String) ID of the policy to be applied when this routing rule matches.
6262
- `query` (String) Defines the query or condition that triggers this routing rule. Defaults to `""`.
63-
- `time_restrictions` (Block, Optional) Holds time zone information and a list of time restrictions for a routing rule. (see [below for nested schema](#nestedblock--rule--time_restrictions))
63+
- `time_restrictions` (Block List) Holds time zone information and a list of time restrictions for a routing rule. (see [below for nested schema](#nestedblock--rule--time_restrictions))
6464
- `urgency` (String) Defines the urgency for pages created via this rule. Only valid if `escalation_policy` is set. Valid values are `high`, `low`, `dynamic`.
6565

6666
Read-Only:
@@ -72,13 +72,13 @@ Read-Only:
7272

7373
Optional:
7474

75-
- `send_slack_message` (Block, Optional) (see [below for nested schema](#nestedblock--rule--action--send_slack_message))
76-
- `send_teams_message` (Block, Optional) (see [below for nested schema](#nestedblock--rule--action--send_teams_message))
75+
- `send_slack_message` (Block List) (see [below for nested schema](#nestedblock--rule--action--send_slack_message))
76+
- `send_teams_message` (Block List) (see [below for nested schema](#nestedblock--rule--action--send_teams_message))
7777

7878
<a id="nestedblock--rule--action--send_slack_message"></a>
7979
### Nested Schema for `rule.action.send_slack_message`
8080

81-
Optional:
81+
Required:
8282

8383
- `channel` (String) Slack channel ID.
8484
- `workspace` (String) Slack workspace ID.
@@ -87,7 +87,7 @@ Optional:
8787
<a id="nestedblock--rule--action--send_teams_message"></a>
8888
### Nested Schema for `rule.action.send_teams_message`
8989

90-
Optional:
90+
Required:
9191

9292
- `channel` (String) Teams channel ID.
9393
- `team` (String) Teams team ID.
@@ -98,15 +98,15 @@ Optional:
9898
<a id="nestedblock--rule--time_restrictions"></a>
9999
### Nested Schema for `rule.time_restrictions`
100100

101-
Optional:
101+
Required:
102102

103-
- `restriction` (Block List) List of restrictions for the rule. (see [below for nested schema](#nestedblock--rule--time_restrictions--restriction))
104103
- `time_zone` (String) Specifies the time zone applicable to the restrictions, e.g. `America/New_York`.
104+
- `restriction` (Block List) List of restrictions for the rule. (see [below for nested schema](#nestedblock--rule--time_restrictions--restriction))
105105

106106
<a id="nestedblock--rule--time_restrictions--restriction"></a>
107107
### Nested Schema for `rule.time_restrictions.restriction`
108108

109-
Optional:
109+
Required:
110110

111111
- `end_day` (String) The weekday when the restriction period ends. Valid values are `monday`, `tuesday`, `wednesday`, `thursday`, `friday`, `saturday`, `sunday`.
112112
- `end_time` (String) The time of day when the restriction ends (hh:mm:ss).

scripts/generate-docs.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
exclude_files=(
66
"docs/resources/integration_aws_account.md"
77
"docs/resources/compliance_custom_framework.md"
8+
"docs/resources/on_call_schedule.md"
9+
"docs/resources/on_call_team_routing_rules.md"
810
)
911

1012
# Check if manual changes were made to any excluded files and exit

0 commit comments

Comments
 (0)