Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
89a1263
Add fallbackToMatchOnlyText flag to PatternedTextFieldMapper
jordan-powers Sep 10, 2025
a8289cb
Include settings defined in plugins in MapperServiceTestCase#createMa…
jordan-powers Sep 10, 2025
d52ea6d
Add tests for fallbackToMatchOnlyText
jordan-powers Sep 10, 2025
706718e
Create DataStreamLicenseChangeTestCase base class
jordan-powers Sep 10, 2025
3cabb61
Add integration tests for patterned_text license upgrade/downgrade
jordan-powers Sep 10, 2025
8de8d0f
Make DataStreamLicenseChangeTestCase abstract
jordan-powers Sep 11, 2025
0020f48
Pass up license to XPackPlugin in LocalStateCompositeXPackPlugin
jordan-powers Sep 11, 2025
061c8d4
Update LogsdbIndexSettingsProviderLegacyLicenseTests
jordan-powers Sep 11, 2025
6f7a5a8
Rename settings
jordan-powers Sep 11, 2025
162a38a
Clean up comments
jordan-powers Sep 11, 2025
c1c63d4
Disable PatternedTextLicense tests in non-snapshot builds
jordan-powers Sep 11, 2025
d97bf2c
Merge remote-tracking branch 'upstream/main' into patterned-text-lice…
jordan-powers Sep 11, 2025
00f8341
Add missed rename
jordan-powers Sep 11, 2025
0860b3e
Add LocalStateLogsdb subclass of LocalStateCompositeXPackPlugin
jordan-powers Sep 11, 2025
051c545
Rename patterned_text_disable_enterprise to patterned_text.disable_te…
jordan-powers Sep 11, 2025
6797e8b
Change patterned_text.disable_templating index setting scope to Priva…
jordan-powers Sep 11, 2025
3ea06e5
Merge remote-tracking branch 'upstream/main' into patterned-text-lice…
jordan-powers Sep 11, 2025
21c06de
Fix failing tests
jordan-powers Sep 15, 2025
2e06c2d
Revert "Add LocalStateLogsdb subclass of LocalStateCompositeXPackPlugin"
jordan-powers Sep 15, 2025
329b243
Merge remote-tracking branch 'upstream/main' into patterned-text-lice…
jordan-powers Sep 15, 2025
f4b7aa7
Move disableTemplating flag to PatternedTextFieldType
jordan-powers Sep 15, 2025
5cf3b93
Fix typo in comment
jordan-powers Sep 16, 2025
96543e1
Merge remote-tracking branch 'upstream/main' into patterned-text-lice…
jordan-powers Sep 16, 2025
76ae5b1
Merge remote-tracking branch 'upstream/main' into patterned-text-lice…
jordan-powers Sep 16, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.IndexScopedSettings;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.common.util.MockBigArrays;
Expand Down Expand Up @@ -88,6 +90,7 @@
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -282,10 +285,15 @@ public TestMapperServiceBuilder applyDefaultMapping(boolean applyDefaultMapping)
}

public MapperService build() {
IndexSettings indexSettings = createIndexSettings(indexVersion, settings);
Collection<? extends Plugin> plugins = getPlugins();
Collection<Setting<?>> pluginIndexSettings = plugins.stream()
.flatMap(plugin -> plugin.getSettings().stream())
.filter(Setting::hasIndexScope)
.toList();
IndexSettings indexSettings = createIndexSettings(indexVersion, settings, pluginIndexSettings);
SimilarityService similarityService = new SimilarityService(indexSettings, null, Map.of());
MapperRegistry mapperRegistry = new IndicesModule(
getPlugins().stream().filter(p -> p instanceof MapperPlugin).map(p -> (MapperPlugin) p).collect(toList())
plugins.stream().filter(p -> p instanceof MapperPlugin).map(p -> (MapperPlugin) p).collect(toList())
).getMapperRegistry();

BitsetFilterCache bitsetFilterCache = new BitsetFilterCache(indexSettings, BitsetFilterCache.Listener.NOOP);
Expand Down Expand Up @@ -327,9 +335,19 @@ protected <T> T compileScript(Script script, ScriptContext<T> context) {
}

protected static IndexSettings createIndexSettings(IndexVersion version, Settings settings) {
return createIndexSettings(version, settings, List.of());
}

protected static IndexSettings createIndexSettings(
IndexVersion version,
Settings settings,
Collection<Setting<?>> pluginIndexSettings
) {
settings = indexSettings(1, 0).put(settings).put(IndexMetadata.SETTING_VERSION_CREATED, version).build();
IndexMetadata meta = IndexMetadata.builder("index").settings(settings).build();
return new IndexSettings(meta, settings);
Set<Setting<?>> indexSettings = new HashSet<>(IndexScopedSettings.BUILT_IN_INDEX_SETTINGS);
indexSettings.addAll(pluginIndexSettings);
return new IndexSettings(meta, settings, new IndexScopedSettings(Settings.EMPTY, indexSettings));
}

protected MapperMetrics createTestMapperMetrics() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.logsdb;

import org.elasticsearch.client.Request;
import org.elasticsearch.test.cluster.ElasticsearchCluster;
import org.elasticsearch.test.cluster.local.distribution.DistributionType;
import org.junit.ClassRule;

import java.io.IOException;

public abstract class DataStreamLicenseChangeTestCase extends LogsIndexModeRestTestIT {
@ClassRule
public static ElasticsearchCluster cluster = ElasticsearchCluster.local()
.distribution(DistributionType.DEFAULT)
.module("data-streams")
.module("x-pack-stack")
.setting("cluster.logsdb.enabled", "true")
.setting("xpack.security.enabled", "false")
.setting("xpack.license.self_generated.type", "basic")
.build();

@Override
protected String getTestRestCluster() {
return cluster.getHttpAddresses();
}

protected static void startBasic() throws IOException {
Request startTrial = new Request("POST", "/_license/start_basic");
startTrial.addParameter("acknowledge", "true");
assertOK(client().performRequest(startTrial));
}

protected static void startTrial() throws IOException {
Request startTrial = new Request("POST", "/_license/start_trial");
startTrial.addParameter("acknowledge", "true");
assertOK(client().performRequest(startTrial));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ protected static void waitForLogs(RestClient client) throws Exception {
});
}

protected static Response putComponentTemplate(final RestClient client, final String componentTemplate, final String contends)
protected static Response putComponentTemplate(final RestClient client, final String componentTemplate, final String contents)
throws IOException {
final Request request = new Request("PUT", "/_component_template/" + componentTemplate);
request.setJsonEntity(contends);
request.setJsonEntity(contents);
return client.performRequest(request);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,10 @@ public void testFeatureUsageWithLogsdbIndex() throws IOException {
boolean found = false;
for (var feature : features) {
if (feature.get("family") != null) {
assertThat(feature.get("name"), anyOf(equalTo("synthetic-source"), equalTo("logsdb-routing-on-sort-fields")));
assertThat(
feature.get("name"),
anyOf(equalTo("synthetic-source"), equalTo("logsdb-routing-on-sort-fields"), equalTo("patterned-text-templating"))
);
assertThat(feature.get("license_level"), equalTo("enterprise"));
found = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,11 @@
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.index.mapper.SourceFieldMapper;
import org.elasticsearch.test.cluster.ElasticsearchCluster;
import org.elasticsearch.test.cluster.local.distribution.DistributionType;
import org.junit.ClassRule;

import java.io.IOException;
import java.util.List;

public abstract class DataStreamLicenseChangeIT extends LogsIndexModeRestTestIT {
@ClassRule
public static ElasticsearchCluster cluster = ElasticsearchCluster.local()
.distribution(DistributionType.DEFAULT)
.module("data-streams")
.module("x-pack-stack")
.setting("cluster.logsdb.enabled", "true")
.setting("xpack.security.enabled", "false")
.setting("xpack.license.self_generated.type", "basic")
.build();

@Override
protected String getTestRestCluster() {
return cluster.getHttpAddresses();
}
public abstract class SourceModeLicenseChangeTestCase extends DataStreamLicenseChangeTestCase {

protected interface TestCase {
String dataStreamName();
Expand Down Expand Up @@ -88,18 +71,6 @@ public void testLicenseChange() throws IOException {
}
}

protected static void startBasic() throws IOException {
Request startTrial = new Request("POST", "/_license/start_basic");
startTrial.addParameter("acknowledge", "true");
assertOK(client().performRequest(startTrial));
}

protected static void startTrial() throws IOException {
Request startTrial = new Request("POST", "/_license/start_trial");
startTrial.addParameter("acknowledge", "true");
assertOK(client().performRequest(startTrial));
}

protected static Response removeComponentTemplate(final RestClient client, final String componentTemplate) throws IOException {
final Request request = new Request("DELETE", "/_component_template/" + componentTemplate);
return client.performRequest(request);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import java.io.IOException;
import java.util.List;

public class DataStreamLicenceDowngradeIT extends DataStreamLicenseChangeIT {
public class SourceModeLicenseDowngradeIT extends SourceModeLicenseChangeTestCase {
@Override
protected void applyInitialLicense() throws IOException {
startTrial();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import java.io.IOException;
import java.util.List;

public class DataStreamLicenseUpgradeIT extends DataStreamLicenseChangeIT {
public class SourceModeLicenseUpgradeIT extends SourceModeLicenseChangeTestCase {
@Override
protected void applyInitialLicense() {}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.logsdb.patternedtext;

import org.elasticsearch.Build;
import org.elasticsearch.xpack.logsdb.DataStreamLicenseChangeTestCase;
import org.junit.Before;

import java.io.IOException;
import java.util.Map;

import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.not;

public class PatternedTextLicenseDowngradeIT extends DataStreamLicenseChangeTestCase {
@Before
public void checkClusterFeature() {
assumeTrue("[patterned_text] must be available", clusterHasFeature("mapper.patterned_text"));
assumeTrue("[patterned_text] is only available in snapshot builds", Build.current().isSnapshot());
}

private static final String patternedTextMapping = """
{
"template": {
"mappings": {
"properties": {
"patterned_field": {
"type": "patterned_text"
}
}
}
}
}""";

@SuppressWarnings("unchecked")
public void testLicenseDowngrade() throws IOException {
final String dataStreamName = "logs-test-patterned-text";

startTrial();
assertOK(putComponentTemplate(client(), "logs@custom", patternedTextMapping));
assertOK(createDataStream(client(), dataStreamName));

String backingIndex0 = getDataStreamBackingIndex(client(), dataStreamName, 0);
{
assertEquals("false", getSetting(client(), backingIndex0, "index.mapping.patterned_text.disable_templating"));
Map<String, Object> mapping = getMapping(client(), backingIndex0);
Map<String, Object> patternedFieldMapping = (Map<String, Object>) ((Map<String, Object>) mapping.get("properties")).get(
"patterned_field"
);
assertThat(patternedFieldMapping, not(hasKey("disable_templating")));
}

startBasic();
rolloverDataStream(client(), dataStreamName);

{
assertEquals("false", getSetting(client(), backingIndex0, "index.mapping.patterned_text.disable_templating"));
Map<String, Object> mapping = getMapping(client(), backingIndex0);
Map<String, Object> patternedFieldMapping = (Map<String, Object>) ((Map<String, Object>) mapping.get("properties")).get(
"patterned_field"
);
assertThat(patternedFieldMapping, not(hasKey("disable_templating")));
}

String backingIndex1 = getDataStreamBackingIndex(client(), dataStreamName, 1);
{
assertEquals("true", getSetting(client(), backingIndex1, "index.mapping.patterned_text.disable_templating"));
Map<String, Object> mapping = getMapping(client(), backingIndex1);
Map<String, Object> patternedFieldMapping = (Map<String, Object>) ((Map<String, Object>) mapping.get("properties")).get(
"patterned_field"
);
assertThat(patternedFieldMapping, hasEntry("disable_templating", true));
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.logsdb.patternedtext;

import org.elasticsearch.Build;
import org.elasticsearch.xpack.logsdb.DataStreamLicenseChangeTestCase;
import org.junit.Before;

import java.io.IOException;
import java.util.Map;

import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.not;

public class PatternedTextLicenseUpgradeIT extends DataStreamLicenseChangeTestCase {
@Before
public void checkClusterFeature() {
assumeTrue("[patterned_text] must be available", clusterHasFeature("mapper.patterned_text"));
assumeTrue("[patterned_text] is only available in snapshot builds", Build.current().isSnapshot());
}

private static final String patternedTextMapping = """
{
"template": {
"mappings": {
"properties": {
"patterned_field": {
"type": "patterned_text"
}
}
}
}
}""";

@SuppressWarnings("unchecked")
public void testLicenseUpgrade() throws IOException {
final String dataStreamName = "logs-test-patterned-text";

assertOK(putComponentTemplate(client(), "logs@custom", patternedTextMapping));
assertOK(createDataStream(client(), dataStreamName));

String backingIndex0 = getDataStreamBackingIndex(client(), dataStreamName, 0);
{
assertEquals("true", getSetting(client(), backingIndex0, "index.mapping.patterned_text.disable_templating"));
Map<String, Object> mapping = getMapping(client(), backingIndex0);
Map<String, Object> patternedFieldMapping = (Map<String, Object>) ((Map<String, Object>) mapping.get("properties")).get(
"patterned_field"
);
assertThat(patternedFieldMapping, hasEntry("disable_templating", true));
}

startTrial();
rolloverDataStream(client(), dataStreamName);

{
assertEquals("true", getSetting(client(), backingIndex0, "index.mapping.patterned_text.disable_templating"));
Map<String, Object> mapping = getMapping(client(), backingIndex0);
Map<String, Object> patternedFieldMapping = (Map<String, Object>) ((Map<String, Object>) mapping.get("properties")).get(
"patterned_field"
);
assertThat(patternedFieldMapping, hasEntry("disable_templating", true));
}

String backingIndex1 = getDataStreamBackingIndex(client(), dataStreamName, 1);
{
assertEquals("false", getSetting(client(), backingIndex1, "index.mapping.patterned_text.disable_templating"));
Map<String, Object> mapping = getMapping(client(), backingIndex1);
Map<String, Object> patternedFieldMapping = (Map<String, Object>) ((Map<String, Object>) mapping.get("properties")).get(
"patterned_field"
);
assertThat(patternedFieldMapping, not(hasKey("disable_templating")));
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -93,7 +94,11 @@ public Collection<IndexSettingProvider> getAdditionalIndexSettingProviders(Index

@Override
public List<Setting<?>> getSettings() {
return List.of(FALLBACK_SETTING, CLUSTER_LOGSDB_ENABLED, LOGSDB_PRIOR_LOGS_USAGE);
List<Setting<?>> settings = new ArrayList<>(List.of(FALLBACK_SETTING, CLUSTER_LOGSDB_ENABLED, LOGSDB_PRIOR_LOGS_USAGE));
if (PatternedTextFieldMapper.PATTERNED_TEXT_MAPPER.isEnabled()) {
settings.add(PatternedTextFieldMapper.DISABLE_TEMPLATING_SETTING);
}
return Collections.unmodifiableList(settings);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.elasticsearch.index.mapper.ObjectMapper;
import org.elasticsearch.index.mapper.SourceFieldMapper;
import org.elasticsearch.xcontent.XContentType;
import org.elasticsearch.xpack.logsdb.patternedtext.PatternedTextFieldMapper;

import java.io.IOException;
import java.time.Instant;
Expand Down Expand Up @@ -192,6 +193,11 @@ && matchesLogsPattern(dataStreamName)) {
}
}
}

if (PatternedTextFieldMapper.PATTERNED_TEXT_MAPPER.isEnabled()
&& licenseService.allowPatternedTextTemplating(isTemplateValidation) == false) {
additionalSettings.put(PatternedTextFieldMapper.DISABLE_TEMPLATING_SETTING.getKey(), true);
}
}

record MappingHints(boolean hasSyntheticSourceUsage, boolean sortOnHostName, boolean addHostNameField) {
Expand Down
Loading