diff --git a/CHANGELOG.md b/CHANGELOG.md index 32afa2c5c..a98032f68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/docs/resources/kibana_slo.md b/docs/resources/kibana_slo.md index 0ce7e5788..61add57c0 100644 --- a/docs/resources/kibana_slo.md +++ b/docs/resources/kibana_slo.md @@ -323,6 +323,7 @@ Required: Optional: +- `data_view_id` (String) Optional data view id to use for this indicator. - `filter` (String) - `timestamp_field` (String) @@ -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) @@ -383,6 +385,7 @@ Required: Optional: +- `data_view_id` (String) Optional data view id to use for this indicator. - `filter` (String) - `timestamp_field` (String) @@ -453,6 +456,7 @@ Required: Optional: +- `data_view_id` (String) Optional data view id to use for this indicator. - `filter` (String) diff --git a/internal/clients/kibana/slo.go b/internal/clients/kibana/slo.go index 593c7e8f6..08aed32a2 100644 --- a/internal/clients/kibana/slo.go +++ b/internal/clients/kibana/slo.go @@ -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() @@ -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() @@ -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() @@ -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() diff --git a/internal/kibana/slo.go b/internal/kibana/slo.go index eaf5429e7..53dc3d19c 100644 --- a/internal/kibana/slo.go +++ b/internal/kibana/slo.go @@ -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{ @@ -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, @@ -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, @@ -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, @@ -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, @@ -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 { @@ -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), @@ -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), @@ -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{ @@ -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) @@ -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) @@ -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] @@ -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] @@ -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] @@ -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") diff --git a/internal/kibana/slo_test.go b/internal/kibana/slo_test.go index 23a287c1a..2f1216bed 100644 --- a/internal/kibana/slo_test.go +++ b/internal/kibana/slo_test.go @@ -31,149 +31,224 @@ func TestAccResourceSlo(t *testing.T) { slo8_10Constraints, err := version.NewConstraint(">=8.10.0,!=8.11.0,!=8.11.1,!=8.11.2,!=8.11.3,!=8.11.4") require.NoError(t, err) - sloName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) - resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - CheckDestroy: checkResourceSloDestroy, - ProtoV6ProviderFactories: acctest.Providers, - Steps: []resource.TestStep{ - { - SkipFunc: versionutils.CheckIfVersionMeetsConstraints(slo8_9Constraints), - Config: getSLOConfig(sloVars{name: sloName, indicatorType: "apm_latency_indicator"}), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "name", sloName), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "slo_id", "id-"+sloName), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "description", "fully sick SLO"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_latency_indicator.0.environment", "production"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_latency_indicator.0.service", "my-service"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_latency_indicator.0.transaction_type", "request"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_latency_indicator.0.transaction_name", "GET /sup/dawg"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_latency_indicator.0.index", "my-index-"+sloName), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_latency_indicator.0.threshold", "500"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "time_window.0.duration", "7d"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "time_window.0.type", "rolling"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "budgeting_method", "timeslices"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "objective.0.target", "0.999"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "objective.0.timeslice_target", "0.95"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "objective.0.timeslice_window", "5m"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "settings.0.sync_delay", "1m"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "settings.0.frequency", "1m"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "space_id", "default"), - ), - }, - { //check that name can be updated - SkipFunc: versionutils.CheckIfVersionMeetsConstraints(slo8_9Constraints), - Config: getSLOConfig(sloVars{ - name: fmt.Sprintf("updated-%s", sloName), - indicatorType: "apm_latency_indicator", - }), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "name", fmt.Sprintf("updated-%s", sloName)), - ), - }, - { //check that settings can be updated from api-computed defaults - SkipFunc: versionutils.CheckIfVersionMeetsConstraints(slo8_9Constraints), - Config: getSLOConfig(sloVars{name: sloName, indicatorType: "apm_latency_indicator", settingsEnabled: true}), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "settings.0.sync_delay", "5m"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "settings.0.frequency", "5m"), - ), - }, - { - SkipFunc: versionutils.CheckIfVersionMeetsConstraints(slo8_9Constraints), - Config: getSLOConfig(sloVars{name: sloName, indicatorType: "apm_availability_indicator", settingsEnabled: true}), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_availability_indicator.0.environment", "production"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_availability_indicator.0.service", "my-service"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_availability_indicator.0.transaction_type", "request"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_availability_indicator.0.transaction_name", "GET /sup/dawg"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_availability_indicator.0.index", "my-index-"+sloName), - ), - }, - { - SkipFunc: versionutils.CheckIfVersionMeetsConstraints(slo8_9Constraints), - Config: getSLOConfig(sloVars{name: sloName, indicatorType: "kql_custom_indicator", settingsEnabled: true}), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "kql_custom_indicator.0.index", "my-index-"+sloName), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "kql_custom_indicator.0.good", "latency < 300"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "kql_custom_indicator.0.total", "*"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "kql_custom_indicator.0.filter", "labels.groupId: group-0"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "kql_custom_indicator.0.timestamp_field", "custom_timestamp"), - ), - }, - { - SkipFunc: versionutils.CheckIfVersionMeetsConstraints(slo8_10Constraints), - Config: getSLOConfig(sloVars{name: sloName, indicatorType: "histogram_custom_indicator", settingsEnabled: true}), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.index", "my-index-"+sloName), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.field", "test"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.aggregation", "value_count"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.filter", "latency < 300"), - resource.TestCheckResourceAttrSet("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.from"), - resource.TestCheckResourceAttrSet("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.to"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.total.0.field", "test"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.total.0.aggregation", "value_count"), - ), - }, - { - SkipFunc: versionutils.CheckIfVersionMeetsConstraints(slo8_10Constraints), - Config: getSLOConfig(sloVars{ - name: sloName, - indicatorType: "metric_custom_indicator", - settingsEnabled: true, - groupBy: []string{"some.field"}, - }), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.index", "my-index-"+sloName), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.good.0.metrics.0.name", "A"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.good.0.metrics.0.aggregation", "sum"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.good.0.metrics.0.field", "processor.processed"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.good.0.metrics.1.name", "B"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.good.0.metrics.1.aggregation", "sum"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.good.0.metrics.1.field", "processor.processed"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.good.0.equation", "A + B"), + for _, testWithDataViewID := range []bool{true, false} { + t.Run("with-data-view-id="+fmt.Sprint(testWithDataViewID), func(t *testing.T) { + dataviewCheckFunc := func(indicator string) resource.TestCheckFunc { + if !testWithDataViewID { + return func(s *terraform.State) error { + return nil + } + } - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.total.0.metrics.0.name", "A"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.total.0.metrics.0.aggregation", "sum"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.total.0.metrics.0.field", "processor.accepted"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.total.0.metrics.1.name", "B"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.total.0.metrics.1.aggregation", "sum"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.total.0.metrics.1.field", "processor.accepted"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.total.0.equation", "A + B"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "group_by.#", "1"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "group_by.0", "some.field"), - ), - }, - { - SkipFunc: versionutils.CheckIfVersionMeetsConstraints(slo8_10Constraints), - Config: getSLOConfig(sloVars{ - name: sloName, - indicatorType: "metric_custom_indicator", - settingsEnabled: true, - tags: []string{"tag-1", "another_tag"}, - }), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "tags.0", "tag-1"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "tags.1", "another_tag"), - ), - }, - { - SkipFunc: versionutils.CheckIfVersionIsUnsupported(sloTimesliceMetricsMinVersion), - Config: getSLOConfig(sloVars{ - name: sloName, - indicatorType: "timeslice_metric_indicator", - settingsEnabled: true, - tags: []string{"tag-1", "another_tag"}, - }), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "timeslice_metric_indicator.0.index", "my-index-"+sloName), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "timeslice_metric_indicator.0.metric.0.metrics.0.name", "A"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "timeslice_metric_indicator.0.metric.0.metrics.0.aggregation", "sum"), - resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "timeslice_metric_indicator.0.metric.0.equation", "A"), - ), - }, - }, - }) + return resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", indicator+".0.data_view_id", "my-data-view-id") + } + sloName := sdkacctest.RandStringFromCharSet(22, sdkacctest.CharSetAlphaNum) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + CheckDestroy: checkResourceSloDestroy, + ProtoV6ProviderFactories: acctest.Providers, + Steps: []resource.TestStep{ + { + SkipFunc: func() (bool, error) { + if !testWithDataViewID { + return versionutils.CheckIfVersionMeetsConstraints(slo8_9Constraints)() + } + + return versionutils.CheckIfVersionIsUnsupported(kibanaresource.SLOSupportsDataViewIDMinVersion)() + }, + Config: getSLOConfig(sloVars{name: sloName, indicatorType: "apm_latency_indicator", includeDataViewID: testWithDataViewID}), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "name", sloName), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "slo_id", "id-"+sloName), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "description", "fully sick SLO"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_latency_indicator.0.environment", "production"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_latency_indicator.0.service", "my-service"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_latency_indicator.0.transaction_type", "request"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_latency_indicator.0.transaction_name", "GET /sup/dawg"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_latency_indicator.0.index", "my-index-"+sloName), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_latency_indicator.0.threshold", "500"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "time_window.0.duration", "7d"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "time_window.0.type", "rolling"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "budgeting_method", "timeslices"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "objective.0.target", "0.999"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "objective.0.timeslice_target", "0.95"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "objective.0.timeslice_window", "5m"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "settings.0.sync_delay", "1m"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "settings.0.frequency", "1m"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "space_id", "default"), + ), + }, + { //check that name can be updated + SkipFunc: func() (bool, error) { + if !testWithDataViewID { + return versionutils.CheckIfVersionMeetsConstraints(slo8_9Constraints)() + } + + return versionutils.CheckIfVersionIsUnsupported(kibanaresource.SLOSupportsDataViewIDMinVersion)() + }, + Config: getSLOConfig(sloVars{ + name: fmt.Sprintf("updated-%s", sloName), + indicatorType: "apm_latency_indicator", + includeDataViewID: testWithDataViewID, + }), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "name", fmt.Sprintf("updated-%s", sloName)), + ), + }, + { //check that settings can be updated from api-computed defaults + SkipFunc: func() (bool, error) { + if !testWithDataViewID { + return versionutils.CheckIfVersionMeetsConstraints(slo8_9Constraints)() + } + + return versionutils.CheckIfVersionIsUnsupported(kibanaresource.SLOSupportsDataViewIDMinVersion)() + }, + Config: getSLOConfig(sloVars{name: sloName, indicatorType: "apm_latency_indicator", settingsEnabled: true, includeDataViewID: testWithDataViewID}), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "settings.0.sync_delay", "5m"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "settings.0.frequency", "5m"), + ), + }, + { + SkipFunc: func() (bool, error) { + if !testWithDataViewID { + return versionutils.CheckIfVersionMeetsConstraints(slo8_9Constraints)() + } + + return versionutils.CheckIfVersionIsUnsupported(kibanaresource.SLOSupportsDataViewIDMinVersion)() + }, + Config: getSLOConfig(sloVars{name: sloName, indicatorType: "apm_availability_indicator", settingsEnabled: true, includeDataViewID: testWithDataViewID}), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_availability_indicator.0.environment", "production"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_availability_indicator.0.service", "my-service"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_availability_indicator.0.transaction_type", "request"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_availability_indicator.0.transaction_name", "GET /sup/dawg"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "apm_availability_indicator.0.index", "my-index-"+sloName), + ), + }, + { + SkipFunc: func() (bool, error) { + if !testWithDataViewID { + return versionutils.CheckIfVersionMeetsConstraints(slo8_9Constraints)() + } + + return versionutils.CheckIfVersionIsUnsupported(kibanaresource.SLOSupportsDataViewIDMinVersion)() + }, + Config: getSLOConfig(sloVars{name: sloName, indicatorType: "kql_custom_indicator", settingsEnabled: true, includeDataViewID: testWithDataViewID}), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "kql_custom_indicator.0.index", "my-index-"+sloName), + dataviewCheckFunc("kql_custom_indicator"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "kql_custom_indicator.0.good", "latency < 300"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "kql_custom_indicator.0.total", "*"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "kql_custom_indicator.0.filter", "labels.groupId: group-0"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "kql_custom_indicator.0.timestamp_field", "custom_timestamp"), + ), + }, + { + SkipFunc: func() (bool, error) { + if !testWithDataViewID { + return versionutils.CheckIfVersionMeetsConstraints(slo8_10Constraints)() + } + + return versionutils.CheckIfVersionIsUnsupported(kibanaresource.SLOSupportsDataViewIDMinVersion)() + }, + Config: getSLOConfig(sloVars{name: sloName, indicatorType: "histogram_custom_indicator", settingsEnabled: true, includeDataViewID: testWithDataViewID}), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.index", "my-index-"+sloName), + dataviewCheckFunc("histogram_custom_indicator"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.field", "test"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.aggregation", "value_count"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.filter", "latency < 300"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.from"), + resource.TestCheckResourceAttrSet("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.good.0.to"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.total.0.field", "test"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "histogram_custom_indicator.0.total.0.aggregation", "value_count"), + ), + }, + { + SkipFunc: func() (bool, error) { + if !testWithDataViewID { + return versionutils.CheckIfVersionMeetsConstraints(slo8_10Constraints)() + } + + return versionutils.CheckIfVersionIsUnsupported(kibanaresource.SLOSupportsDataViewIDMinVersion)() + }, + Config: getSLOConfig(sloVars{ + name: sloName, + indicatorType: "metric_custom_indicator", + settingsEnabled: true, + groupBy: []string{"some.field"}, + includeDataViewID: testWithDataViewID, + }), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.index", "my-index-"+sloName), + dataviewCheckFunc("metric_custom_indicator"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.good.0.metrics.0.name", "A"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.good.0.metrics.0.aggregation", "sum"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.good.0.metrics.0.field", "processor.processed"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.good.0.metrics.1.name", "B"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.good.0.metrics.1.aggregation", "sum"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.good.0.metrics.1.field", "processor.processed"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.good.0.equation", "A + B"), + + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.total.0.metrics.0.name", "A"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.total.0.metrics.0.aggregation", "sum"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.total.0.metrics.0.field", "processor.accepted"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.total.0.metrics.1.name", "B"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.total.0.metrics.1.aggregation", "sum"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.total.0.metrics.1.field", "processor.accepted"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.total.0.equation", "A + B"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "group_by.#", "1"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "group_by.0", "some.field"), + ), + }, + { + SkipFunc: func() (bool, error) { + if !testWithDataViewID { + return versionutils.CheckIfVersionMeetsConstraints(slo8_10Constraints)() + } + + return versionutils.CheckIfVersionIsUnsupported(kibanaresource.SLOSupportsDataViewIDMinVersion)() + }, + Config: getSLOConfig(sloVars{ + name: sloName, + indicatorType: "metric_custom_indicator", + settingsEnabled: true, + tags: []string{"tag-1", "another_tag"}, + includeDataViewID: testWithDataViewID, + }), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "tags.0", "tag-1"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "tags.1", "another_tag"), + ), + }, + { + SkipFunc: func() (bool, error) { + if !testWithDataViewID { + return versionutils.CheckIfVersionIsUnsupported(sloTimesliceMetricsMinVersion)() + } + + return versionutils.CheckIfVersionIsUnsupported(kibanaresource.SLOSupportsDataViewIDMinVersion)() + }, + Config: getSLOConfig(sloVars{ + name: sloName, + indicatorType: "timeslice_metric_indicator", + settingsEnabled: true, + tags: []string{"tag-1", "another_tag"}, + includeDataViewID: testWithDataViewID, + }), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "timeslice_metric_indicator.0.index", "my-index-"+sloName), + dataviewCheckFunc("timeslice_metric_indicator"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "timeslice_metric_indicator.0.metric.0.metrics.0.name", "A"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "timeslice_metric_indicator.0.metric.0.metrics.0.aggregation", "sum"), + resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "timeslice_metric_indicator.0.metric.0.equation", "A"), + ), + }, + }, + }) + }) + } } func TestAccResourceSloGroupBy(t *testing.T) { @@ -197,6 +272,8 @@ func TestAccResourceSloGroupBy(t *testing.T) { settingsEnabled: true, groupBy: []string{"some.field"}, useSingleElementGroupBy: true, + includeDataViewID: false, + // Do not set data_view_id for this test, as it is not supported in this provider version }), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.index", "my-index-"+sloName), @@ -222,10 +299,12 @@ func TestAccResourceSloGroupBy(t *testing.T) { ProtoV6ProviderFactories: acctest.Providers, SkipFunc: versionutils.CheckIfVersionIsUnsupported(kibanaresource.SLOSupportsMultipleGroupByMinVersion), Config: getSLOConfig(sloVars{ - name: sloName, - indicatorType: "metric_custom_indicator", - settingsEnabled: true, - groupBy: []string{"some.field", "some.other.field"}, + name: sloName, + indicatorType: "metric_custom_indicator", + settingsEnabled: true, + groupBy: []string{"some.field", "some.other.field"}, + includeDataViewID: false, + // Do not set data_view_id for this test, as it is not supported in this provider version }), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("elasticstack_kibana_slo.test_slo", "metric_custom_indicator.0.index", "my-index-"+sloName), @@ -720,6 +799,7 @@ type sloVars struct { tags []string groupBy []string useSingleElementGroupBy bool + includeDataViewID bool } func getSLOConfig(vars sloVars) string { @@ -757,6 +837,11 @@ func getSLOConfig(vars sloVars) string { groupByOption = "" } + dataViewID := "" + if vars.includeDataViewID { + dataViewID = "data_view_id = \"my-data-view-id\"" + } + configTemplate := ` provider "elasticstack" { elasticsearch {} @@ -804,126 +889,131 @@ func getSLOConfig(vars sloVars) string { switch indicatorType { case "apm_latency_indicator": indicator = fmt.Sprintf(` - apm_latency_indicator { - environment = "production" - service = "my-service" - transaction_type = "request" - transaction_name = "GET /sup/dawg" - index = "my-index-%s" - threshold = 500 - } - `, vars.name) + apm_latency_indicator { + environment = "production" + service = "my-service" + transaction_type = "request" + transaction_name = "GET /sup/dawg" + index = "my-index-%s" + threshold = 500 + } + `, vars.name) case "apm_availability_indicator": indicator = fmt.Sprintf(` - apm_availability_indicator { - environment = "production" - service = "my-service" - transaction_type = "request" - transaction_name = "GET /sup/dawg" - index = "my-index-%s" - } - `, vars.name) + apm_availability_indicator { + environment = "production" + service = "my-service" + transaction_type = "request" + transaction_name = "GET /sup/dawg" + index = "my-index-%s" + } + `, vars.name) case "kql_custom_indicator": indicator = fmt.Sprintf(` - kql_custom_indicator { - index = "my-index-%s" - good = "latency < 300" - total = "*" - filter = "labels.groupId: group-0" - timestamp_field = "custom_timestamp" - } - `, vars.name) + kql_custom_indicator { + index = "my-index-%s" + %s + good = "latency < 300" + total = "*" + filter = "labels.groupId: group-0" + timestamp_field = "custom_timestamp" + } + `, vars.name, dataViewID) case "histogram_custom_indicator": indicator = fmt.Sprintf(` - histogram_custom_indicator { - index = "my-index-%s" - good { - field = "test" - aggregation = "value_count" - filter = "latency < 300" - } - total { - field = "test" - aggregation = "value_count" - } - filter = "labels.groupId: group-0" - timestamp_field = "custom_timestamp" - } - `, vars.name) + histogram_custom_indicator { + index = "my-index-%s" + %s + good { + field = "test" + aggregation = "value_count" + filter = "latency < 300" + } + total { + field = "test" + aggregation = "value_count" + } + filter = "labels.groupId: group-0" + timestamp_field = "custom_timestamp" + } + `, vars.name, dataViewID) case "histogram_custom_indicator_agg_fail": indicator = fmt.Sprintf(` - histogram_custom_indicator { - index = "my-index-%s" - good { - field = "test" - aggregation = "supdawg" - filter = "latency < 300" - from = 0 - to = 10 - } - total { - field = "test" - aggregation = "supdawg" - } - filter = "labels.groupId: group-0" - timestamp_field = "custom_timestamp" - } - `, vars.name) + histogram_custom_indicator { + index = "my-index-%s" + %s + good { + field = "test" + aggregation = "supdawg" + filter = "latency < 300" + from = 0 + to = 10 + } + total { + field = "test" + aggregation = "supdawg" + } + filter = "labels.groupId: group-0" + timestamp_field = "custom_timestamp" + } + `, vars.name, dataViewID) case "metric_custom_indicator": indicator = fmt.Sprintf(` - metric_custom_indicator { - index = "my-index-%s" - good { - metrics { - name = "A" - aggregation = "sum" - field = "processor.processed" - } - metrics { - name = "B" - aggregation = "sum" - field = "processor.processed" - } - equation = "A + B" - } - - total { - metrics { - name = "A" - aggregation = "sum" - field = "processor.accepted" - } - metrics { - name = "B" - aggregation = "sum" - field = "processor.accepted" - } - equation = "A + B" - } - } - `, vars.name) + metric_custom_indicator { + index = "my-index-%s" + %s + good { + metrics { + name = "A" + aggregation = "sum" + field = "processor.processed" + } + metrics { + name = "B" + aggregation = "sum" + field = "processor.processed" + } + equation = "A + B" + } + + total { + metrics { + name = "A" + aggregation = "sum" + field = "processor.accepted" + } + metrics { + name = "B" + aggregation = "sum" + field = "processor.accepted" + } + equation = "A + B" + } + } + `, vars.name, dataViewID) case "timeslice_metric_indicator": indicator = fmt.Sprintf(` - timeslice_metric_indicator { - index = "my-index-%s" - timestamp_field = "@timestamp" - metric { - metrics { - name = "A" - aggregation = "sum" - field = "latency" - } - equation = "A" - comparator = "GT" - threshold = 100 - } - } - `, vars.name) + timeslice_metric_indicator { + index = "my-index-%s" + %s + timestamp_field = "@timestamp" + metric { + metrics { + name = "A" + aggregation = "sum" + field = "latency" + } + equation = "A" + comparator = "GT" + threshold = 100 + } + } + `, vars.name, dataViewID) } return indicator }