Skip to content

Commit 319d56a

Browse files
authored
[datadog_spans_metric] Fix validation with unintended side effects (#2983)
* [datadog_spans_metric] Remove validation that breaks declaration using a dynamic block * [datadog_spans_metric] Added tests for dynamic declaration of group_by * [datadog_spans_metric] Modified validation to avoid dynamic blocks breaking and changed tests accordignly * [datadog_spans_metric] (NIT) Added back the interface implementation check
1 parent e8fdc23 commit 319d56a

14 files changed

+384
-109
lines changed

datadog/fwprovider/resource_datadog_spans_metric.go

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
77
"github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator"
88
"github.com/hashicorp/terraform-plugin-framework/diag"
9+
"github.com/hashicorp/terraform-plugin-framework/path"
910
frameworkPath "github.com/hashicorp/terraform-plugin-framework/path"
1011
"github.com/hashicorp/terraform-plugin-framework/resource"
1112
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
@@ -146,6 +147,26 @@ func (r *spansMetricResource) Schema(_ context.Context, _ resource.SchemaRequest
146147
},
147148
}
148149
}
150+
func (r *spansMetricResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) {
151+
var data computeModel
152+
resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("compute"), &data)...)
153+
154+
if resp.Diagnostics.HasError() {
155+
return
156+
}
157+
158+
if data.IncludePercentiles.IsNull() || data.IncludePercentiles.IsUnknown() {
159+
return
160+
}
161+
162+
if data.AggregationType.ValueString() != "distribution" && !data.IncludePercentiles.IsUnknown() {
163+
resp.Diagnostics.AddAttributeError(
164+
frameworkPath.Root("compute").AtName("include_percentiles"),
165+
"Invalid configuration",
166+
"include_percentiles can only be set when aggregation_type is 'distribution'",
167+
)
168+
}
169+
}
149170

150171
type includePercentilesUnknownSuppressor struct{}
151172

@@ -174,27 +195,6 @@ func (m includePercentilesUnknownSuppressor) PlanModifyBool(ctx context.Context,
174195
}
175196
}
176197

177-
func (r *spansMetricResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) {
178-
var data spansMetricModel
179-
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
180-
181-
if resp.Diagnostics.HasError() {
182-
return
183-
}
184-
185-
if data.Compute.IncludePercentiles.IsNull() || data.Compute.IncludePercentiles.IsUnknown() {
186-
return
187-
}
188-
189-
if data.Compute.AggregationType.ValueString() != "distribution" && !data.Compute.IncludePercentiles.IsUnknown() {
190-
resp.Diagnostics.AddAttributeError(
191-
frameworkPath.Root("compute").AtName("include_percentiles"),
192-
"Invalid configuration",
193-
"include_percentiles can only be set when aggregation_type is 'distribution'",
194-
)
195-
}
196-
}
197-
198198
func (r *spansMetricResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) {
199199
resource.ImportStatePassthroughID(ctx, frameworkPath.Root("id"), request, response)
200200
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2025-02-03T11:56:40.519271+01:00
1+
2025-04-29T15:35:17.293466+02:00

datadog/tests/cassettes/TestAccSpansMetricBasic.yaml

Lines changed: 45 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ interactions:
1313
remote_addr: ""
1414
request_uri: ""
1515
body: |
16-
{"data":{"attributes":{"compute":{"aggregation_type":"distribution","include_percentiles":false,"path":"@duration"},"filter":{"query":"@http.status_code:200 service:my-service"},"group_by":[{"path":"resource_name","tag_name":"resource_name"}]},"id":"\"tf_TestAccSpansMetricBasic_local_1738580200\"","type":"spans_metrics"}}
16+
{"data":{"attributes":{"compute":{"aggregation_type":"distribution","include_percentiles":false,"path":"@duration"},"filter":{"query":"@http.status_code:200 service:my-service"},"group_by":[{"path":"resource_name","tag_name":"resource_name"}]},"id":"\"tf_TestAccSpansMetricBasic_local_1745933717\"","type":"spans_metrics"}}
1717
form: {}
1818
headers:
1919
Accept:
@@ -23,21 +23,22 @@ interactions:
2323
url: https://api.datadoghq.com/api/v2/apm/config/metrics
2424
method: POST
2525
response:
26-
proto: HTTP/2.0
27-
proto_major: 2
28-
proto_minor: 0
29-
transfer_encoding: []
26+
proto: HTTP/1.1
27+
proto_major: 1
28+
proto_minor: 1
29+
transfer_encoding:
30+
- chunked
3031
trailer: {}
3132
content_length: -1
3233
uncompressed: true
3334
body: |
34-
{"data":{"id":"tf_TestAccSpansMetricBasic_local_1738580200","attributes":{"filter":{"query":"@http.status_code:200 service:my-service"},"group_by":[{"path":"resource_name","tag_name":"resource_name"}],"compute":{"aggregation_type":"distribution","path":"@duration","include_percentiles":false}},"type":"spans_metrics"}}
35+
{"data":{"id":"tf_TestAccSpansMetricBasic_local_1745933717","attributes":{"filter":{"query":"@http.status_code:200 service:my-service"},"group_by":[{"path":"resource_name","tag_name":"resource_name"}],"compute":{"aggregation_type":"distribution","path":"@duration","include_percentiles":false}},"type":"spans_metrics"}}
3536
headers:
3637
Content-Type:
3738
- application/json
3839
status: 200 OK
3940
code: 200
40-
duration: 448.400417ms
41+
duration: 759.568708ms
4142
- id: 1
4243
request:
4344
proto: HTTP/1.1
@@ -54,24 +55,25 @@ interactions:
5455
headers:
5556
Accept:
5657
- application/json
57-
url: https://api.datadoghq.com/api/v2/apm/config/metrics/tf_TestAccSpansMetricBasic_local_1738580200
58+
url: https://api.datadoghq.com/api/v2/apm/config/metrics/tf_TestAccSpansMetricBasic_local_1745933717
5859
method: GET
5960
response:
60-
proto: HTTP/2.0
61-
proto_major: 2
62-
proto_minor: 0
63-
transfer_encoding: []
61+
proto: HTTP/1.1
62+
proto_major: 1
63+
proto_minor: 1
64+
transfer_encoding:
65+
- chunked
6466
trailer: {}
6567
content_length: -1
6668
uncompressed: true
6769
body: |
68-
{"data":{"id":"tf_TestAccSpansMetricBasic_local_1738580200","attributes":{"filter":{"query":"@http.status_code:200 service:my-service"},"group_by":[{"path":"resource_name","tag_name":"resource_name"}],"compute":{"aggregation_type":"distribution","path":"@duration","include_percentiles":false}},"type":"spans_metrics"}}
70+
{"data":{"id":"tf_TestAccSpansMetricBasic_local_1745933717","attributes":{"filter":{"query":"@http.status_code:200 service:my-service"},"group_by":[{"path":"resource_name","tag_name":"resource_name"}],"compute":{"aggregation_type":"distribution","path":"@duration","include_percentiles":false}},"type":"spans_metrics"}}
6971
headers:
7072
Content-Type:
7173
- application/json
7274
status: 200 OK
7375
code: 200
74-
duration: 122.608334ms
76+
duration: 129.931958ms
7577
- id: 2
7678
request:
7779
proto: HTTP/1.1
@@ -88,24 +90,25 @@ interactions:
8890
headers:
8991
Accept:
9092
- application/json
91-
url: https://api.datadoghq.com/api/v2/apm/config/metrics/tf_TestAccSpansMetricBasic_local_1738580200
93+
url: https://api.datadoghq.com/api/v2/apm/config/metrics/tf_TestAccSpansMetricBasic_local_1745933717
9294
method: GET
9395
response:
94-
proto: HTTP/2.0
95-
proto_major: 2
96-
proto_minor: 0
97-
transfer_encoding: []
96+
proto: HTTP/1.1
97+
proto_major: 1
98+
proto_minor: 1
99+
transfer_encoding:
100+
- chunked
98101
trailer: {}
99102
content_length: -1
100103
uncompressed: true
101104
body: |
102-
{"data":{"id":"tf_TestAccSpansMetricBasic_local_1738580200","attributes":{"filter":{"query":"@http.status_code:200 service:my-service"},"group_by":[{"path":"resource_name","tag_name":"resource_name"}],"compute":{"aggregation_type":"distribution","path":"@duration","include_percentiles":false}},"type":"spans_metrics"}}
105+
{"data":{"id":"tf_TestAccSpansMetricBasic_local_1745933717","attributes":{"filter":{"query":"@http.status_code:200 service:my-service"},"group_by":[{"path":"resource_name","tag_name":"resource_name"}],"compute":{"aggregation_type":"distribution","path":"@duration","include_percentiles":false}},"type":"spans_metrics"}}
103106
headers:
104107
Content-Type:
105108
- application/json
106109
status: 200 OK
107110
code: 200
108-
duration: 129.687125ms
111+
duration: 132.424417ms
109112
- id: 3
110113
request:
111114
proto: HTTP/1.1
@@ -125,24 +128,25 @@ interactions:
125128
- application/json
126129
Content-Type:
127130
- application/json
128-
url: https://api.datadoghq.com/api/v2/apm/config/metrics/tf_TestAccSpansMetricBasic_local_1738580200
131+
url: https://api.datadoghq.com/api/v2/apm/config/metrics/tf_TestAccSpansMetricBasic_local_1745933717
129132
method: PATCH
130133
response:
131-
proto: HTTP/2.0
132-
proto_major: 2
133-
proto_minor: 0
134-
transfer_encoding: []
134+
proto: HTTP/1.1
135+
proto_major: 1
136+
proto_minor: 1
137+
transfer_encoding:
138+
- chunked
135139
trailer: {}
136140
content_length: -1
137141
uncompressed: true
138142
body: |
139-
{"data":{"id":"tf_TestAccSpansMetricBasic_local_1738580200","attributes":{"filter":{"query":"*"},"group_by":[],"compute":{"aggregation_type":"distribution","path":"@duration","include_percentiles":true}},"type":"spans_metrics"}}
143+
{"data":{"id":"tf_TestAccSpansMetricBasic_local_1745933717","attributes":{"filter":{"query":"*"},"group_by":[],"compute":{"aggregation_type":"distribution","path":"@duration","include_percentiles":true}},"type":"spans_metrics"}}
140144
headers:
141145
Content-Type:
142146
- application/json
143147
status: 200 OK
144148
code: 200
145-
duration: 236.091042ms
149+
duration: 268.373708ms
146150
- id: 4
147151
request:
148152
proto: HTTP/1.1
@@ -159,24 +163,25 @@ interactions:
159163
headers:
160164
Accept:
161165
- application/json
162-
url: https://api.datadoghq.com/api/v2/apm/config/metrics/tf_TestAccSpansMetricBasic_local_1738580200
166+
url: https://api.datadoghq.com/api/v2/apm/config/metrics/tf_TestAccSpansMetricBasic_local_1745933717
163167
method: GET
164168
response:
165-
proto: HTTP/2.0
166-
proto_major: 2
167-
proto_minor: 0
168-
transfer_encoding: []
169+
proto: HTTP/1.1
170+
proto_major: 1
171+
proto_minor: 1
172+
transfer_encoding:
173+
- chunked
169174
trailer: {}
170175
content_length: -1
171176
uncompressed: true
172177
body: |
173-
{"data":{"id":"tf_TestAccSpansMetricBasic_local_1738580200","attributes":{"filter":{"query":"*"},"group_by":[],"compute":{"aggregation_type":"distribution","path":"@duration","include_percentiles":true}},"type":"spans_metrics"}}
178+
{"data":{"id":"tf_TestAccSpansMetricBasic_local_1745933717","attributes":{"filter":{"query":"*"},"group_by":[],"compute":{"aggregation_type":"distribution","path":"@duration","include_percentiles":true}},"type":"spans_metrics"}}
174179
headers:
175180
Content-Type:
176181
- application/json
177182
status: 200 OK
178183
code: 200
179-
duration: 124.605ms
184+
duration: 139.312791ms
180185
- id: 5
181186
request:
182187
proto: HTTP/1.1
@@ -193,12 +198,12 @@ interactions:
193198
headers:
194199
Accept:
195200
- '*/*'
196-
url: https://api.datadoghq.com/api/v2/apm/config/metrics/tf_TestAccSpansMetricBasic_local_1738580200
201+
url: https://api.datadoghq.com/api/v2/apm/config/metrics/tf_TestAccSpansMetricBasic_local_1745933717
197202
method: DELETE
198203
response:
199-
proto: HTTP/2.0
200-
proto_major: 2
201-
proto_minor: 0
204+
proto: HTTP/1.1
205+
proto_major: 1
206+
proto_minor: 1
202207
transfer_encoding: []
203208
trailer: {}
204209
content_length: 0
@@ -209,4 +214,4 @@ interactions:
209214
- text/html; charset=utf-8
210215
status: 204 No Content
211216
code: 204
212-
duration: 146.191333ms
217+
duration: 156.094541ms
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2025-04-24T15:39:59.557799+02:00
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
---
2+
version: 2
3+
interactions:
4+
- id: 0
5+
request:
6+
proto: HTTP/1.1
7+
proto_major: 1
8+
proto_minor: 1
9+
content_length: 221
10+
transfer_encoding: []
11+
trailer: {}
12+
host: api.datadoghq.com
13+
remote_addr: ""
14+
request_uri: ""
15+
body: |
16+
{"data":{"attributes":{"compute":{"aggregation_type":"count"},"filter":{"query":"@http.status_code:200 service:my-service"}},"id":"\"tf_TestAccSpansMetricDynamicGroupBys_empty_local_1745501999\"","type":"spans_metrics"}}
17+
form: {}
18+
headers:
19+
Accept:
20+
- application/json
21+
Content-Type:
22+
- application/json
23+
url: https://api.datadoghq.com/api/v2/apm/config/metrics
24+
method: POST
25+
response:
26+
proto: HTTP/1.1
27+
proto_major: 1
28+
proto_minor: 1
29+
transfer_encoding:
30+
- chunked
31+
trailer: {}
32+
content_length: -1
33+
uncompressed: true
34+
body: |
35+
{"data":{"id":"tf_TestAccSpansMetricDynamicGroupBys_empty_local_1745501999","attributes":{"filter":{"query":"@http.status_code:200 service:my-service"},"group_by":[],"compute":{"aggregation_type":"count"}},"type":"spans_metrics"}}
36+
headers:
37+
Content-Type:
38+
- application/json
39+
status: 200 OK
40+
code: 200
41+
duration: 732.442167ms
42+
- id: 1
43+
request:
44+
proto: HTTP/1.1
45+
proto_major: 1
46+
proto_minor: 1
47+
content_length: 0
48+
transfer_encoding: []
49+
trailer: {}
50+
host: api.datadoghq.com
51+
remote_addr: ""
52+
request_uri: ""
53+
body: ""
54+
form: {}
55+
headers:
56+
Accept:
57+
- application/json
58+
url: https://api.datadoghq.com/api/v2/apm/config/metrics/tf_TestAccSpansMetricDynamicGroupBys_empty_local_1745501999
59+
method: GET
60+
response:
61+
proto: HTTP/1.1
62+
proto_major: 1
63+
proto_minor: 1
64+
transfer_encoding:
65+
- chunked
66+
trailer: {}
67+
content_length: -1
68+
uncompressed: true
69+
body: |
70+
{"data":{"id":"tf_TestAccSpansMetricDynamicGroupBys_empty_local_1745501999","attributes":{"filter":{"query":"@http.status_code:200 service:my-service"},"group_by":[],"compute":{"aggregation_type":"count"}},"type":"spans_metrics"}}
71+
headers:
72+
Content-Type:
73+
- application/json
74+
status: 200 OK
75+
code: 200
76+
duration: 156.014542ms
77+
- id: 2
78+
request:
79+
proto: HTTP/1.1
80+
proto_major: 1
81+
proto_minor: 1
82+
content_length: 0
83+
transfer_encoding: []
84+
trailer: {}
85+
host: api.datadoghq.com
86+
remote_addr: ""
87+
request_uri: ""
88+
body: ""
89+
form: {}
90+
headers:
91+
Accept:
92+
- '*/*'
93+
url: https://api.datadoghq.com/api/v2/apm/config/metrics/tf_TestAccSpansMetricDynamicGroupBys_empty_local_1745501999
94+
method: DELETE
95+
response:
96+
proto: HTTP/1.1
97+
proto_major: 1
98+
proto_minor: 1
99+
transfer_encoding: []
100+
trailer: {}
101+
content_length: 0
102+
uncompressed: false
103+
body: ""
104+
headers:
105+
Content-Type:
106+
- text/html; charset=utf-8
107+
status: 204 No Content
108+
code: 204
109+
duration: 153.784667ms
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2025-04-24T15:39:59.557929+02:00

0 commit comments

Comments
 (0)