Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
458 changes: 458 additions & 0 deletions datadog/fwprovider/data_source_datadog_reference_table.go

Large diffs are not rendered by default.

165 changes: 165 additions & 0 deletions datadog/fwprovider/data_source_datadog_reference_table_rows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package fwprovider

import (
"context"
"fmt"
"net/http"
"time"

"github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"

"github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils"
)

var (
_ datasource.DataSource = &datadogReferenceTableRowsDataSource{}
)

type datadogReferenceTableRowsDataSource struct {
Api *datadogV2.ReferenceTablesApi
Auth context.Context
}

type datadogReferenceTableRowsDataSourceModel struct {
// Query Parameters
TableId types.String `tfsdk:"table_id"`
RowIds types.List `tfsdk:"row_ids"`

// Computed values (list of rows)
Rows []*rowModel `tfsdk:"rows"`
}

type rowModel struct {
Id types.String `tfsdk:"id"`
Values types.Map `tfsdk:"values"`
}

func NewDatadogReferenceTableRowsDataSource() datasource.DataSource {
return &datadogReferenceTableRowsDataSource{}
}

func (d *datadogReferenceTableRowsDataSource) Configure(_ context.Context, request datasource.ConfigureRequest, response *datasource.ConfigureResponse) {
providerData, _ := request.ProviderData.(*FrameworkProvider)
d.Api = providerData.DatadogApiInstances.GetReferenceTablesApiV2()
d.Auth = providerData.Auth
}

func (d *datadogReferenceTableRowsDataSource) Metadata(_ context.Context, request datasource.MetadataRequest, response *datasource.MetadataResponse) {
response.TypeName = "reference_table_rows"
}

func (d *datadogReferenceTableRowsDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, response *datasource.SchemaResponse) {
response.Schema = schema.Schema{
Description: "Use this data source to retrieve specific rows from a Datadog reference table by their primary key values. Works with all reference table source types.",
Attributes: map[string]schema.Attribute{
"table_id": schema.StringAttribute{
Required: true,
Description: "The UUID of the reference table to query rows from.",
},
"row_ids": schema.ListAttribute{
Required: true,
Description: "List of primary key values (row IDs) to retrieve. These are the values of the table's primary key field(s).",
ElementType: types.StringType,
},
},
Blocks: map[string]schema.Block{
"rows": schema.ListNestedBlock{
Description: "List of retrieved rows. Each row contains its ID and field values.",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
Description: "The primary key value of the row.",
},
"values": schema.MapAttribute{
Computed: true,
Description: "Map of field names to values for this row. All values are returned as strings.",
ElementType: types.StringType,
},
},
},
},
},
}
}

func (d *datadogReferenceTableRowsDataSource) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) {
var state datadogReferenceTableRowsDataSourceModel
response.Diagnostics.Append(request.Config.Get(ctx, &state)...)
if response.Diagnostics.HasError() {
return
}

tableId := state.TableId.ValueString()

// Extract row IDs from the list
var rowIds []string
response.Diagnostics.Append(state.RowIds.ElementsAs(ctx, &rowIds, false)...)
if response.Diagnostics.HasError() {
return
}

// Call API to get rows by ID with retry logic
// Rows are written asynchronously, so we need to retry if the table hasn't synced yet
// Use a 5-second interval to avoid spamming the API while waiting for sync
var ddResp datadogV2.TableRowResourceArray
var httpResp *http.Response
var err error

retryErr := utils.Retry(5*time.Second, 10, func() error {
ddResp, httpResp, err = d.Api.GetRowsByID(d.Auth, tableId, rowIds)
if err != nil {
// If we get a 404, the table might not have synced yet - retry
if httpResp != nil && httpResp.StatusCode == 404 {
return &utils.RetryableError{Prob: fmt.Sprintf("rows not found (table may not have synced yet): %v", err)}
}
// For other errors, don't retry
return &utils.FatalError{Prob: fmt.Sprintf("error getting reference table rows: %v", err)}
}
// Success - check if we got the expected number of rows
if len(ddResp.Data) == len(rowIds) {
return nil
}
// If we got some rows but not all, the table might still be syncing - retry
if len(ddResp.Data) > 0 && len(ddResp.Data) < len(rowIds) {
return &utils.RetryableError{Prob: fmt.Sprintf("only %d of %d rows found (table may still be syncing)", len(ddResp.Data), len(rowIds))}
}
// If we got no rows, retry
return &utils.RetryableError{Prob: "no rows found (table may not have synced yet)"}
})

if retryErr != nil {
response.Diagnostics.Append(utils.FrameworkErrorDiag(retryErr, "error getting reference table rows"))
return
}

// Convert API response to state
state.Rows = make([]*rowModel, len(ddResp.Data))
for i, row := range ddResp.Data {
rowTf := &rowModel{
Id: types.StringValue(row.GetId()),
}

// Convert values map to types.Map with string values
if attrs, ok := row.GetAttributesOk(); ok && attrs.Values != nil {
// Type assert Values to map[string]interface{}
if valuesMap, ok := attrs.Values.(map[string]interface{}); ok {
// Convert all values to strings for the map
stringValues := make(map[string]string)
for k, v := range valuesMap {
// Convert value to string representation
stringValues[k] = fmt.Sprintf("%v", v)
}
rowTf.Values, _ = types.MapValueFrom(ctx, types.StringType, stringValues)
}
}

state.Rows[i] = rowTf
}

// Save data into Terraform state
response.Diagnostics.Append(response.State.Set(ctx, &state)...)
}
3 changes: 3 additions & 0 deletions datadog/fwprovider/framework_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ var Resources = []func() resource.Resource{
NewDatadogCustomAllocationRuleResource,
NewCustomAllocationRulesResource,
NewAzureUcConfigResource,
NewReferenceTableResource,
}

var Datasources = []func() datasource.DataSource{
Expand Down Expand Up @@ -154,6 +155,8 @@ var Datasources = []func() datasource.DataSource{
NewDatadogGcpUcConfigDataSource,
NewDatadogCustomAllocationRuleDataSource,
NewDatadogAzureUcConfigDataSource,
NewDatadogReferenceTableDataSource,
NewDatadogReferenceTableRowsDataSource,
}

// FrameworkProvider struct
Expand Down
44 changes: 44 additions & 0 deletions datadog/fwprovider/models_reference_table.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package fwprovider

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

// Shared model definitions for reference table resource and data sources

type schemaModel struct {
PrimaryKeys types.List `tfsdk:"primary_keys"`
Fields []*fieldsModel `tfsdk:"fields"`
}

type fieldsModel struct {
Name types.String `tfsdk:"name"`
Type types.String `tfsdk:"type"`
}

type accessDetailsModel struct {
AwsDetail *awsDetailModel `tfsdk:"aws_detail"`
AzureDetail *azureDetailModel `tfsdk:"azure_detail"`
GcpDetail *gcpDetailModel `tfsdk:"gcp_detail"`
}

type awsDetailModel struct {
AwsAccountId types.String `tfsdk:"aws_account_id"`
AwsBucketName types.String `tfsdk:"aws_bucket_name"`
FilePath types.String `tfsdk:"file_path"`
}

type azureDetailModel struct {
AzureTenantId types.String `tfsdk:"azure_tenant_id"`
AzureClientId types.String `tfsdk:"azure_client_id"`
AzureStorageAccountName types.String `tfsdk:"azure_storage_account_name"`
AzureContainerName types.String `tfsdk:"azure_container_name"`
FilePath types.String `tfsdk:"file_path"`
}

type gcpDetailModel struct {
GcpProjectId types.String `tfsdk:"gcp_project_id"`
GcpBucketName types.String `tfsdk:"gcp_bucket_name"`
FilePath types.String `tfsdk:"file_path"`
GcpServiceAccountEmail types.String `tfsdk:"gcp_service_account_email"`
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"

"github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils"
)

Expand Down
Loading