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
105 changes: 104 additions & 1 deletion datadog/fwprovider/resource_datadog_monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,15 @@ type monitorResourceModel struct {
SchedulingOptions []SchedulingOption `tfsdk:"scheduling_options"`
Variables []Variable `tfsdk:"variables"`
DraftStatus types.String `tfsdk:"draft_status"`
MonitorAssets []MonitorAsset `tfsdk:"assets"`
}

type MonitorAsset struct {
Name types.String `tfsdk:"name"`
Url types.String `tfsdk:"url"`
Category types.String `tfsdk:"category"`
ResourceKey types.String `tfsdk:"resource_key"`
ResourceType types.String `tfsdk:"resource_type"`
}

type MonitorThreshold struct {
Expand Down Expand Up @@ -448,6 +457,39 @@ func (r *monitorResource) Schema(_ context.Context, _ resource.SchemaRequest, re
},
},
Blocks: map[string]schema.Block{
"assets": schema.ListNestedBlock{
Description: "List of monitor assets (e.g., runbooks, dashboards, workflows) tied to this monitor.",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
Required: true,
Description: "Name for the monitor asset.",
},
"url": schema.StringAttribute{
Required: true,
Description: "URL for the asset.",
},
"category": schema.StringAttribute{
Required: true,
Description: "Type of asset the entity represents on a monitor.",
Validators: []validator.String{
stringvalidator.OneOf(r.getAllowMonitorAssetCategory()...),
},
},
"resource_key": schema.StringAttribute{
Optional: true,
Description: "Identifier of the internal Datadog resource that this asset represents.",
},
"resource_type": schema.StringAttribute{
Optional: true,
Description: "Type of internal Datadog resource associated with a monitor asset.",
Validators: []validator.String{
stringvalidator.OneOf(r.getAllowMonitorAssetResourceType()...),
},
},
},
},
},
"monitor_thresholds": schema.ListNestedBlock{
Description: "Alert thresholds of the monitor.",
Validators: []validator.List{
Expand Down Expand Up @@ -765,7 +807,7 @@ func (r *monitorResource) Read(ctx context.Context, request resource.ReadRequest
if diags.HasError() {
return
}
resp, httpResp, err := r.Api.GetMonitor(r.Auth, *id)
resp, httpResp, err := r.Api.GetMonitor(r.Auth, *id, *datadogV1.NewGetMonitorOptionalParameters().WithWithAssets(true))
if err != nil {
if httpResp != nil && httpResp.StatusCode == 404 {
response.State.RemoveResource(ctx)
Expand Down Expand Up @@ -954,6 +996,12 @@ func (r *monitorResource) buildMonitorStruct(ctx context.Context, state *monitor
u.SetRestrictedRolesNil()
}

// Assets
if assets := r.buildAssetsStruct(ctx, state.MonitorAssets); len(assets) > 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: On API level, if client makes an Update Monitor request with assets not defined, does it removed all assets on the monitor or preserving existing assets?

m.SetAssets(assets)
u.SetAssets(assets)
}

monitorOptions := datadogV1.MonitorOptions{}
if !state.EscalationMessage.IsNull() {
escalationMessage := strings.TrimSpace(state.EscalationMessage.ValueString())
Expand Down Expand Up @@ -1162,6 +1210,25 @@ func (r *monitorResource) buildCloudCostQueryStruct(cloudCostQs []CloudCostQuery
return variablesReq
}

func (r *monitorResource) buildAssetsStruct(ctx context.Context, tfAssets []MonitorAsset) []datadogV1.MonitorAsset {
if len(tfAssets) == 0 {
return nil
}
assets := make([]datadogV1.MonitorAsset, 0, len(tfAssets))
for _, a := range tfAssets {
category := datadogV1.MonitorAssetCategory(a.Category.ValueString())
asset := datadogV1.NewMonitorAsset(category, a.Name.ValueString(), a.Url.ValueString())
if !a.ResourceKey.IsNull() {
asset.SetResourceKey(a.ResourceKey.ValueString())
}
if !a.ResourceType.IsNull() {
asset.SetResourceType(datadogV1.MonitorAssetResourceType(a.ResourceType.ValueString()))
}
assets = append(assets, *asset)
}
return assets
}

func (r *monitorResource) updateState(ctx context.Context, state *monitorResourceModel, m *datadogV1.Monitor) {
if id, ok := m.GetIdOk(); ok && id != nil {
state.ID = types.StringValue(strconv.FormatInt(*id, 10))
Expand Down Expand Up @@ -1232,6 +1299,8 @@ func (r *monitorResource) updateState(ctx context.Context, state *monitorResourc
state.EnableLogsSample = fwutils.ToTerraformBool(m.Options.GetEnableLogsSampleOk())
state.Locked = fwutils.ToTerraformBool(m.Options.GetLockedOk())

r.updateAssetsState(ctx, state, m)

if monitorThresholds, ok := m.Options.GetThresholdsOk(); ok && monitorThresholds != nil {
state.MonitorThresholds = []MonitorThreshold{{
Ok: r.buildFloatStringValue(fwutils.ToTerraformStr(monitorThresholds.GetOkOk())),
Expand All @@ -1252,6 +1321,32 @@ func (r *monitorResource) updateState(ctx context.Context, state *monitorResourc
r.updateVariablesState(ctx, state, m.Options)
}

func (r *monitorResource) updateAssetsState(ctx context.Context, state *monitorResourceModel, m *datadogV1.Monitor) {
// Assets -> state
if assets, ok := m.GetAssetsOk(); ok && assets != nil {
tfAssets := make([]MonitorAsset, 0, len(*assets))
for _, a := range *assets {
tfAsset := MonitorAsset{
Name: fwutils.ToTerraformStr(a.GetNameOk()),
Url: fwutils.ToTerraformStr(a.GetUrlOk()),
Category: types.StringValue(string(a.GetCategory())),
}
if rk, ok := a.GetResourceKeyOk(); ok && rk != nil {
tfAsset.ResourceKey = types.StringValue(*rk)
} else {
tfAsset.ResourceKey = types.StringNull()
}
if rt, ok := a.GetResourceTypeOk(); ok && rt != nil {
tfAsset.ResourceType = types.StringValue(string(*rt))
} else {
tfAsset.ResourceType = types.StringNull()
}
tfAssets = append(tfAssets, tfAsset)
}
state.MonitorAssets = tfAssets
}
}

func (r *monitorResource) updateSchedulingOptionState(state *monitorResourceModel, mOptions *datadogV1.MonitorOptions) {
schedulingOptions, ok := mOptions.GetSchedulingOptionsOk()
if !ok || schedulingOptions == nil {
Expand Down Expand Up @@ -1416,6 +1511,14 @@ func (r *monitorResource) getAllowCloudCostAggregator() []string {
return enumStrings((*datadogV1.MonitorFormulaAndFunctionCostAggregator)(nil).GetAllowedValues())
}

func (r *monitorResource) getAllowMonitorAssetCategory() []string {
return enumStrings((*datadogV1.MonitorAssetCategory)(nil).GetAllowedValues())
}

func (r *monitorResource) getAllowMonitorAssetResourceType() []string {
return enumStrings((*datadogV1.MonitorAssetResourceType)(nil).GetAllowedValues())
}

func (r *monitorResource) parseInt(v types.String) *int64 {
if v.IsNull() || v.IsUnknown() {
return nil
Expand Down
104 changes: 103 additions & 1 deletion datadog/resource_datadog_monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,42 @@
Default: string(datadogV1.MONITORDRAFTSTATUS_PUBLISHED),
ValidateDiagFunc: validators.ValidateEnumValue(datadogV1.NewMonitorDraftStatusFromValue),
},
"assets": {
Description: "List of monitor assets (for example, runbooks, dashboards, workflows) tied to this monitor.",
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Description: "Name for the monitor asset.",
Type: schema.TypeString,
Required: true,
},
"url": {
Description: "URL for the asset.",
Type: schema.TypeString,
Required: true,
},
"category": {
Description: "Type of asset the entity represents on a monitor.",
Type: schema.TypeString,
Required: true,
ValidateDiagFunc: validators.ValidateEnumValue(datadogV1.NewMonitorAssetCategoryFromValue),

Check failure on line 457 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / linter-checks

undefined: datadogV1.NewMonitorAssetCategoryFromValue

Check failure on line 457 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.15.5, ubuntu-latest)

undefined: datadogV1.NewMonitorAssetCategoryFromValue

Check failure on line 457 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (1.13.1, ubuntu-latest)

undefined: datadogV1.NewMonitorAssetCategoryFromValue

Check failure on line 457 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.14.11, ubuntu-latest)

undefined: datadogV1.NewMonitorAssetCategoryFromValue

Check failure on line 457 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test-tofu

undefined: datadogV1.NewMonitorAssetCategoryFromValue
},
"resource_key": {
Description: "Identifier of the internal Datadog resource that this asset represents.",
Type: schema.TypeString,
Optional: true,
},
"resource_type": {
Description: "Type of internal Datadog resource associated with a monitor asset.",
Type: schema.TypeString,
Optional: true,
ValidateDiagFunc: validators.ValidateEnumValue(datadogV1.NewMonitorAssetResourceTypeFromValue),

Check failure on line 468 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / linter-checks

undefined: datadogV1.NewMonitorAssetResourceTypeFromValue

Check failure on line 468 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.15.5, ubuntu-latest)

undefined: datadogV1.NewMonitorAssetResourceTypeFromValue

Check failure on line 468 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (1.13.1, ubuntu-latest)

undefined: datadogV1.NewMonitorAssetResourceTypeFromValue

Check failure on line 468 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.14.11, ubuntu-latest)

undefined: datadogV1.NewMonitorAssetResourceTypeFromValue

Check failure on line 468 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test-tofu

undefined: datadogV1.NewMonitorAssetResourceTypeFromValue
},
},
},
},
}
},
}
Expand Down Expand Up @@ -858,6 +894,16 @@
m.SetTags(tags)
u.SetTags(tags)

// Assets
if attr, ok := d.GetOk("assets"); ok {
tfAssets := attr.([]interface{})
assets := buildMonitorAssets(tfAssets)
if len(assets) > 0 {
m.SetAssets(assets)

Check failure on line 902 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / linter-checks

m.SetAssets undefined (type *datadogV1.Monitor has no field or method SetAssets)

Check failure on line 902 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.15.5, ubuntu-latest)

m.SetAssets undefined (type *datadogV1.Monitor has no field or method SetAssets)

Check failure on line 902 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (1.13.1, ubuntu-latest)

m.SetAssets undefined (type *datadogV1.Monitor has no field or method SetAssets)

Check failure on line 902 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.14.11, ubuntu-latest)

m.SetAssets undefined (type *datadogV1.Monitor has no field or method SetAssets)

Check failure on line 902 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test-tofu

m.SetAssets undefined (type *datadogV1.Monitor has no field or method SetAssets)
u.SetAssets(assets)

Check failure on line 903 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / linter-checks

u.SetAssets undefined (type *datadogV1.MonitorUpdateRequest has no field or method SetAssets)

Check failure on line 903 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.15.5, ubuntu-latest)

u.SetAssets undefined (type *datadogV1.MonitorUpdateRequest has no field or method SetAssets)

Check failure on line 903 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (1.13.1, ubuntu-latest)

u.SetAssets undefined (type *datadogV1.MonitorUpdateRequest has no field or method SetAssets)

Check failure on line 903 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.14.11, ubuntu-latest)

u.SetAssets undefined (type *datadogV1.MonitorUpdateRequest has no field or method SetAssets)

Check failure on line 903 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test-tofu

u.SetAssets undefined (type *datadogV1.MonitorUpdateRequest has no field or method SetAssets)
}
}

return m, u
}

Expand Down Expand Up @@ -1236,6 +1282,14 @@
return diag.FromErr(err)
}

// Assets -> state
if assets, ok := m.GetAssetsOk(); ok && assets != nil {

Check failure on line 1286 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / linter-checks

m.GetAssetsOk undefined (type *datadogV1.Monitor has no field or method GetAssetsOk)

Check failure on line 1286 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.15.5, ubuntu-latest)

m.GetAssetsOk undefined (type *datadogV1.Monitor has no field or method GetAssetsOk)

Check failure on line 1286 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (1.13.1, ubuntu-latest)

m.GetAssetsOk undefined (type *datadogV1.Monitor has no field or method GetAssetsOk)

Check failure on line 1286 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.14.11, ubuntu-latest)

m.GetAssetsOk undefined (type *datadogV1.Monitor has no field or method GetAssetsOk)

Check failure on line 1286 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test-tofu

m.GetAssetsOk undefined (type *datadogV1.Monitor has no field or method GetAssetsOk)
terraformAssets := buildTerraformMonitorAssets(*assets)
if err := d.Set("assets", terraformAssets); err != nil {
return diag.FromErr(err)
}
}

return nil
}

Expand Down Expand Up @@ -1355,7 +1409,7 @@
httpresp *http.Response
)
if err = retry.RetryContext(ctx, d.Timeout(schema.TimeoutRead), func() *retry.RetryError {
m, httpresp, err = apiInstances.GetMonitorsApiV1().GetMonitor(auth, i)
m, httpresp, err = apiInstances.GetMonitorsApiV1().GetMonitor(auth, i, *datadogV1.NewGetMonitorOptionalParameters().WithWithAssets(true))

Check failure on line 1412 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / linter-checks

datadogV1.NewGetMonitorOptionalParameters().WithWithAssets undefined (type *datadogV1.GetMonitorOptionalParameters has no field or method WithWithAssets)

Check failure on line 1412 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.15.5, ubuntu-latest)

datadogV1.NewGetMonitorOptionalParameters().WithWithAssets undefined (type *datadogV1.GetMonitorOptionalParameters has no field or method WithWithAssets)

Check failure on line 1412 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (1.13.1, ubuntu-latest)

datadogV1.NewGetMonitorOptionalParameters().WithWithAssets undefined (type *datadogV1.GetMonitorOptionalParameters has no field or method WithWithAssets)

Check failure on line 1412 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.14.11, ubuntu-latest)

datadogV1.NewGetMonitorOptionalParameters().WithWithAssets undefined (type *datadogV1.GetMonitorOptionalParameters has no field or method WithWithAssets)

Check failure on line 1412 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test-tofu

datadogV1.NewGetMonitorOptionalParameters().WithWithAssets undefined (type *datadogV1.GetMonitorOptionalParameters has no field or method WithWithAssets)
if err != nil {
if httpresp != nil {
if httpresp.StatusCode == 404 {
Expand Down Expand Up @@ -1461,3 +1515,51 @@
}
return fallback
}

// buildMonitorAssets converts Terraform assets into API MonitorAsset slice.
func buildMonitorAssets(tfAssets []interface{}) []datadogV1.MonitorAsset {

Check failure on line 1520 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / linter-checks

undefined: datadogV1.MonitorAsset

Check failure on line 1520 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.15.5, ubuntu-latest)

undefined: datadogV1.MonitorAsset

Check failure on line 1520 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (1.13.1, ubuntu-latest)

undefined: datadogV1.MonitorAsset

Check failure on line 1520 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.14.11, ubuntu-latest)

undefined: datadogV1.MonitorAsset

Check failure on line 1520 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test-tofu

undefined: datadogV1.MonitorAsset
if len(tfAssets) == 0 {
return nil
}
assets := make([]datadogV1.MonitorAsset, 0, len(tfAssets))

Check failure on line 1524 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / linter-checks

undefined: datadogV1.MonitorAsset

Check failure on line 1524 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.15.5, ubuntu-latest)

undefined: datadogV1.MonitorAsset

Check failure on line 1524 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (1.13.1, ubuntu-latest)

undefined: datadogV1.MonitorAsset

Check failure on line 1524 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.14.11, ubuntu-latest)

undefined: datadogV1.MonitorAsset

Check failure on line 1524 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test-tofu

undefined: datadogV1.MonitorAsset
for _, raw := range tfAssets {
aMap, ok := raw.(map[string]interface{})
if !ok {
continue
}
categoryStr, _ := aMap["category"].(string)
nameStr, _ := aMap["name"].(string)
urlStr, _ := aMap["url"].(string)
category := datadogV1.MonitorAssetCategory(categoryStr)

Check failure on line 1533 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / linter-checks

undefined: datadogV1.MonitorAssetCategory

Check failure on line 1533 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.15.5, ubuntu-latest)

undefined: datadogV1.MonitorAssetCategory

Check failure on line 1533 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (1.13.1, ubuntu-latest)

undefined: datadogV1.MonitorAssetCategory

Check failure on line 1533 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.14.11, ubuntu-latest)

undefined: datadogV1.MonitorAssetCategory

Check failure on line 1533 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test-tofu

undefined: datadogV1.MonitorAssetCategory
asset := datadogV1.NewMonitorAsset(category, nameStr, urlStr)
if rk, ok := aMap["resource_key"].(string); ok && rk != "" {
asset.SetResourceKey(rk)
}
if rt, ok := aMap["resource_type"].(string); ok && rt != "" {
rtEnum := datadogV1.MonitorAssetResourceType(rt)
asset.SetResourceType(rtEnum)
}
assets = append(assets, *asset)
}
return assets
}

// buildTerraformMonitorAssets flattens API assets into Terraform state shape.
func buildTerraformMonitorAssets(apiAssets []datadogV1.MonitorAsset) []map[string]interface{} {

Check failure on line 1548 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / linter-checks

undefined: datadogV1.MonitorAsset

Check failure on line 1548 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.15.5, ubuntu-latest)

undefined: datadogV1.MonitorAsset

Check failure on line 1548 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (1.13.1, ubuntu-latest)

undefined: datadogV1.MonitorAsset

Check failure on line 1548 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test (0.14.11, ubuntu-latest)

undefined: datadogV1.MonitorAsset

Check failure on line 1548 in datadog/resource_datadog_monitor.go

View workflow job for this annotation

GitHub Actions / test-tofu

undefined: datadogV1.MonitorAsset
tfAssets := make([]map[string]interface{}, 0, len(apiAssets))
for _, a := range apiAssets {
tf := map[string]interface{}{
"name": a.GetName(),
"url": a.GetUrl(),
"category": string(a.GetCategory()),
}
if rk, ok := a.GetResourceKeyOk(); ok && rk != nil {
tf["resource_key"] = *rk
}
if rt, ok := a.GetResourceTypeOk(); ok && rt != nil {
tf["resource_type"] = string(*rt)
}
tfAssets = append(tfAssets, tf)
}
return tfAssets
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2025-12-02T15:10:39.184264-05:00
Loading
Loading