Skip to content

Data stream settings API doesn't work for TSDS #136166

@felixbarny

Description

@felixbarny

Elasticsearch Version

9.2

Installed Plugins

No response

Java Version

bundled

OS Version

not relevant

Problem Description

When trying to use the data stream settings api on a time series data stream, it fails with the error message [index.mode=time_series] requires a non-empty [index.routing_path]

Steps to Reproduce

PUT _index_template/quickstart-tsds-template
{
  "index_patterns": ["quickstart-*"],
  "data_stream": { },
  "priority": 100, 
  "template": {
    "settings": {
      "index.mode": "time_series"
    },
    "mappings": {
      "properties": {
        "host.name": {
          "type": "keyword",
          "time_series_dimension": true
        }
      }
    }
  }
}


PUT _data_stream/quickstart-tsds
PUT _data_stream/quickstart-tsds/_settings
{
  "index.number_of_shards": 2
}
{
  "data_streams": [
    {
      "name": "quickstart-tsds",
      "applied_to_data_stream": false,
      "error": "[index.mode=time_series] requires a non-empty [index.routing_path]",
      "settings": {},
      "effective_settings": {},
      "index_settings_results": {
        "applied_to_data_stream_only": [],
        "applied_to_data_stream_and_write_indices": [],
        "applied_to_data_stream_and_backing_indices": []
      }
    }
  ]
}

Reproduce in tests:

---
Index: modules/data-streams/src/internalClusterTest/java/org/elasticsearch/datastreams/DataStreamSettingsIT.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/modules/data-streams/src/internalClusterTest/java/org/elasticsearch/datastreams/DataStreamSettingsIT.java b/modules/data-streams/src/internalClusterTest/java/org/elasticsearch/datastreams/DataStreamSettingsIT.java
--- a/modules/data-streams/src/internalClusterTest/java/org/elasticsearch/datastreams/DataStreamSettingsIT.java	(revision 83120cd4a0e140b7ac3cdcd74beb5c2482614b3e)
+++ b/modules/data-streams/src/internalClusterTest/java/org/elasticsearch/datastreams/DataStreamSettingsIT.java	(date 1759913103316)
@@ -24,6 +24,7 @@
 import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
 import org.elasticsearch.cluster.metadata.IndexMetadata;
 import org.elasticsearch.cluster.metadata.Template;
+import org.elasticsearch.common.compress.CompressedXContent;
 import org.elasticsearch.common.settings.Setting;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.core.Nullable;
@@ -154,6 +155,44 @@
         }
     }
 
+    public void testPutDataStreamSettingsTSDS() throws Exception {
+        String dataStreamName = randomAlphaOfLength(20).toLowerCase(Locale.ROOT);
+        putComposableIndexTemplate(
+            "my-template",
+            List.of(dataStreamName),
+            indexSettings(1, 0).put("index.mode", "time_series").build(),
+            CompressedXContent.fromJSON("""
+                {
+                  "properties": {
+                    "host.name": {
+                      "type": "keyword",
+                      "time_series_dimension": true
+                    }
+                  }
+                }
+                """)
+        );
+        final var createDataStreamRequest = new CreateDataStreamAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, dataStreamName);
+        assertAcked(client().execute(CreateDataStreamAction.INSTANCE, createDataStreamRequest).actionGet());
+        final int numberOfShards = randomIntBetween(2, 7);
+        Settings dataStreamSettings = Settings.builder()
+            .put("index.number_of_shards", numberOfShards)
+            .build();
+        UpdateDataStreamSettingsAction.Response putSettingsResponse = client().execute(
+            UpdateDataStreamSettingsAction.INSTANCE,
+            new UpdateDataStreamSettingsAction.Request(dataStreamSettings, TimeValue.THIRTY_SECONDS, TimeValue.THIRTY_SECONDS).indices(
+                dataStreamName
+            )
+        ).actionGet();
+        List<UpdateDataStreamSettingsAction.DataStreamSettingsResponse> dataStreamSettingsResponses = putSettingsResponse
+            .getDataStreamSettingsResponses();
+        assertThat(dataStreamSettingsResponses.size(), equalTo(1));
+        UpdateDataStreamSettingsAction.DataStreamSettingsResponse dataStreamSettingsResponse = dataStreamSettingsResponses.get(0);
+        assertThat(dataStreamSettingsResponse.dataStreamName(), equalTo(dataStreamName));
+        assertThat(dataStreamSettingsResponse.dataStreamSucceeded(), equalTo(true));
+        assertThat(dataStreamSettingsResponse.settings().get("index.number_of_shards"), equalTo(Integer.toString(numberOfShards)));
+    }
+
     public void testPutMultipleDataStreamSettings() throws Exception {
         List<String> testDataStreamNames = new ArrayList<>();
         List<String> ignoredDataStreamNames = new ArrayList<>();
@@ -324,11 +363,20 @@
     }
 
     static void putComposableIndexTemplate(String id, List<String> patterns, @Nullable Settings settings) throws IOException {
+        putComposableIndexTemplate(id, patterns, settings, null);
+    }
+
+    static void putComposableIndexTemplate(
+        String id,
+        List<String> patterns,
+        @Nullable Settings settings,
+        @Nullable CompressedXContent mappings
+    ) throws IOException {
         TransportPutComposableIndexTemplateAction.Request request = new TransportPutComposableIndexTemplateAction.Request(id);
         request.indexTemplate(
             ComposableIndexTemplate.builder()
                 .indexPatterns(patterns)
-                .template(Template.builder().settings(settings))
+                .template(Template.builder().settings(settings).mappings(mappings))
                 .dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate())
                 .build()
         );
Index: x-pack/plugin/otel-data/src/yamlRestTest/resources/rest-api-spec/test/20_metrics_tests.yml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/x-pack/plugin/otel-data/src/yamlRestTest/resources/rest-api-spec/test/20_metrics_tests.yml b/x-pack/plugin/otel-data/src/yamlRestTest/resources/rest-api-spec/test/20_metrics_tests.yml
--- a/x-pack/plugin/otel-data/src/yamlRestTest/resources/rest-api-spec/test/20_metrics_tests.yml	(revision 83120cd4a0e140b7ac3cdcd74beb5c2482614b3e)
+++ b/x-pack/plugin/otel-data/src/yamlRestTest/resources/rest-api-spec/test/20_metrics_tests.yml	(date 1759911177211)
@@ -351,3 +351,28 @@
   - length: { hits.hits: 1 }
   - match: { hits.hits.0.fields.resource\.attributes\.host\.name: [ "localhost" ] }
   - match: { hits.hits.0.fields.host\.name: [ "localhost" ] }
+
+---
+data stream settings ilm:
+  - do:
+      bulk:
+        index: metrics-generic.otel-default
+        refresh: true
+        body:
+          - create: {"dynamic_templates":{"metrics.foo.bar":"counter_long"}}
+          - "@timestamp": 2024-07-18T14:00:00Z
+            resource:
+              attributes:
+                host.name: localhost
+            metrics:
+              foo.bar: 42
+  - is_false: errors
+  - do:
+      indices.put_data_stream_settings:
+        name: metrics-generic.otel-default
+        body:
+          index:
+            number_of_shards: 2
+  - match: { data_streams.0.name: metrics-generic.otel-default }
+  - match: { data_streams.0.applied_to_data_stream: true }
+

Logs (if relevant)

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions