Skip to content

Commit 04bb863

Browse files
cloudprovider: fix list base types for AWS scrape jobs (#1952)
* start changing any nested Go types to proper TF types * fix nested attribute types * finish impl
1 parent d7f6390 commit 04bb863

File tree

1 file changed

+181
-68
lines changed

1 file changed

+181
-68
lines changed

internal/resources/cloudprovider/models.go

Lines changed: 181 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ type awsCWScrapeJobTFResourceModel struct {
2424
// TODO(tristan): if the grafana provider is updated to use the Terraform v6 plugin protocol,
2525
// we can consider adding additional support to use Set Nested Attributes, instead of Blocks.
2626
// See https://developer.hashicorp.com/terraform/plugin/framework/handling-data/attributes#nested-attribute-types
27-
Services []awsCWScrapeJobServiceTFModel `tfsdk:"service"`
28-
CustomNamespaces []awsCWScrapeJobCustomNamespaceTFModel `tfsdk:"custom_namespace"`
27+
Services types.List `tfsdk:"service"`
28+
CustomNamespaces types.List `tfsdk:"custom_namespace"`
2929
}
30+
3031
type awsCWScrapeJobTFDataSourceModel struct {
3132
ID types.String `tfsdk:"id"`
3233
StackID types.String `tfsdk:"stack_id"`
@@ -41,30 +42,82 @@ type awsCWScrapeJobTFDataSourceModel struct {
4142
// TODO(tristan): if the grafana provider is updated to use the Terraform v6 plugin protocol,
4243
// we can consider adding additional support to use Set Nested Attributes, instead of Blocks.
4344
// See https://developer.hashicorp.com/terraform/plugin/framework/handling-data/attributes#nested-attribute-types
44-
Services []awsCWScrapeJobServiceTFModel `tfsdk:"service"`
45-
CustomNamespaces []awsCWScrapeJobCustomNamespaceTFModel `tfsdk:"custom_namespace"`
45+
Services types.List `tfsdk:"service"`
46+
CustomNamespaces types.List `tfsdk:"custom_namespace"`
4647
}
48+
4749
type awsCWScrapeJobServiceTFModel struct {
48-
Name types.String `tfsdk:"name"`
49-
Metrics []awsCWScrapeJobMetricTFModel `tfsdk:"metric"`
50-
ScrapeIntervalSeconds types.Int64 `tfsdk:"scrape_interval_seconds"`
51-
ResourceDiscoveryTagFilters []awsCWScrapeJobTagFilterTFModel `tfsdk:"resource_discovery_tag_filter"`
52-
TagsToAddToMetrics types.Set `tfsdk:"tags_to_add_to_metrics"`
50+
Name types.String `tfsdk:"name"`
51+
Metrics types.List `tfsdk:"metric"`
52+
ScrapeIntervalSeconds types.Int64 `tfsdk:"scrape_interval_seconds"`
53+
ResourceDiscoveryTagFilters types.List `tfsdk:"resource_discovery_tag_filter"`
54+
TagsToAddToMetrics types.Set `tfsdk:"tags_to_add_to_metrics"`
55+
}
56+
57+
func (m awsCWScrapeJobServiceTFModel) attrTypes() map[string]attr.Type {
58+
return map[string]attr.Type{
59+
"name": types.StringType,
60+
"metric": types.ListType{
61+
ElemType: types.ObjectType{
62+
AttrTypes: awsCWScrapeJobMetricTFModel{}.attrTypes(),
63+
},
64+
},
65+
"scrape_interval_seconds": types.Int64Type,
66+
"resource_discovery_tag_filter": types.ListType{
67+
ElemType: types.ObjectType{
68+
AttrTypes: awsCWScrapeJobTagFilterTFModel{}.attrTypes(),
69+
},
70+
},
71+
"tags_to_add_to_metrics": types.SetType{
72+
ElemType: types.StringType,
73+
},
74+
}
5375
}
76+
5477
type awsCWScrapeJobCustomNamespaceTFModel struct {
55-
Name types.String `tfsdk:"name"`
56-
Metrics []awsCWScrapeJobMetricTFModel `tfsdk:"metric"`
57-
ScrapeIntervalSeconds types.Int64 `tfsdk:"scrape_interval_seconds"`
78+
Name types.String `tfsdk:"name"`
79+
Metrics types.List `tfsdk:"metric"`
80+
ScrapeIntervalSeconds types.Int64 `tfsdk:"scrape_interval_seconds"`
81+
}
82+
83+
func (m awsCWScrapeJobCustomNamespaceTFModel) attrTypes() map[string]attr.Type {
84+
return map[string]attr.Type{
85+
"name": types.StringType,
86+
"metric": types.ListType{
87+
ElemType: types.ObjectType{
88+
AttrTypes: awsCWScrapeJobMetricTFModel{}.attrTypes(),
89+
},
90+
},
91+
"scrape_interval_seconds": types.Int64Type,
92+
}
5893
}
94+
5995
type awsCWScrapeJobMetricTFModel struct {
6096
Name types.String `tfsdk:"name"`
6197
Statistics types.Set `tfsdk:"statistics"`
6298
}
99+
100+
func (m awsCWScrapeJobMetricTFModel) attrTypes() map[string]attr.Type {
101+
return map[string]attr.Type{
102+
"name": types.StringType,
103+
"statistics": types.SetType{
104+
ElemType: types.StringType,
105+
},
106+
}
107+
}
108+
63109
type awsCWScrapeJobTagFilterTFModel struct {
64110
Key types.String `tfsdk:"key"`
65111
Value types.String `tfsdk:"value"`
66112
}
67113

114+
func (m awsCWScrapeJobTagFilterTFModel) attrTypes() map[string]attr.Type {
115+
return map[string]attr.Type{
116+
"key": types.StringType,
117+
"value": types.StringType,
118+
}
119+
}
120+
68121
type awsCWScrapeJobNoDuplicateServiceNamesValidator struct{}
69122

70123
func (v awsCWScrapeJobNoDuplicateServiceNamesValidator) Description(ctx context.Context) string {
@@ -76,15 +129,15 @@ func (v awsCWScrapeJobNoDuplicateServiceNamesValidator) MarkdownDescription(ctx
76129
}
77130

78131
func (v awsCWScrapeJobNoDuplicateServiceNamesValidator) ValidateList(ctx context.Context, req validator.ListRequest, resp *validator.ListResponse) {
79-
seen := map[string]struct{}{}
80-
elems := make([]awsCWScrapeJobServiceTFModel, len(req.ConfigValue.Elements()))
81-
diags := req.ConfigValue.ElementsAs(ctx, &elems, false)
132+
var services []awsCWScrapeJobServiceTFModel
133+
diags := req.ConfigValue.ElementsAs(ctx, &services, true)
82134
resp.Diagnostics.Append(diags...)
83135
if diags.HasError() {
84136
return
85137
}
86-
for _, elem := range elems {
87-
name := elem.Name.ValueString()
138+
seen := map[string]struct{}{}
139+
for _, service := range services {
140+
name := service.Name.ValueString()
88141
if _, ok := seen[name]; ok {
89142
resp.Diagnostics.AddError("Duplicate service name", fmt.Sprintf("Service name %q is duplicated.", name))
90143
}
@@ -103,15 +156,15 @@ func (v awsCWScrapeJobNoDuplicateCustomNamespaceNamesValidator) MarkdownDescript
103156
}
104157

105158
func (v awsCWScrapeJobNoDuplicateCustomNamespaceNamesValidator) ValidateList(ctx context.Context, req validator.ListRequest, resp *validator.ListResponse) {
106-
seen := map[string]struct{}{}
107-
elems := make([]awsCWScrapeJobCustomNamespaceTFModel, len(req.ConfigValue.Elements()))
108-
diags := req.ConfigValue.ElementsAs(ctx, &elems, false)
159+
var customNamespaces []awsCWScrapeJobCustomNamespaceTFModel
160+
diags := req.ConfigValue.ElementsAs(ctx, &customNamespaces, true)
109161
resp.Diagnostics.Append(diags...)
110162
if diags.HasError() {
111163
return
112164
}
113-
for _, elem := range elems {
114-
name := elem.Name.ValueString()
165+
seen := map[string]struct{}{}
166+
for _, customNamespace := range customNamespaces {
167+
name := customNamespace.Name.ValueString()
115168
if _, ok := seen[name]; ok {
116169
resp.Diagnostics.AddError("Duplicate custom namespace name", fmt.Sprintf("Custom namespace name %q is duplicated.", name))
117170
}
@@ -162,8 +215,14 @@ func (tfData awsCWScrapeJobTFResourceModel) toClientModel(ctx context.Context) (
162215
return cloudproviderapi.AWSCloudWatchScrapeJobRequest{}, conversionDiags
163216
}
164217

165-
converted.Services = make([]cloudproviderapi.AWSCloudWatchService, len(tfData.Services))
166-
for i, service := range tfData.Services {
218+
var services []awsCWScrapeJobServiceTFModel
219+
diags = tfData.Services.ElementsAs(ctx, &services, false)
220+
conversionDiags.Append(diags...)
221+
if conversionDiags.HasError() {
222+
return cloudproviderapi.AWSCloudWatchScrapeJobRequest{}, conversionDiags
223+
}
224+
converted.Services = make([]cloudproviderapi.AWSCloudWatchService, len(services))
225+
for i, service := range services {
167226
converted.Services[i] = cloudproviderapi.AWSCloudWatchService{
168227
Name: service.Name.ValueString(),
169228
ScrapeIntervalSeconds: service.ScrapeIntervalSeconds.ValueInt64(),
@@ -175,8 +234,14 @@ func (tfData awsCWScrapeJobTFResourceModel) toClientModel(ctx context.Context) (
175234
return cloudproviderapi.AWSCloudWatchScrapeJobRequest{}, conversionDiags
176235
}
177236

178-
converted.Services[i].Metrics = make([]cloudproviderapi.AWSCloudWatchMetric, len(service.Metrics))
179-
for j, metric := range service.Metrics {
237+
var metrics []awsCWScrapeJobMetricTFModel
238+
diags = service.Metrics.ElementsAs(ctx, &metrics, false)
239+
conversionDiags.Append(diags...)
240+
if conversionDiags.HasError() {
241+
return cloudproviderapi.AWSCloudWatchScrapeJobRequest{}, conversionDiags
242+
}
243+
converted.Services[i].Metrics = make([]cloudproviderapi.AWSCloudWatchMetric, len(metrics))
244+
for j, metric := range metrics {
180245
converted.Services[i].Metrics[j] = cloudproviderapi.AWSCloudWatchMetric{
181246
Name: metric.Name.ValueString(),
182247
}
@@ -188,24 +253,42 @@ func (tfData awsCWScrapeJobTFResourceModel) toClientModel(ctx context.Context) (
188253
}
189254
}
190255

191-
converted.Services[i].ResourceDiscoveryTagFilters = make([]cloudproviderapi.AWSCloudWatchTagFilter, len(service.ResourceDiscoveryTagFilters))
192-
for j, tagFilter := range service.ResourceDiscoveryTagFilters {
256+
var tagFilters []awsCWScrapeJobTagFilterTFModel
257+
diags = service.ResourceDiscoveryTagFilters.ElementsAs(ctx, &tagFilters, false)
258+
conversionDiags.Append(diags...)
259+
if conversionDiags.HasError() {
260+
return cloudproviderapi.AWSCloudWatchScrapeJobRequest{}, conversionDiags
261+
}
262+
converted.Services[i].ResourceDiscoveryTagFilters = make([]cloudproviderapi.AWSCloudWatchTagFilter, len(tagFilters))
263+
for j, tagFilter := range tagFilters {
193264
converted.Services[i].ResourceDiscoveryTagFilters[j] = cloudproviderapi.AWSCloudWatchTagFilter{
194265
Key: tagFilter.Key.ValueString(),
195266
Value: tagFilter.Value.ValueString(),
196267
}
197268
}
198269
}
199270

200-
converted.CustomNamespaces = make([]cloudproviderapi.AWSCloudWatchCustomNamespace, len(tfData.CustomNamespaces))
201-
for i, customNamespace := range tfData.CustomNamespaces {
271+
var customNamepsaces []awsCWScrapeJobCustomNamespaceTFModel
272+
diags = tfData.CustomNamespaces.ElementsAs(ctx, &customNamepsaces, false)
273+
conversionDiags.Append(diags...)
274+
if conversionDiags.HasError() {
275+
return cloudproviderapi.AWSCloudWatchScrapeJobRequest{}, conversionDiags
276+
}
277+
converted.CustomNamespaces = make([]cloudproviderapi.AWSCloudWatchCustomNamespace, len(customNamepsaces))
278+
for i, customNamespace := range customNamepsaces {
202279
converted.CustomNamespaces[i] = cloudproviderapi.AWSCloudWatchCustomNamespace{
203280
Name: customNamespace.Name.ValueString(),
204281
ScrapeIntervalSeconds: customNamespace.ScrapeIntervalSeconds.ValueInt64(),
205282
}
206283

207-
converted.CustomNamespaces[i].Metrics = make([]cloudproviderapi.AWSCloudWatchMetric, len(customNamespace.Metrics))
208-
for j, metric := range customNamespace.Metrics {
284+
var metrics []awsCWScrapeJobMetricTFModel
285+
diags = customNamespace.Metrics.ElementsAs(ctx, &metrics, false)
286+
conversionDiags.Append(diags...)
287+
if conversionDiags.HasError() {
288+
return cloudproviderapi.AWSCloudWatchScrapeJobRequest{}, conversionDiags
289+
}
290+
converted.CustomNamespaces[i].Metrics = make([]cloudproviderapi.AWSCloudWatchMetric, len(metrics))
291+
for j, metric := range metrics {
209292
converted.CustomNamespaces[i].Metrics[j] = cloudproviderapi.AWSCloudWatchMetric{
210293
Name: metric.Name.ValueString(),
211294
}
@@ -301,80 +384,110 @@ func generateCloudWatchScrapeJobDataSourceTFModel(ctx context.Context, stackID s
301384
return converted, conversionDiags
302385
}
303386

304-
func convertServicesClientToTFModel(ctx context.Context, services []cloudproviderapi.AWSCloudWatchService) ([]awsCWScrapeJobServiceTFModel, diag.Diagnostics) {
387+
func convertServicesClientToTFModel(ctx context.Context, services []cloudproviderapi.AWSCloudWatchService) (types.List, diag.Diagnostics) {
305388
conversionDiags := diag.Diagnostics{}
306389
servicesTF := make([]awsCWScrapeJobServiceTFModel, len(services))
390+
servicesListObjType := types.ObjectType{AttrTypes: awsCWScrapeJobServiceTFModel{}.attrTypes()}
307391

308-
for i, serviceData := range services {
309-
service := awsCWScrapeJobServiceTFModel{
310-
Name: types.StringValue(serviceData.Name),
311-
ScrapeIntervalSeconds: types.Int64Value(serviceData.ScrapeIntervalSeconds),
392+
for i, service := range services {
393+
serviceTF := awsCWScrapeJobServiceTFModel{
394+
Name: types.StringValue(service.Name),
395+
ScrapeIntervalSeconds: types.Int64Value(service.ScrapeIntervalSeconds),
312396
}
313397

314-
metricsData := make([]awsCWScrapeJobMetricTFModel, len(serviceData.Metrics))
315-
for j, metricData := range serviceData.Metrics {
316-
metricsData[j] = awsCWScrapeJobMetricTFModel{
317-
Name: types.StringValue(metricData.Name),
398+
metricsTF := make([]awsCWScrapeJobMetricTFModel, len(service.Metrics))
399+
for j, metric := range service.Metrics {
400+
metricsTF[j] = awsCWScrapeJobMetricTFModel{
401+
Name: types.StringValue(metric.Name),
318402
}
319403
statistics, diags := types.SetValueFrom(ctx, basetypes.StringType{}, services[i].Metrics[j].Statistics)
320404
conversionDiags.Append(diags...)
321405
if conversionDiags.HasError() {
322-
return nil, conversionDiags
406+
return types.ListNull(servicesListObjType), conversionDiags
323407
}
324-
metricsData[j].Statistics = statistics
408+
metricsTF[j].Statistics = statistics
409+
}
410+
metricsTFList, diags := types.ListValueFrom(ctx, types.ObjectType{AttrTypes: awsCWScrapeJobMetricTFModel{}.attrTypes()}, metricsTF)
411+
conversionDiags.Append(diags...)
412+
if conversionDiags.HasError() {
413+
return types.ListNull(servicesListObjType), conversionDiags
325414
}
326-
service.Metrics = metricsData
415+
serviceTF.Metrics = metricsTFList
327416

328-
tagFiltersData := make([]awsCWScrapeJobTagFilterTFModel, len(serviceData.ResourceDiscoveryTagFilters))
329-
for j, tagFilterData := range serviceData.ResourceDiscoveryTagFilters {
330-
tagFiltersData[j] = awsCWScrapeJobTagFilterTFModel{
331-
Key: types.StringValue(tagFilterData.Key),
332-
Value: types.StringValue(tagFilterData.Value),
417+
tagFiltersTF := make([]awsCWScrapeJobTagFilterTFModel, len(service.ResourceDiscoveryTagFilters))
418+
for j, tagFilter := range service.ResourceDiscoveryTagFilters {
419+
tagFiltersTF[j] = awsCWScrapeJobTagFilterTFModel{
420+
Key: types.StringValue(tagFilter.Key),
421+
Value: types.StringValue(tagFilter.Value),
333422
}
334423
}
335-
service.ResourceDiscoveryTagFilters = tagFiltersData
424+
tagFiltersTFList, diags := types.ListValueFrom(ctx, types.ObjectType{AttrTypes: awsCWScrapeJobTagFilterTFModel{}.attrTypes()}, tagFiltersTF)
425+
conversionDiags.Append(diags...)
426+
if conversionDiags.HasError() {
427+
return types.ListNull(servicesListObjType), conversionDiags
428+
}
429+
serviceTF.ResourceDiscoveryTagFilters = tagFiltersTFList
336430

337431
tagsToAdd, diags := types.SetValueFrom(ctx, basetypes.StringType{}, services[i].TagsToAddToMetrics)
338432
if tagsToAdd.IsNull() {
339433
tagsToAdd = types.SetValueMust(basetypes.StringType{}, []attr.Value{})
340434
}
341435
conversionDiags.Append(diags...)
342436
if conversionDiags.HasError() {
343-
return nil, conversionDiags
437+
return types.ListNull(servicesListObjType), conversionDiags
344438
}
345-
service.TagsToAddToMetrics = tagsToAdd
346-
servicesTF[i] = service
439+
serviceTF.TagsToAddToMetrics = tagsToAdd
440+
441+
servicesTF[i] = serviceTF
442+
}
443+
444+
servicesTFList, diags := types.ListValueFrom(ctx, servicesListObjType, servicesTF)
445+
conversionDiags.Append(diags...)
446+
if conversionDiags.HasError() {
447+
return types.ListNull(servicesListObjType), conversionDiags
347448
}
348449

349-
return servicesTF, conversionDiags
450+
return servicesTFList, conversionDiags
350451
}
351452

352-
func convertCustomNamespacesClientToTFModel(ctx context.Context, customNamespaces []cloudproviderapi.AWSCloudWatchCustomNamespace) ([]awsCWScrapeJobCustomNamespaceTFModel, diag.Diagnostics) {
453+
func convertCustomNamespacesClientToTFModel(ctx context.Context, customNamespaces []cloudproviderapi.AWSCloudWatchCustomNamespace) (types.List, diag.Diagnostics) {
353454
conversionDiags := diag.Diagnostics{}
354455
customNamespacesTF := make([]awsCWScrapeJobCustomNamespaceTFModel, len(customNamespaces))
456+
customNamspacesListObjType := types.ObjectType{AttrTypes: awsCWScrapeJobCustomNamespaceTFModel{}.attrTypes()}
355457

356-
for i, customNamespaceData := range customNamespaces {
357-
customNamespace := awsCWScrapeJobCustomNamespaceTFModel{
358-
Name: types.StringValue(customNamespaceData.Name),
359-
ScrapeIntervalSeconds: types.Int64Value(customNamespaceData.ScrapeIntervalSeconds),
458+
for i, customNamespace := range customNamespaces {
459+
customNamespaceTF := awsCWScrapeJobCustomNamespaceTFModel{
460+
Name: types.StringValue(customNamespace.Name),
461+
ScrapeIntervalSeconds: types.Int64Value(customNamespace.ScrapeIntervalSeconds),
360462
}
361463

362-
metricsData := make([]awsCWScrapeJobMetricTFModel, len(customNamespaceData.Metrics))
363-
for j, metricData := range customNamespaceData.Metrics {
364-
metricsData[j] = awsCWScrapeJobMetricTFModel{
365-
Name: types.StringValue(metricData.Name),
464+
metricsTF := make([]awsCWScrapeJobMetricTFModel, len(customNamespace.Metrics))
465+
for j, metric := range customNamespace.Metrics {
466+
metricsTF[j] = awsCWScrapeJobMetricTFModel{
467+
Name: types.StringValue(metric.Name),
366468
}
367469
statistics, diags := types.SetValueFrom(ctx, basetypes.StringType{}, customNamespaces[i].Metrics[j].Statistics)
368470
conversionDiags.Append(diags...)
369471
if conversionDiags.HasError() {
370-
return nil, conversionDiags
472+
return types.ListNull(customNamspacesListObjType), conversionDiags
371473
}
372-
metricsData[j].Statistics = statistics
474+
metricsTF[j].Statistics = statistics
475+
}
476+
metricsTFList, diags := types.ListValueFrom(ctx, types.ObjectType{AttrTypes: awsCWScrapeJobMetricTFModel{}.attrTypes()}, metricsTF)
477+
conversionDiags.Append(diags...)
478+
if conversionDiags.HasError() {
479+
return types.ListNull(customNamspacesListObjType), conversionDiags
373480
}
374-
customNamespace.Metrics = metricsData
481+
customNamespaceTF.Metrics = metricsTFList
375482

376-
customNamespacesTF[i] = customNamespace
483+
customNamespacesTF[i] = customNamespaceTF
484+
}
485+
486+
customNamespacesTFList, diags := types.ListValueFrom(ctx, customNamspacesListObjType, customNamespacesTF)
487+
conversionDiags.Append(diags...)
488+
if conversionDiags.HasError() {
489+
return types.ListNull(customNamspacesListObjType), conversionDiags
377490
}
378491

379-
return customNamespacesTF, conversionDiags
492+
return customNamespacesTFList, conversionDiags
380493
}

0 commit comments

Comments
 (0)