Skip to content
Merged
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
- Migrate `elasticstack_kibana_action_connector` to the Terraform plugin framework ([#1269](https://github.com/elastic/terraform-provider-elasticstack/pull/1269))
- Migrate `elasticstack_elasticsearch_security_role_mapping` resource and data source to Terraform Plugin Framework ([#1279](https://github.com/elastic/terraform-provider-elasticstack/pull/1279))
- Add support for `inactivity_timeout` in `elasticstack_fleet_agent_policy` ([#641](https://github.com/elastic/terraform-provider-elasticstack/issues/641))
- [Refactor] Regenerate the SLO client using the current OpenAPI spec ([#1303](https://github.com/elastic/terraform-provider-elasticstack/pull/1303))
- Add support for `data_view_id` in the `elasticstack_kibana_slo` resource ([#1305](https://github.com/elastic/terraform-provider-elasticstack/pull/1305))
- Add support for `unenrollment_timeout` in `elasticstack_fleet_agent_policy` ([#1169](https://github.com/elastic/terraform-provider-elasticstack/issues/1169))

## [0.11.17] - 2025-07-21
Expand Down
4 changes: 4 additions & 0 deletions docs/resources/kibana_slo.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ Required:

Optional:

- `data_view_id` (String) Optional data view id to use for this indicator.
- `filter` (String)
- `timestamp_field` (String)

Expand Down Expand Up @@ -366,6 +367,7 @@ Required:

Optional:

- `data_view_id` (String) Optional data view id to use for this indicator.
- `filter` (String)
- `good` (String)
- `timestamp_field` (String)
Expand All @@ -383,6 +385,7 @@ Required:

Optional:

- `data_view_id` (String) Optional data view id to use for this indicator.
- `filter` (String)
- `timestamp_field` (String)

Expand Down Expand Up @@ -453,6 +456,7 @@ Required:

Optional:

- `data_view_id` (String) Optional data view id to use for this indicator.
- `filter` (String)

<a id="nestedblock--timeslice_metric_indicator--metric"></a>
Expand Down
16 changes: 12 additions & 4 deletions internal/clients/kibana/slo.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ func GetSlo(ctx context.Context, apiClient *clients.ApiClient, id, spaceID strin
return nil, nil
}
if err != nil {
return nil, diag.FromErr(err)
diags := diag.FromErr(err)
diags = append(diags, utils.CheckHttpError(res, "unable to create slo with id "+id)...)
return nil, diags
}

defer res.Body.Close()
Expand All @@ -46,7 +48,9 @@ func DeleteSlo(ctx context.Context, apiClient *clients.ApiClient, sloId string,
req := client.DeleteSloOp(ctxWithAuth, sloId, spaceId).KbnXsrf("true")
res, err := req.Execute()
if err != nil && res == nil {
return diag.FromErr(err)
diags := diag.FromErr(err)
diags = append(diags, utils.CheckHttpError(res, "unable to create slo with id "+sloId)...)
return diags
}

defer res.Body.Close()
Expand Down Expand Up @@ -80,7 +84,9 @@ func UpdateSlo(ctx context.Context, apiClient *clients.ApiClient, s models.Slo,
_, res, err := req.Execute()

if err != nil {
return nil, diag.FromErr(err)
diags := diag.FromErr(err)
diags = append(diags, utils.CheckHttpError(res, "unable to create slo with id "+s.SloID)...)
return nil, diags
}

defer res.Body.Close()
Expand Down Expand Up @@ -122,7 +128,9 @@ func CreateSlo(ctx context.Context, apiClient *clients.ApiClient, s models.Slo,
req := client.CreateSloOp(ctxWithAuth, s.SpaceID).KbnXsrf("true").CreateSloRequest(reqModel)
sloRes, res, err := req.Execute()
if err != nil {
return nil, diag.FromErr(err)
diags := diag.FromErr(err)
diags = append(diags, utils.CheckHttpError(res, "unable to create slo with id "+s.SloID)...)
return nil, diags
}
defer res.Body.Close()

Expand Down
82 changes: 72 additions & 10 deletions internal/kibana/slo.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

var SLOSupportsMultipleGroupByMinVersion = version.Must(version.NewVersion("8.14.0"))
var (
SLOSupportsMultipleGroupByMinVersion = version.Must(version.NewVersion("8.14.0"))
SLOSupportsDataViewIDMinVersion = version.Must(version.NewVersion("8.15.0"))
)

func ResourceSlo() *schema.Resource {
return &schema.Resource{
Expand Down Expand Up @@ -114,6 +117,11 @@ func getSchema() map[string]*schema.Schema {
Type: schema.TypeString,
Required: true,
},
"data_view_id": {
Type: schema.TypeString,
Optional: true,
Description: "Optional data view id to use for this indicator.",
},
"filter": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -215,6 +223,11 @@ func getSchema() map[string]*schema.Schema {
Type: schema.TypeString,
Required: true,
},
"data_view_id": {
Type: schema.TypeString,
Optional: true,
Description: "Optional data view id to use for this indicator.",
},
"filter": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -375,6 +388,11 @@ func getSchema() map[string]*schema.Schema {
Type: schema.TypeString,
Required: true,
},
"data_view_id": {
Type: schema.TypeString,
Optional: true,
Description: "Optional data view id to use for this indicator.",
},
"filter": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -408,6 +426,11 @@ func getSchema() map[string]*schema.Schema {
Type: schema.TypeString,
Required: true,
},
"data_view_id": {
Type: schema.TypeString,
Optional: true,
Description: "Optional data view id to use for this indicator.",
},
"timestamp_field": {
Type: schema.TypeString,
Required: true,
Expand Down Expand Up @@ -609,7 +632,8 @@ func getSloFromResourceData(d *schema.ResourceData) (models.Slo, diag.Diagnostic
IndicatorPropertiesCustomKql: &slo.IndicatorPropertiesCustomKql{
Type: indicatorAddressToType[indicatorType],
Params: slo.IndicatorPropertiesCustomKqlParams{
Index: d.Get(indicatorType + ".0.index").(string),
Index: d.Get(indicatorType + ".0.index").(string),
DataViewId: getOrNil[string](indicatorType+".0.data_view_id", d),
Filter: transformOrNil[slo.KqlWithFilters](
indicatorType+".0.filter", d,
func(v interface{}) slo.KqlWithFilters {
Expand Down Expand Up @@ -666,6 +690,7 @@ func getSloFromResourceData(d *schema.ResourceData) (models.Slo, diag.Diagnostic
Params: slo.IndicatorPropertiesHistogramParams{
Filter: getOrNil[string](indicatorType+".0.filter", d),
Index: d.Get(indicatorType + ".0.index").(string),
DataViewId: getOrNil[string](indicatorType+".0.data_view_id", d),
TimestampField: d.Get(indicatorType + ".0.timestamp_field").(string),
Good: slo.IndicatorPropertiesHistogramParamsGood{
Field: d.Get(indicatorType + ".0.good.0.field").(string),
Expand Down Expand Up @@ -714,6 +739,7 @@ func getSloFromResourceData(d *schema.ResourceData) (models.Slo, diag.Diagnostic
Params: slo.IndicatorPropertiesCustomMetricParams{
Filter: getOrNil[string](indicatorType+".0.filter", d),
Index: d.Get(indicatorType + ".0.index").(string),
DataViewId: getOrNil[string](indicatorType+".0.data_view_id", d),
TimestampField: d.Get(indicatorType + ".0.timestamp_field").(string),
Good: slo.IndicatorPropertiesCustomMetricParamsGood{
Equation: d.Get(indicatorType + ".0.good.0.equation").(string),
Expand Down Expand Up @@ -769,6 +795,7 @@ func getSloFromResourceData(d *schema.ResourceData) (models.Slo, diag.Diagnostic
Type: indicatorAddressToType[indicatorType],
Params: slo.IndicatorPropertiesTimesliceMetricParams{
Index: params["index"].(string),
DataViewId: getOrNil[string]("timeslice_metric_indicator.0.data_view_id", d),
TimestampField: params["timestamp_field"].(string),
Filter: getOrNil[string]("timeslice_metric_indicator.0.filter", d),
Metric: slo.IndicatorPropertiesTimesliceMetricParamsMetric{
Expand Down Expand Up @@ -850,6 +877,16 @@ func resourceSloCreate(ctx context.Context, d *schema.ResourceData, meta interfa
return diags
}

// Version check for data_view_id support
if !serverVersion.GreaterThanOrEqual(SLOSupportsDataViewIDMinVersion) {
// Check all indicator types that support data_view_id
for _, indicatorType := range []string{"metric_custom_indicator", "histogram_custom_indicator", "kql_custom_indicator", "timeslice_metric_indicator"} {
if v, ok := d.GetOk(indicatorType + ".0.data_view_id"); ok && v != "" {
return diag.Errorf("data_view_id is not supported for %s on Elastic Stack versions < %s", indicatorType, SLOSupportsDataViewIDMinVersion)
}
}
}

supportsMultipleGroupBy := serverVersion.GreaterThanOrEqual(SLOSupportsMultipleGroupByMinVersion)
if len(slo.GroupBy) > 1 && !supportsMultipleGroupBy {
return diag.Errorf("multiple group_by fields are not supported in this version of the Elastic Stack. Multiple group_by fields requires %s", SLOSupportsMultipleGroupByMinVersion)
Expand Down Expand Up @@ -882,6 +919,15 @@ func resourceSloUpdate(ctx context.Context, d *schema.ResourceData, meta interfa
return diags
}

// Version check for data_view_id support
if !serverVersion.GreaterThanOrEqual(SLOSupportsDataViewIDMinVersion) {
for _, indicatorType := range []string{"metric_custom_indicator", "histogram_custom_indicator", "kql_custom_indicator", "timeslice_metric_indicator"} {
if v, ok := d.GetOk(indicatorType + ".0.data_view_id"); ok && v != "" {
return diag.Errorf("data_view_id is not supported for %s on Elastic Stack versions < %s", indicatorType, SLOSupportsDataViewIDMinVersion)
}
}
}

supportsMultipleGroupBy := serverVersion.GreaterThanOrEqual(SLOSupportsMultipleGroupByMinVersion)
if len(slo.GroupBy) > 1 && !supportsMultipleGroupBy {
return diag.Errorf("multiple group_by fields are not supported in this version of the Elastic Stack. Multiple group_by fields requires %s", SLOSupportsMultipleGroupByMinVersion)
Expand Down Expand Up @@ -950,13 +996,17 @@ func resourceSloRead(ctx context.Context, d *schema.ResourceData, meta interface
case s.Indicator.IndicatorPropertiesCustomKql != nil:
indicatorAddress = indicatorTypeToAddress[s.Indicator.IndicatorPropertiesCustomKql.Type]
params := s.Indicator.IndicatorPropertiesCustomKql.Params
indicator = append(indicator, map[string]interface{}{
indicatorMap := map[string]interface{}{
"index": params.Index,
"filter": params.Filter.String,
"good": params.Good.String,
"total": params.Total.String,
"timestamp_field": params.TimestampField,
})
}
if params.DataViewId != nil {
indicatorMap["data_view_id"] = *params.DataViewId
}
indicator = append(indicator, indicatorMap)

case s.Indicator.IndicatorPropertiesHistogram != nil:
indicatorAddress = indicatorTypeToAddress[s.Indicator.IndicatorPropertiesHistogram.Type]
Expand All @@ -975,13 +1025,17 @@ func resourceSloRead(ctx context.Context, d *schema.ResourceData, meta interface
"from": params.Total.From,
"to": params.Total.To,
}}
indicator = append(indicator, map[string]interface{}{
indicatorMap := map[string]interface{}{
"index": params.Index,
"filter": params.Filter,
"timestamp_field": params.TimestampField,
"good": good,
"total": total,
})
}
if params.DataViewId != nil {
indicatorMap["data_view_id"] = *params.DataViewId
}
indicator = append(indicator, indicatorMap)

case s.Indicator.IndicatorPropertiesCustomMetric != nil:
indicatorAddress = indicatorTypeToAddress[s.Indicator.IndicatorPropertiesCustomMetric.Type]
Expand Down Expand Up @@ -1012,13 +1066,17 @@ func resourceSloRead(ctx context.Context, d *schema.ResourceData, meta interface
"equation": params.Total.Equation,
"metrics": totalMetrics,
}}
indicator = append(indicator, map[string]interface{}{
indicatorMap := map[string]interface{}{
"index": params.Index,
"filter": params.Filter,
"timestamp_field": params.TimestampField,
"good": good,
"total": total,
})
}
if params.DataViewId != nil {
indicatorMap["data_view_id"] = *params.DataViewId
}
indicator = append(indicator, indicatorMap)

case s.Indicator.IndicatorPropertiesTimesliceMetric != nil:
indicatorAddress = indicatorTypeToAddress[s.Indicator.IndicatorPropertiesTimesliceMetric.Type]
Expand Down Expand Up @@ -1049,12 +1107,16 @@ func resourceSloRead(ctx context.Context, d *schema.ResourceData, meta interface
"comparator": params.Metric.Comparator,
"threshold": params.Metric.Threshold,
}
indicator = append(indicator, map[string]interface{}{
indicatorMap := map[string]interface{}{
"index": params.Index,
"timestamp_field": params.TimestampField,
"filter": params.Filter,
"metric": []interface{}{metricBlock},
})
}
if params.DataViewId != nil {
indicatorMap["data_view_id"] = *params.DataViewId
}
indicator = append(indicator, indicatorMap)

default:
return diag.Errorf("indicator not set")
Expand Down
Loading
Loading