mirror of
https://github.com/elastic/elasticsearch.git
synced 2025-04-24 23:27:25 -04:00
Merge branch 'main' into multi-project
This commit is contained in:
commit
597ab8a7e9
137 changed files with 2214 additions and 928 deletions
|
@ -15,6 +15,7 @@ import org.gradle.api.GradleException;
|
||||||
import org.gradle.api.Plugin;
|
import org.gradle.api.Plugin;
|
||||||
import org.gradle.api.Project;
|
import org.gradle.api.Project;
|
||||||
import org.gradle.api.Transformer;
|
import org.gradle.api.Transformer;
|
||||||
|
import org.gradle.api.invocation.Gradle;
|
||||||
import org.gradle.api.plugins.JavaBasePlugin;
|
import org.gradle.api.plugins.JavaBasePlugin;
|
||||||
import org.gradle.api.plugins.JavaPluginExtension;
|
import org.gradle.api.plugins.JavaPluginExtension;
|
||||||
import org.gradle.api.tasks.Copy;
|
import org.gradle.api.tasks.Copy;
|
||||||
|
@ -38,6 +39,15 @@ public class EclipseConventionPlugin implements Plugin<Project> {
|
||||||
@Override
|
@Override
|
||||||
public void apply(Project project) {
|
public void apply(Project project) {
|
||||||
project.getPlugins().apply(EclipsePlugin.class);
|
project.getPlugins().apply(EclipsePlugin.class);
|
||||||
|
Gradle gradle = project.getGradle();
|
||||||
|
|
||||||
|
boolean isEclipse = project.getProviders().systemProperty("eclipse.launcher").isPresent() || // Gradle launched from Eclipse
|
||||||
|
project.getProviders().systemProperty("eclipse.application").isPresent() || // Gradle launched from the Eclipse compiler server
|
||||||
|
gradle.getStartParameter().getTaskNames().contains("eclipse") || // Gradle launched from the command line to do eclipse stuff
|
||||||
|
gradle.getStartParameter().getTaskNames().contains("cleanEclipse");
|
||||||
|
// for eclipse ide specific hacks...
|
||||||
|
project.getExtensions().add("isEclipse", isEclipse);
|
||||||
|
|
||||||
EclipseModel eclipseModel = project.getExtensions().getByType(EclipseModel.class);
|
EclipseModel eclipseModel = project.getExtensions().getByType(EclipseModel.class);
|
||||||
EclipseProject eclipseProject = eclipseModel.getProject();
|
EclipseProject eclipseProject = eclipseModel.getProject();
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ public enum DockerBase {
|
||||||
// Chainguard based wolfi image with latest jdk
|
// Chainguard based wolfi image with latest jdk
|
||||||
// This is usually updated via renovatebot
|
// This is usually updated via renovatebot
|
||||||
// spotless:off
|
// spotless:off
|
||||||
WOLFI("docker.elastic.co/wolfi/chainguard-base:latest@sha256:d74b1fda6b7fee2c90b410df258e005c049e0672fe16d79d00e58f14fb69f90b",
|
WOLFI("docker.elastic.co/wolfi/chainguard-base:latest@sha256:c66fdafe581a6ab1668a962015de4ce4666a60ed601d24f019f03bb4aaab8eeb",
|
||||||
"-wolfi",
|
"-wolfi",
|
||||||
"apk"
|
"apk"
|
||||||
),
|
),
|
||||||
|
|
|
@ -33,11 +33,15 @@ public abstract class OracleOpenJdkToolchainResolver extends AbstractCustomJavaT
|
||||||
String url(String os, String arch, String extension);
|
String url(String os, String arch, String extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
record ReleasedJdkBuild(JavaLanguageVersion languageVersion, String version, String buildNumber, String hash) implements JdkBuild {
|
record ReleaseJdkBuild(JavaLanguageVersion languageVersion, String host, String version, String buildNumber, String hash)
|
||||||
|
implements
|
||||||
|
JdkBuild {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String url(String os, String arch, String extension) {
|
public String url(String os, String arch, String extension) {
|
||||||
return "https://download.oracle.com/java/GA/jdk"
|
return "https://"
|
||||||
|
+ host
|
||||||
|
+ "/java/GA/jdk"
|
||||||
+ version
|
+ version
|
||||||
+ "/"
|
+ "/"
|
||||||
+ hash
|
+ hash
|
||||||
|
@ -111,7 +115,8 @@ public abstract class OracleOpenJdkToolchainResolver extends AbstractCustomJavaT
|
||||||
// package private so it can be replaced by tests
|
// package private so it can be replaced by tests
|
||||||
List<JdkBuild> builds = List.of(
|
List<JdkBuild> builds = List.of(
|
||||||
getBundledJdkBuild(),
|
getBundledJdkBuild(),
|
||||||
new EarlyAccessJdkBuild(JavaLanguageVersion.of(24)),
|
// release candidate of JDK 24
|
||||||
|
new ReleaseJdkBuild(JavaLanguageVersion.of(24), "download.java.net", "24", "36", "1f9ff9062db4449d8ca828c504ffae90"),
|
||||||
new EarlyAccessJdkBuild(JavaLanguageVersion.of(25))
|
new EarlyAccessJdkBuild(JavaLanguageVersion.of(25))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -125,7 +130,7 @@ public abstract class OracleOpenJdkToolchainResolver extends AbstractCustomJavaT
|
||||||
String baseVersion = jdkVersionMatcher.group(1) + (jdkVersionMatcher.group(2) != null ? (jdkVersionMatcher.group(2)) : "");
|
String baseVersion = jdkVersionMatcher.group(1) + (jdkVersionMatcher.group(2) != null ? (jdkVersionMatcher.group(2)) : "");
|
||||||
String build = jdkVersionMatcher.group(3);
|
String build = jdkVersionMatcher.group(3);
|
||||||
String hash = jdkVersionMatcher.group(5);
|
String hash = jdkVersionMatcher.group(5);
|
||||||
return new ReleasedJdkBuild(bundledJdkMajorVersion, baseVersion, build, hash);
|
return new ReleaseJdkBuild(bundledJdkMajorVersion, "download.oracle.com", baseVersion, build, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -30,9 +30,10 @@ class OracleOpenJdkToolchainResolverSpec extends AbstractToolchainResolverSpec {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
toolChain.builds = toolChain.builds.findAll { it instanceof OracleOpenJdkToolchainResolver.EarlyAccessJdkBuild } + [
|
toolChain.builds = toolChain.builds + [
|
||||||
new OracleOpenJdkToolchainResolver.ReleasedJdkBuild(
|
new OracleOpenJdkToolchainResolver.ReleaseJdkBuild(
|
||||||
JavaLanguageVersion.of(20),
|
JavaLanguageVersion.of(20),
|
||||||
|
"download.oracle.com",
|
||||||
"20",
|
"20",
|
||||||
"36",
|
"36",
|
||||||
"bdc68b4b9cbc4ebcb30745c85038d91d"
|
"bdc68b4b9cbc4ebcb30745c85038d91d"
|
||||||
|
@ -52,16 +53,16 @@ class OracleOpenJdkToolchainResolverSpec extends AbstractToolchainResolverSpec {
|
||||||
[20, anyVendor(), LINUX, AARCH64, "https://download.oracle.com/java/GA/jdk20/bdc68b4b9cbc4ebcb30745c85038d91d/36/GPL/openjdk-20_linux-aarch64_bin.tar.gz"],
|
[20, anyVendor(), LINUX, AARCH64, "https://download.oracle.com/java/GA/jdk20/bdc68b4b9cbc4ebcb30745c85038d91d/36/GPL/openjdk-20_linux-aarch64_bin.tar.gz"],
|
||||||
[20, anyVendor(), WINDOWS, X86_64, "https://download.oracle.com/java/GA/jdk20/bdc68b4b9cbc4ebcb30745c85038d91d/36/GPL/openjdk-20_windows-x64_bin.zip"],
|
[20, anyVendor(), WINDOWS, X86_64, "https://download.oracle.com/java/GA/jdk20/bdc68b4b9cbc4ebcb30745c85038d91d/36/GPL/openjdk-20_windows-x64_bin.zip"],
|
||||||
// https://download.java.net/java/early_access/jdk23/23/GPL/openjdk-23-ea+23_macos-aarch64_bin.tar.gz
|
// https://download.java.net/java/early_access/jdk23/23/GPL/openjdk-23-ea+23_macos-aarch64_bin.tar.gz
|
||||||
[24, ORACLE, MAC_OS, X86_64, "https://download.java.net/java/early_access/jdk24/29/GPL/openjdk-24-ea+29_macos-x64_bin.tar.gz"],
|
[24, ORACLE, MAC_OS, X86_64, "https://download.java.net/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_macos-x64_bin.tar.gz"],
|
||||||
[24, ORACLE, MAC_OS, AARCH64, "https://download.java.net/java/early_access/jdk24/29/GPL/openjdk-24-ea+29_macos-aarch64_bin.tar.gz"],
|
[24, ORACLE, MAC_OS, AARCH64, "https://download.java.net/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_macos-aarch64_bin.tar.gz"],
|
||||||
[24, ORACLE, LINUX, X86_64, "https://download.java.net/java/early_access/jdk24/29/GPL/openjdk-24-ea+29_linux-x64_bin.tar.gz"],
|
[24, ORACLE, LINUX, X86_64, "https://download.java.net/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_linux-x64_bin.tar.gz"],
|
||||||
[24, ORACLE, LINUX, AARCH64, "https://download.java.net/java/early_access/jdk24/29/GPL/openjdk-24-ea+29_linux-aarch64_bin.tar.gz"],
|
[24, ORACLE, LINUX, AARCH64, "https://download.java.net/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_linux-aarch64_bin.tar.gz"],
|
||||||
[24, ORACLE, WINDOWS, X86_64, "https://download.java.net/java/early_access/jdk24/29/GPL/openjdk-24-ea+29_windows-x64_bin.zip"],
|
[24, ORACLE, WINDOWS, X86_64, "https://download.java.net/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_windows-x64_bin.zip"],
|
||||||
[24, anyVendor(), MAC_OS, X86_64, "https://download.java.net/java/early_access/jdk24/29/GPL/openjdk-24-ea+29_macos-x64_bin.tar.gz"],
|
[24, anyVendor(), MAC_OS, X86_64, "https://download.java.net/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_macos-x64_bin.tar.gz"],
|
||||||
[24, anyVendor(), MAC_OS, AARCH64, "https://download.java.net/java/early_access/jdk24/29/GPL/openjdk-24-ea+29_macos-aarch64_bin.tar.gz"],
|
[24, anyVendor(), MAC_OS, AARCH64, "https://download.java.net/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_macos-aarch64_bin.tar.gz"],
|
||||||
[24, anyVendor(), LINUX, X86_64, "https://download.java.net/java/early_access/jdk24/29/GPL/openjdk-24-ea+29_linux-x64_bin.tar.gz"],
|
[24, anyVendor(), LINUX, X86_64, "https://download.java.net/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_linux-x64_bin.tar.gz"],
|
||||||
[24, anyVendor(), LINUX, AARCH64, "https://download.java.net/java/early_access/jdk24/29/GPL/openjdk-24-ea+29_linux-aarch64_bin.tar.gz"],
|
[24, anyVendor(), LINUX, AARCH64, "https://download.java.net/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_linux-aarch64_bin.tar.gz"],
|
||||||
[24, anyVendor(), WINDOWS, X86_64, "https://download.java.net/java/early_access/jdk24/29/GPL/openjdk-24-ea+29_windows-x64_bin.zip"]]
|
[24, anyVendor(), WINDOWS, X86_64, "https://download.java.net/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_windows-x64_bin.zip"]]
|
||||||
}
|
}
|
||||||
|
|
||||||
@RestoreSystemProperties
|
@RestoreSystemProperties
|
||||||
|
@ -85,16 +86,6 @@ class OracleOpenJdkToolchainResolverSpec extends AbstractToolchainResolverSpec {
|
||||||
|
|
||||||
where:
|
where:
|
||||||
version | vendor | os | arch | expectedUrl
|
version | vendor | os | arch | expectedUrl
|
||||||
24 | ORACLE | MAC_OS | X86_64 | urlPrefix(24) + "42/GPL/openjdk-24-ea+42_macos-x64_bin.tar.gz"
|
|
||||||
24 | ORACLE | MAC_OS | AARCH64 | urlPrefix(24) + "42/GPL/openjdk-24-ea+42_macos-aarch64_bin.tar.gz"
|
|
||||||
24 | ORACLE | LINUX | X86_64 | urlPrefix(24) + "42/GPL/openjdk-24-ea+42_linux-x64_bin.tar.gz"
|
|
||||||
24 | ORACLE | LINUX | AARCH64 | urlPrefix(24) + "42/GPL/openjdk-24-ea+42_linux-aarch64_bin.tar.gz"
|
|
||||||
24 | ORACLE | WINDOWS | X86_64 | urlPrefix(24) + "42/GPL/openjdk-24-ea+42_windows-x64_bin.zip"
|
|
||||||
24 | anyVendor() | MAC_OS | X86_64 | urlPrefix(24) + "42/GPL/openjdk-24-ea+42_macos-x64_bin.tar.gz"
|
|
||||||
24 | anyVendor() | MAC_OS | AARCH64 | urlPrefix(24) + "42/GPL/openjdk-24-ea+42_macos-aarch64_bin.tar.gz"
|
|
||||||
24 | anyVendor() | LINUX | X86_64 | urlPrefix(24) + "42/GPL/openjdk-24-ea+42_linux-x64_bin.tar.gz"
|
|
||||||
24 | anyVendor() | LINUX | AARCH64 | urlPrefix(24) + "42/GPL/openjdk-24-ea+42_linux-aarch64_bin.tar.gz"
|
|
||||||
24 | anyVendor() | WINDOWS | X86_64 | urlPrefix(24) + "42/GPL/openjdk-24-ea+42_windows-x64_bin.zip"
|
|
||||||
25 | ORACLE | MAC_OS | X86_64 | urlPrefix(25) + "13/GPL/openjdk-25-ea+13_macos-x64_bin.tar.gz"
|
25 | ORACLE | MAC_OS | X86_64 | urlPrefix(25) + "13/GPL/openjdk-25-ea+13_macos-x64_bin.tar.gz"
|
||||||
25 | ORACLE | MAC_OS | AARCH64 | urlPrefix(25) + "13/GPL/openjdk-25-ea+13_macos-aarch64_bin.tar.gz"
|
25 | ORACLE | MAC_OS | AARCH64 | urlPrefix(25) + "13/GPL/openjdk-25-ea+13_macos-aarch64_bin.tar.gz"
|
||||||
25 | ORACLE | LINUX | X86_64 | urlPrefix(25) + "13/GPL/openjdk-25-ea+13_linux-x64_bin.tar.gz"
|
25 | ORACLE | LINUX | X86_64 | urlPrefix(25) + "13/GPL/openjdk-25-ea+13_linux-x64_bin.tar.gz"
|
||||||
|
|
|
@ -247,15 +247,6 @@ allprojects {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// injecting groovy property variables into all projects
|
|
||||||
project.ext {
|
|
||||||
// for ide hacks...
|
|
||||||
isEclipse = providers.systemProperty("eclipse.launcher").isPresent() || // Detects gradle launched from Eclipse's IDE
|
|
||||||
providers.systemProperty("eclipse.application").isPresent() || // Detects gradle launched from the Eclipse compiler server
|
|
||||||
gradle.startParameter.taskNames.contains('eclipse') || // Detects gradle launched from the command line to do eclipse stuff
|
|
||||||
gradle.startParameter.taskNames.contains('cleanEclipse')
|
|
||||||
}
|
|
||||||
|
|
||||||
ext.bwc_tests_enabled = bwc_tests_enabled
|
ext.bwc_tests_enabled = bwc_tests_enabled
|
||||||
|
|
||||||
// eclipse configuration
|
// eclipse configuration
|
||||||
|
|
|
@ -28,7 +28,7 @@ final class SystemJvmOptions {
|
||||||
static List<String> systemJvmOptions(Settings nodeSettings, final Map<String, String> sysprops) {
|
static List<String> systemJvmOptions(Settings nodeSettings, final Map<String, String> sysprops) {
|
||||||
String distroType = sysprops.get("es.distribution.type");
|
String distroType = sysprops.get("es.distribution.type");
|
||||||
boolean isHotspot = sysprops.getOrDefault("sun.management.compiler", "").contains("HotSpot");
|
boolean isHotspot = sysprops.getOrDefault("sun.management.compiler", "").contains("HotSpot");
|
||||||
boolean entitlementsExplicitlyEnabled = Booleans.parseBoolean(sysprops.getOrDefault("es.entitlements.enabled", "false"));
|
boolean entitlementsExplicitlyEnabled = Booleans.parseBoolean(sysprops.getOrDefault("es.entitlements.enabled", "true"));
|
||||||
// java 24+ only supports entitlements, but it may be enabled on earlier versions explicitly
|
// java 24+ only supports entitlements, but it may be enabled on earlier versions explicitly
|
||||||
boolean useEntitlements = RuntimeVersionFeature.isSecurityManagerAvailable() == false || entitlementsExplicitlyEnabled;
|
boolean useEntitlements = RuntimeVersionFeature.isSecurityManagerAvailable() == false || entitlementsExplicitlyEnabled;
|
||||||
return Stream.of(
|
return Stream.of(
|
||||||
|
|
6
docs/changelog/121827.yaml
Normal file
6
docs/changelog/121827.yaml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
pr: 121827
|
||||||
|
summary: Updates to allow using Cohere binary embedding response in semantic search
|
||||||
|
queries
|
||||||
|
area: Machine Learning
|
||||||
|
type: bug
|
||||||
|
issues: []
|
6
docs/changelog/122886.yaml
Normal file
6
docs/changelog/122886.yaml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
pr: 122886
|
||||||
|
summary: Add support to VALUES aggregation for spatial types
|
||||||
|
area: ES|QL
|
||||||
|
type: bug
|
||||||
|
issues:
|
||||||
|
- 122413
|
10
docs/changelog/122960.yaml
Normal file
10
docs/changelog/122960.yaml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
pr: 122960
|
||||||
|
summary: Deprecate Behavioral Analytics CRUD apis
|
||||||
|
area: Search
|
||||||
|
type: deprecation
|
||||||
|
issues: [ ]
|
||||||
|
deprecation:
|
||||||
|
title: Deprecate Behavioral Analytics CRUD apis
|
||||||
|
area: Search
|
||||||
|
details: Behavioral Analytics has been deprecated as of 9.0.0 and will be removed in a future release. The APIs will still work for now, but will emit warning headers that the API has been deprecated.
|
||||||
|
impact: Behavioral Analytics has been deprecated as of 9.0.0 and will be removed in a future release.
|
5
docs/changelog/122999.yaml
Normal file
5
docs/changelog/122999.yaml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
pr: 122999
|
||||||
|
summary: Store arrays offsets for ip fields natively with synthetic source
|
||||||
|
area: Mapping
|
||||||
|
type: enhancement
|
||||||
|
issues: []
|
6
docs/changelog/123346.yaml
Normal file
6
docs/changelog/123346.yaml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
pr: 123346
|
||||||
|
summary: Reduce license checks in `LicensedWriteLoadForecaster`
|
||||||
|
area: CRUD
|
||||||
|
type: bug
|
||||||
|
issues:
|
||||||
|
- 123247
|
5
docs/changelog/123384.yaml
Normal file
5
docs/changelog/123384.yaml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
pr: 123384
|
||||||
|
summary: Fixing serialization of `ScriptStats` `cache_evictions_history`
|
||||||
|
area: Stats
|
||||||
|
type: bug
|
||||||
|
issues: []
|
5
docs/changelog/123403.yaml
Normal file
5
docs/changelog/123403.yaml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
pr: 123403
|
||||||
|
summary: Use ordered maps for `PipelineConfiguration` xcontent deserialization
|
||||||
|
area: Ingest Node
|
||||||
|
type: bug
|
||||||
|
issues: []
|
|
@ -2,6 +2,7 @@
|
||||||
[[delete-analytics-collection]]
|
[[delete-analytics-collection]]
|
||||||
=== Delete Analytics Collection
|
=== Delete Analytics Collection
|
||||||
|
|
||||||
|
deprecated:[9.0.0]
|
||||||
beta::[]
|
beta::[]
|
||||||
|
|
||||||
++++
|
++++
|
||||||
|
@ -14,15 +15,6 @@ beta::[]
|
||||||
For the most up-to-date API details, refer to {api-es}/group/endpoint-analytics[Behavioral analytics APIs].
|
For the most up-to-date API details, refer to {api-es}/group/endpoint-analytics[Behavioral analytics APIs].
|
||||||
--
|
--
|
||||||
|
|
||||||
////
|
|
||||||
[source,console]
|
|
||||||
----
|
|
||||||
PUT _application/analytics/my_analytics_collection
|
|
||||||
----
|
|
||||||
// TESTSETUP
|
|
||||||
|
|
||||||
////
|
|
||||||
|
|
||||||
Removes a <<behavioral-analytics-overview,Behavioral Analytics>> Collection and its associated data stream.
|
Removes a <<behavioral-analytics-overview,Behavioral Analytics>> Collection and its associated data stream.
|
||||||
|
|
||||||
[[delete-analytics-collection-request]]
|
[[delete-analytics-collection-request]]
|
||||||
|
@ -59,3 +51,4 @@ The following example deletes the Analytics Collection named `my_analytics_colle
|
||||||
----
|
----
|
||||||
DELETE _application/analytics/my_analytics_collection/
|
DELETE _application/analytics/my_analytics_collection/
|
||||||
----
|
----
|
||||||
|
// TEST[skip:Behavioral Analytics APIs emit deprecation warnings and will not be updated]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
[[behavioral-analytics-apis]]
|
[[behavioral-analytics-apis]]
|
||||||
== Behavioral Analytics APIs
|
== Behavioral Analytics APIs
|
||||||
|
|
||||||
|
deprecated:[9.0.0]
|
||||||
beta::[]
|
beta::[]
|
||||||
|
|
||||||
++++
|
++++
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
[[list-analytics-collection]]
|
[[list-analytics-collection]]
|
||||||
=== List Analytics Collections
|
=== List Analytics Collections
|
||||||
|
|
||||||
|
deprecated:[9.0.0]
|
||||||
beta::[]
|
beta::[]
|
||||||
|
|
||||||
++++
|
++++
|
||||||
|
@ -14,22 +15,6 @@ beta::[]
|
||||||
For the most up-to-date API details, refer to {api-es}/group/endpoint-analytics[Behavioral analytics APIs].
|
For the most up-to-date API details, refer to {api-es}/group/endpoint-analytics[Behavioral analytics APIs].
|
||||||
--
|
--
|
||||||
|
|
||||||
////
|
|
||||||
[source,console]
|
|
||||||
----
|
|
||||||
PUT _application/analytics/my_analytics_collection
|
|
||||||
PUT _application/analytics/my_analytics_collection2
|
|
||||||
----
|
|
||||||
// TESTSETUP
|
|
||||||
|
|
||||||
[source,console]
|
|
||||||
----
|
|
||||||
DELETE _application/analytics/my_analytics_collection
|
|
||||||
DELETE _application/analytics/my_analytics_collection2
|
|
||||||
----
|
|
||||||
// TEARDOWN
|
|
||||||
////
|
|
||||||
|
|
||||||
Returns information about <<behavioral-analytics-overview,Behavioral Analytics>> Collections.
|
Returns information about <<behavioral-analytics-overview,Behavioral Analytics>> Collections.
|
||||||
|
|
||||||
[[list-analytics-collection-request]]
|
[[list-analytics-collection-request]]
|
||||||
|
@ -46,8 +31,9 @@ Requires the `manage_behavioral_analytics` cluster privilege.
|
||||||
==== {api-path-parms-title}
|
==== {api-path-parms-title}
|
||||||
|
|
||||||
`<criteria>`::
|
`<criteria>`::
|
||||||
(optional, string)
|
(optional, string) Criteria is used to find a matching analytics collection.
|
||||||
Criteria is used to find a matching analytics collection. This could be the name of the collection or a pattern to match multiple. If not specified, will return all analytics collections.
|
This could be the name of the collection or a pattern to match multiple.
|
||||||
|
If not specified, will return all analytics collections.
|
||||||
|
|
||||||
[[list-analytics-collection-response-codes]]
|
[[list-analytics-collection-response-codes]]
|
||||||
==== {api-response-codes-title}
|
==== {api-response-codes-title}
|
||||||
|
@ -66,6 +52,7 @@ The following example lists all configured Analytics Collections:
|
||||||
----
|
----
|
||||||
GET _application/analytics/
|
GET _application/analytics/
|
||||||
----
|
----
|
||||||
|
// TEST[skip:Behavioral Analytics APIs emit deprecation warnings and will not be updated]
|
||||||
|
|
||||||
A sample response:
|
A sample response:
|
||||||
|
|
||||||
|
@ -91,6 +78,7 @@ The following example returns the Analytics Collection that matches `my_analytic
|
||||||
----
|
----
|
||||||
GET _application/analytics/my_analytics_collection
|
GET _application/analytics/my_analytics_collection
|
||||||
----
|
----
|
||||||
|
// TEST[skip:Behavioral Analytics APIs emit deprecation warnings and will not be updated]
|
||||||
|
|
||||||
A sample response:
|
A sample response:
|
||||||
|
|
||||||
|
@ -111,6 +99,7 @@ The following example returns all Analytics Collections prefixed with `my`:
|
||||||
----
|
----
|
||||||
GET _application/analytics/my*
|
GET _application/analytics/my*
|
||||||
----
|
----
|
||||||
|
// TEST[skip:Behavioral Analytics APIs emit deprecation warnings and will not be updated]
|
||||||
|
|
||||||
A sample response:
|
A sample response:
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
[[post-analytics-collection-event]]
|
[[post-analytics-collection-event]]
|
||||||
=== Post Event to an Analytics Collection
|
=== Post Event to an Analytics Collection
|
||||||
|
|
||||||
|
deprecated:[9.0.0]
|
||||||
beta::[]
|
beta::[]
|
||||||
|
|
||||||
++++
|
++++
|
||||||
|
@ -14,20 +15,6 @@ beta::[]
|
||||||
For the most up-to-date API details, refer to {api-es}/group/endpoint-analytics[Behavioral analytics APIs].
|
For the most up-to-date API details, refer to {api-es}/group/endpoint-analytics[Behavioral analytics APIs].
|
||||||
--
|
--
|
||||||
|
|
||||||
////
|
|
||||||
[source,console]
|
|
||||||
----
|
|
||||||
PUT _application/analytics/my_analytics_collection
|
|
||||||
----
|
|
||||||
// TESTSETUP
|
|
||||||
|
|
||||||
[source,console]
|
|
||||||
----
|
|
||||||
DELETE _application/analytics/my_analytics_collection
|
|
||||||
----
|
|
||||||
// TEARDOWN
|
|
||||||
////
|
|
||||||
|
|
||||||
Post an event to a <<behavioral-analytics-overview,Behavioral Analytics>> Collection.
|
Post an event to a <<behavioral-analytics-overview,Behavioral Analytics>> Collection.
|
||||||
|
|
||||||
[[post-analytics-collection-event-request]]
|
[[post-analytics-collection-event-request]]
|
||||||
|
@ -105,3 +92,4 @@ POST _application/analytics/my_analytics_collection/event/search_click
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
// TEST[skip:Behavioral Analytics APIs emit deprecation warnings and will not be updated]
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
[[put-analytics-collection]]
|
[[put-analytics-collection]]
|
||||||
=== Put Analytics Collection
|
=== Put Analytics Collection
|
||||||
|
|
||||||
|
deprecated:[9.0.0]
|
||||||
beta::[]
|
beta::[]
|
||||||
|
|
||||||
++++
|
++++
|
||||||
|
@ -14,14 +15,6 @@ beta::[]
|
||||||
For the most up-to-date API details, refer to {api-es}/group/endpoint-analytics[Behavioral analytics APIs].
|
For the most up-to-date API details, refer to {api-es}/group/endpoint-analytics[Behavioral analytics APIs].
|
||||||
--
|
--
|
||||||
|
|
||||||
////
|
|
||||||
[source,console]
|
|
||||||
----
|
|
||||||
DELETE _application/analytics/my_analytics_collection
|
|
||||||
----
|
|
||||||
// TEARDOWN
|
|
||||||
////
|
|
||||||
|
|
||||||
Creates a <<behavioral-analytics-overview,Behavioral Analytics>> Collection.
|
Creates a <<behavioral-analytics-overview,Behavioral Analytics>> Collection.
|
||||||
|
|
||||||
[[put-analytics-collection-request]]
|
[[put-analytics-collection-request]]
|
||||||
|
@ -55,3 +48,4 @@ The following example creates a new Analytics Collection called `my_analytics_co
|
||||||
----
|
----
|
||||||
PUT _application/analytics/my_analytics_collection
|
PUT _application/analytics/my_analytics_collection
|
||||||
----
|
----
|
||||||
|
// TEST[skip:Behavioral Analytics APIs emit deprecation warnings and will not be updated]
|
||||||
|
|
|
@ -16,6 +16,30 @@
|
||||||
"variadic" : false,
|
"variadic" : false,
|
||||||
"returnType" : "boolean"
|
"returnType" : "boolean"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"params" : [
|
||||||
|
{
|
||||||
|
"name" : "field",
|
||||||
|
"type" : "cartesian_point",
|
||||||
|
"optional" : false,
|
||||||
|
"description" : ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"variadic" : false,
|
||||||
|
"returnType" : "cartesian_point"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params" : [
|
||||||
|
{
|
||||||
|
"name" : "field",
|
||||||
|
"type" : "cartesian_shape",
|
||||||
|
"optional" : false,
|
||||||
|
"description" : ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"variadic" : false,
|
||||||
|
"returnType" : "cartesian_shape"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"params" : [
|
"params" : [
|
||||||
{
|
{
|
||||||
|
@ -52,6 +76,30 @@
|
||||||
"variadic" : false,
|
"variadic" : false,
|
||||||
"returnType" : "double"
|
"returnType" : "double"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"params" : [
|
||||||
|
{
|
||||||
|
"name" : "field",
|
||||||
|
"type" : "geo_point",
|
||||||
|
"optional" : false,
|
||||||
|
"description" : ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"variadic" : false,
|
||||||
|
"returnType" : "geo_point"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params" : [
|
||||||
|
{
|
||||||
|
"name" : "field",
|
||||||
|
"type" : "geo_shape",
|
||||||
|
"optional" : false,
|
||||||
|
"description" : ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"variadic" : false,
|
||||||
|
"returnType" : "geo_shape"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"params" : [
|
"params" : [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
[[behavioral-analytics-api]]
|
[[behavioral-analytics-api]]
|
||||||
=== Behavioral Analytics API overview
|
=== Behavioral Analytics API overview
|
||||||
|
|
||||||
++++
|
++++
|
||||||
<titleabbrev>API overview</titleabbrev>
|
<titleabbrev>API overview</titleabbrev>
|
||||||
++++
|
++++
|
||||||
|
|
||||||
|
deprecated:[9.0.0]
|
||||||
|
|
||||||
This page outlines all the APIs available for behavioral analytics and links to their documentation.
|
This page outlines all the APIs available for behavioral analytics and links to their documentation.
|
||||||
|
|
||||||
[discrete]
|
[discrete]
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
<titleabbrev>Set up CORs</titleabbrev>
|
<titleabbrev>Set up CORs</titleabbrev>
|
||||||
++++
|
++++
|
||||||
|
|
||||||
|
deprecated:[9.0.0]
|
||||||
|
|
||||||
Behavioral Analytics sends events directly to the {es} API.
|
Behavioral Analytics sends events directly to the {es} API.
|
||||||
This means that the browser makes requests to the {es} API directly.
|
This means that the browser makes requests to the {es} API directly.
|
||||||
{es} supports https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS[Cross-Origin Resource Sharing (CORS)^], but this feature is disabled by default.
|
{es} supports https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS[Cross-Origin Resource Sharing (CORS)^], but this feature is disabled by default.
|
||||||
|
@ -43,4 +45,4 @@ On Elastic Cloud, you can do this by {cloud}/ec-add-user-settings.html#ec-add-us
|
||||||
==== Proxy the request through a server that supports CORS
|
==== Proxy the request through a server that supports CORS
|
||||||
|
|
||||||
If you are unable to enable CORS on {es}, you can proxy the request through a server that supports CORS.
|
If you are unable to enable CORS on {es}, you can proxy the request through a server that supports CORS.
|
||||||
This is more complicated, but is a viable option.
|
This is more complicated, but is a viable option.
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
<titleabbrev>Events reference</titleabbrev>
|
<titleabbrev>Events reference</titleabbrev>
|
||||||
++++
|
++++
|
||||||
|
|
||||||
|
deprecated:[9.0.0]
|
||||||
|
|
||||||
Behavioral Analytics logs events using the {ecs-ref}/ecs-reference.html[Elastic Common Schema^], including a custom field set for analytics events.
|
Behavioral Analytics logs events using the {ecs-ref}/ecs-reference.html[Elastic Common Schema^], including a custom field set for analytics events.
|
||||||
Refer to <<behavioral-analytics-event-reference-examples,examples>> of the full data objects that are logged.
|
Refer to <<behavioral-analytics-event-reference-examples,examples>> of the full data objects that are logged.
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
<titleabbrev>View events</titleabbrev>
|
<titleabbrev>View events</titleabbrev>
|
||||||
++++
|
++++
|
||||||
|
|
||||||
|
deprecated:[9.0.0]
|
||||||
|
|
||||||
[TIP]
|
[TIP]
|
||||||
====
|
====
|
||||||
Refer to <<behavioral-analytics-event-reference>> for a complete list of the fields logged by events.
|
Refer to <<behavioral-analytics-event-reference>> for a complete list of the fields logged by events.
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
[[behavioral-analytics-overview]]
|
[[behavioral-analytics-overview]]
|
||||||
== Search analytics
|
== Search analytics
|
||||||
|
|
||||||
|
deprecated:[9.0.0]
|
||||||
|
|
||||||
|
|
||||||
Behavioral Analytics is an analytics event collection platform.
|
Behavioral Analytics is an analytics event collection platform.
|
||||||
Use these tools to analyze your users' searching and clicking behavior.
|
Use these tools to analyze your users' searching and clicking behavior.
|
||||||
Leverage this information to improve the relevance of your search results and identify gaps in your content.
|
Leverage this information to improve the relevance of your search results and identify gaps in your content.
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
<titleabbrev>Get started</titleabbrev>
|
<titleabbrev>Get started</titleabbrev>
|
||||||
++++
|
++++
|
||||||
|
|
||||||
|
deprecated:[9.0.0]
|
||||||
|
|
||||||
You can manage your analytics in the {kib} UI.
|
You can manage your analytics in the {kib} UI.
|
||||||
Go to *Search > Behavioral Analytics* to get started.
|
Go to *Search > Behavioral Analytics* to get started.
|
||||||
|
|
||||||
|
|
|
@ -14,19 +14,17 @@ import com.sun.tools.attach.AgentLoadException;
|
||||||
import com.sun.tools.attach.AttachNotSupportedException;
|
import com.sun.tools.attach.AttachNotSupportedException;
|
||||||
import com.sun.tools.attach.VirtualMachine;
|
import com.sun.tools.attach.VirtualMachine;
|
||||||
|
|
||||||
import org.elasticsearch.core.CheckedConsumer;
|
|
||||||
import org.elasticsearch.core.SuppressForbidden;
|
import org.elasticsearch.core.SuppressForbidden;
|
||||||
import org.elasticsearch.entitlement.initialization.EntitlementInitialization;
|
import org.elasticsearch.entitlement.initialization.EntitlementInitialization;
|
||||||
import org.elasticsearch.entitlement.runtime.api.NotEntitledException;
|
|
||||||
import org.elasticsearch.entitlement.runtime.policy.Policy;
|
import org.elasticsearch.entitlement.runtime.policy.Policy;
|
||||||
import org.elasticsearch.logging.LogManager;
|
import org.elasticsearch.logging.LogManager;
|
||||||
import org.elasticsearch.logging.Logger;
|
import org.elasticsearch.logging.Logger;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@ -43,8 +41,11 @@ public class EntitlementBootstrap {
|
||||||
Path[] sharedRepoDirs,
|
Path[] sharedRepoDirs,
|
||||||
Path configDir,
|
Path configDir,
|
||||||
Path libDir,
|
Path libDir,
|
||||||
|
Path pluginsDir,
|
||||||
Path logsDir,
|
Path logsDir,
|
||||||
Path tempDir
|
Path tempDir,
|
||||||
|
Path pidFile,
|
||||||
|
Set<Class<?>> suppressFailureLogClasses
|
||||||
) {
|
) {
|
||||||
public BootstrapArgs {
|
public BootstrapArgs {
|
||||||
requireNonNull(pluginPolicies);
|
requireNonNull(pluginPolicies);
|
||||||
|
@ -58,8 +59,10 @@ public class EntitlementBootstrap {
|
||||||
requireNonNull(sharedRepoDirs);
|
requireNonNull(sharedRepoDirs);
|
||||||
requireNonNull(configDir);
|
requireNonNull(configDir);
|
||||||
requireNonNull(libDir);
|
requireNonNull(libDir);
|
||||||
|
requireNonNull(pluginsDir);
|
||||||
requireNonNull(logsDir);
|
requireNonNull(logsDir);
|
||||||
requireNonNull(tempDir);
|
requireNonNull(tempDir);
|
||||||
|
requireNonNull(suppressFailureLogClasses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,8 +84,11 @@ public class EntitlementBootstrap {
|
||||||
* @param sharedRepoDirs shared repository directories for Elasticsearch
|
* @param sharedRepoDirs shared repository directories for Elasticsearch
|
||||||
* @param configDir the config directory for Elasticsearch
|
* @param configDir the config directory for Elasticsearch
|
||||||
* @param libDir the lib directory for Elasticsearch
|
* @param libDir the lib directory for Elasticsearch
|
||||||
|
* @param pluginsDir the directory where plugins are installed for Elasticsearch
|
||||||
* @param tempDir the temp directory for Elasticsearch
|
* @param tempDir the temp directory for Elasticsearch
|
||||||
* @param logsDir the log directory for Elasticsearch
|
* @param logsDir the log directory for Elasticsearch
|
||||||
|
* @param pidFile path to a pid file for Elasticsearch, or {@code null} if one was not specified
|
||||||
|
* @param suppressFailureLogClasses classes for which we do not need or want to log Entitlements failures
|
||||||
*/
|
*/
|
||||||
public static void bootstrap(
|
public static void bootstrap(
|
||||||
Map<String, Policy> pluginPolicies,
|
Map<String, Policy> pluginPolicies,
|
||||||
|
@ -93,8 +99,11 @@ public class EntitlementBootstrap {
|
||||||
Path[] sharedRepoDirs,
|
Path[] sharedRepoDirs,
|
||||||
Path configDir,
|
Path configDir,
|
||||||
Path libDir,
|
Path libDir,
|
||||||
|
Path pluginsDir,
|
||||||
Path logsDir,
|
Path logsDir,
|
||||||
Path tempDir
|
Path tempDir,
|
||||||
|
Path pidFile,
|
||||||
|
Set<Class<?>> suppressFailureLogClasses
|
||||||
) {
|
) {
|
||||||
logger.debug("Loading entitlement agent");
|
logger.debug("Loading entitlement agent");
|
||||||
if (EntitlementBootstrap.bootstrapArgs != null) {
|
if (EntitlementBootstrap.bootstrapArgs != null) {
|
||||||
|
@ -109,12 +118,14 @@ public class EntitlementBootstrap {
|
||||||
sharedRepoDirs,
|
sharedRepoDirs,
|
||||||
configDir,
|
configDir,
|
||||||
libDir,
|
libDir,
|
||||||
|
pluginsDir,
|
||||||
logsDir,
|
logsDir,
|
||||||
tempDir
|
tempDir,
|
||||||
|
pidFile,
|
||||||
|
suppressFailureLogClasses
|
||||||
);
|
);
|
||||||
exportInitializationToAgent();
|
exportInitializationToAgent();
|
||||||
loadAgent(findAgentJar());
|
loadAgent(findAgentJar());
|
||||||
selfTest();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressForbidden(reason = "The VirtualMachine API is the only way to attach a java agent dynamically")
|
@SuppressForbidden(reason = "The VirtualMachine API is the only way to attach a java agent dynamically")
|
||||||
|
@ -160,50 +171,5 @@ public class EntitlementBootstrap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt a few sensitive operations to ensure that some are permitted and some are forbidden.
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* This serves two purposes:
|
|
||||||
*
|
|
||||||
* <ol>
|
|
||||||
* <li>
|
|
||||||
* a smoke test to make sure the entitlements system is not completely broken, and
|
|
||||||
* </li>
|
|
||||||
* <li>
|
|
||||||
* an early test of certain important operations so they don't fail later on at an awkward time.
|
|
||||||
* </li>
|
|
||||||
* </ol>
|
|
||||||
*
|
|
||||||
* @throws IllegalStateException if the entitlements system can't prevent an unauthorized action of our choosing
|
|
||||||
*/
|
|
||||||
private static void selfTest() {
|
|
||||||
ensureCannotStartProcess(ProcessBuilder::start);
|
|
||||||
// Try again with reflection
|
|
||||||
ensureCannotStartProcess(EntitlementBootstrap::reflectiveStartProcess);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ensureCannotStartProcess(CheckedConsumer<ProcessBuilder, ?> startProcess) {
|
|
||||||
try {
|
|
||||||
// The command doesn't matter; it doesn't even need to exist
|
|
||||||
startProcess.accept(new ProcessBuilder(""));
|
|
||||||
} catch (NotEntitledException e) {
|
|
||||||
logger.debug("Success: Entitlement protection correctly prevented process creation");
|
|
||||||
return;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IllegalStateException("Failed entitlement protection self-test", e);
|
|
||||||
}
|
|
||||||
throw new IllegalStateException("Entitlement protection self-test was incorrectly permitted");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void reflectiveStartProcess(ProcessBuilder pb) throws Exception {
|
|
||||||
try {
|
|
||||||
var start = ProcessBuilder.class.getMethod("start");
|
|
||||||
start.invoke(pb);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
throw (Exception) e.getCause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger(EntitlementBootstrap.class);
|
private static final Logger logger = LogManager.getLogger(EntitlementBootstrap.class);
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,6 +148,38 @@ public class EntitlementInitialization {
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Scope> serverScopes = new ArrayList<>();
|
List<Scope> serverScopes = new ArrayList<>();
|
||||||
|
List<FileData> serverModuleFileDatas = new ArrayList<>();
|
||||||
|
Collections.addAll(
|
||||||
|
serverModuleFileDatas,
|
||||||
|
// Base ES directories
|
||||||
|
FileData.ofPath(bootstrapArgs.pluginsDir(), READ),
|
||||||
|
FileData.ofPath(bootstrapArgs.configDir(), READ),
|
||||||
|
FileData.ofPath(bootstrapArgs.logsDir(), READ_WRITE),
|
||||||
|
FileData.ofRelativePath(Path.of(""), DATA, READ_WRITE),
|
||||||
|
FileData.ofRelativePath(Path.of(""), SHARED_REPO, READ_WRITE),
|
||||||
|
|
||||||
|
// OS release on Linux
|
||||||
|
FileData.ofPath(Path.of("/etc/os-release"), READ).withPlatform(LINUX),
|
||||||
|
FileData.ofPath(Path.of("/etc/system-release"), READ).withPlatform(LINUX),
|
||||||
|
FileData.ofPath(Path.of("/usr/lib/os-release"), READ).withPlatform(LINUX),
|
||||||
|
// read max virtual memory areas
|
||||||
|
FileData.ofPath(Path.of("/proc/sys/vm/max_map_count"), READ).withPlatform(LINUX),
|
||||||
|
FileData.ofPath(Path.of("/proc/meminfo"), READ).withPlatform(LINUX),
|
||||||
|
// load averages on Linux
|
||||||
|
FileData.ofPath(Path.of("/proc/loadavg"), READ).withPlatform(LINUX),
|
||||||
|
// control group stats on Linux. cgroup v2 stats are in an unpredicable
|
||||||
|
// location under `/sys/fs/cgroup`, so unfortunately we have to allow
|
||||||
|
// read access to the entire directory hierarchy.
|
||||||
|
FileData.ofPath(Path.of("/proc/self/cgroup"), READ).withPlatform(LINUX),
|
||||||
|
FileData.ofPath(Path.of("/sys/fs/cgroup/"), READ).withPlatform(LINUX),
|
||||||
|
// // io stats on Linux
|
||||||
|
FileData.ofPath(Path.of("/proc/self/mountinfo"), READ).withPlatform(LINUX),
|
||||||
|
FileData.ofPath(Path.of("/proc/diskstats"), READ).withPlatform(LINUX)
|
||||||
|
);
|
||||||
|
if (bootstrapArgs.pidFile() != null) {
|
||||||
|
serverModuleFileDatas.add(FileData.ofPath(bootstrapArgs.pidFile(), READ_WRITE));
|
||||||
|
}
|
||||||
|
|
||||||
Collections.addAll(
|
Collections.addAll(
|
||||||
serverScopes,
|
serverScopes,
|
||||||
new Scope(
|
new Scope(
|
||||||
|
@ -156,6 +188,7 @@ public class EntitlementInitialization {
|
||||||
new CreateClassLoaderEntitlement(),
|
new CreateClassLoaderEntitlement(),
|
||||||
new FilesEntitlement(
|
new FilesEntitlement(
|
||||||
List.of(
|
List.of(
|
||||||
|
// TODO: what in es.base is accessing shared repo?
|
||||||
FileData.ofRelativePath(Path.of(""), SHARED_REPO, READ_WRITE),
|
FileData.ofRelativePath(Path.of(""), SHARED_REPO, READ_WRITE),
|
||||||
FileData.ofRelativePath(Path.of(""), DATA, READ_WRITE)
|
FileData.ofRelativePath(Path.of(""), DATA, READ_WRITE)
|
||||||
)
|
)
|
||||||
|
@ -173,34 +206,7 @@ public class EntitlementInitialization {
|
||||||
new OutboundNetworkEntitlement(),
|
new OutboundNetworkEntitlement(),
|
||||||
new LoadNativeLibrariesEntitlement(),
|
new LoadNativeLibrariesEntitlement(),
|
||||||
new ManageThreadsEntitlement(),
|
new ManageThreadsEntitlement(),
|
||||||
new FilesEntitlement(
|
new FilesEntitlement(serverModuleFileDatas)
|
||||||
List.of(
|
|
||||||
// Base ES directories
|
|
||||||
FileData.ofPath(bootstrapArgs.tempDir(), READ_WRITE),
|
|
||||||
FileData.ofPath(bootstrapArgs.configDir(), READ),
|
|
||||||
FileData.ofPath(bootstrapArgs.logsDir(), READ_WRITE),
|
|
||||||
FileData.ofRelativePath(Path.of(""), DATA, READ_WRITE),
|
|
||||||
FileData.ofRelativePath(Path.of(""), SHARED_REPO, READ_WRITE),
|
|
||||||
|
|
||||||
// OS release on Linux
|
|
||||||
FileData.ofPath(Path.of("/etc/os-release"), READ).withPlatform(LINUX),
|
|
||||||
FileData.ofPath(Path.of("/etc/system-release"), READ).withPlatform(LINUX),
|
|
||||||
FileData.ofPath(Path.of("/usr/lib/os-release"), READ).withPlatform(LINUX),
|
|
||||||
// read max virtual memory areas
|
|
||||||
FileData.ofPath(Path.of("/proc/sys/vm/max_map_count"), READ).withPlatform(LINUX),
|
|
||||||
FileData.ofPath(Path.of("/proc/meminfo"), READ).withPlatform(LINUX),
|
|
||||||
// load averages on Linux
|
|
||||||
FileData.ofPath(Path.of("/proc/loadavg"), READ).withPlatform(LINUX),
|
|
||||||
// control group stats on Linux. cgroup v2 stats are in an unpredicable
|
|
||||||
// location under `/sys/fs/cgroup`, so unfortunately we have to allow
|
|
||||||
// read access to the entire directory hierarchy.
|
|
||||||
FileData.ofPath(Path.of("/proc/self/cgroup"), READ).withPlatform(LINUX),
|
|
||||||
FileData.ofPath(Path.of("/sys/fs/cgroup/"), READ).withPlatform(LINUX),
|
|
||||||
// // io stats on Linux
|
|
||||||
FileData.ofPath(Path.of("/proc/self/mountinfo"), READ).withPlatform(LINUX),
|
|
||||||
FileData.ofPath(Path.of("/proc/diskstats"), READ).withPlatform(LINUX)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
new Scope("org.apache.httpcomponents.httpclient", List.of(new OutboundNetworkEntitlement())),
|
new Scope("org.apache.httpcomponents.httpclient", List.of(new OutboundNetworkEntitlement())),
|
||||||
|
@ -211,11 +217,7 @@ public class EntitlementInitialization {
|
||||||
new LoadNativeLibrariesEntitlement(),
|
new LoadNativeLibrariesEntitlement(),
|
||||||
new ManageThreadsEntitlement(),
|
new ManageThreadsEntitlement(),
|
||||||
new FilesEntitlement(
|
new FilesEntitlement(
|
||||||
List.of(
|
List.of(FileData.ofPath(bootstrapArgs.configDir(), READ), FileData.ofRelativePath(Path.of(""), DATA, READ_WRITE))
|
||||||
FileData.ofPath(bootstrapArgs.configDir(), READ),
|
|
||||||
FileData.ofPath(bootstrapArgs.tempDir(), READ),
|
|
||||||
FileData.ofRelativePath(Path.of(""), DATA, READ_WRITE)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
@ -223,7 +225,10 @@ public class EntitlementInitialization {
|
||||||
"org.apache.lucene.misc",
|
"org.apache.lucene.misc",
|
||||||
List.of(new FilesEntitlement(List.of(FileData.ofRelativePath(Path.of(""), DATA, READ_WRITE))))
|
List.of(new FilesEntitlement(List.of(FileData.ofRelativePath(Path.of(""), DATA, READ_WRITE))))
|
||||||
),
|
),
|
||||||
new Scope("org.apache.logging.log4j.core", List.of(new ManageThreadsEntitlement())),
|
new Scope(
|
||||||
|
"org.apache.logging.log4j.core",
|
||||||
|
List.of(new ManageThreadsEntitlement(), new FilesEntitlement(List.of(FileData.ofPath(bootstrapArgs.logsDir(), READ_WRITE))))
|
||||||
|
),
|
||||||
new Scope(
|
new Scope(
|
||||||
"org.elasticsearch.nativeaccess",
|
"org.elasticsearch.nativeaccess",
|
||||||
List.of(
|
List.of(
|
||||||
|
@ -256,7 +261,9 @@ public class EntitlementInitialization {
|
||||||
new FilesEntitlement(
|
new FilesEntitlement(
|
||||||
List.of(
|
List.of(
|
||||||
FileData.ofPath(Path.of("/co/elastic/apm/agent/"), READ),
|
FileData.ofPath(Path.of("/co/elastic/apm/agent/"), READ),
|
||||||
FileData.ofPath(Path.of("/agent/co/elastic/apm/agent/"), READ)
|
FileData.ofPath(Path.of("/agent/co/elastic/apm/agent/"), READ),
|
||||||
|
FileData.ofPath(Path.of("/proc/meminfo"), READ),
|
||||||
|
FileData.ofPath(Path.of("/sys/fs/cgroup/"), READ)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -268,7 +275,8 @@ public class EntitlementInitialization {
|
||||||
resolver,
|
resolver,
|
||||||
AGENTS_PACKAGE_NAME,
|
AGENTS_PACKAGE_NAME,
|
||||||
ENTITLEMENTS_MODULE,
|
ENTITLEMENTS_MODULE,
|
||||||
pathLookup
|
pathLookup,
|
||||||
|
bootstrapArgs.suppressFailureLogClasses()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,18 +10,27 @@
|
||||||
package org.elasticsearch.entitlement.runtime.policy;
|
package org.elasticsearch.entitlement.runtime.policy;
|
||||||
|
|
||||||
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement;
|
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement;
|
||||||
|
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode;
|
||||||
|
import org.elasticsearch.logging.LogManager;
|
||||||
|
import org.elasticsearch.logging.Logger;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
import static org.elasticsearch.core.PathUtils.getDefaultFileSystem;
|
import static org.elasticsearch.core.PathUtils.getDefaultFileSystem;
|
||||||
|
|
||||||
public final class FileAccessTree {
|
public final class FileAccessTree {
|
||||||
|
|
||||||
|
private static final Logger logger = LogManager.getLogger(FileAccessTree.class);
|
||||||
private static final String FILE_SEPARATOR = getDefaultFileSystem().getSeparator();
|
private static final String FILE_SEPARATOR = getDefaultFileSystem().getSeparator();
|
||||||
|
|
||||||
private final String[] readPaths;
|
private final String[] readPaths;
|
||||||
|
@ -30,6 +39,27 @@ public final class FileAccessTree {
|
||||||
private FileAccessTree(FilesEntitlement filesEntitlement, PathLookup pathLookup) {
|
private FileAccessTree(FilesEntitlement filesEntitlement, PathLookup pathLookup) {
|
||||||
List<String> readPaths = new ArrayList<>();
|
List<String> readPaths = new ArrayList<>();
|
||||||
List<String> writePaths = new ArrayList<>();
|
List<String> writePaths = new ArrayList<>();
|
||||||
|
BiConsumer<Path, Mode> addPath = (path, mode) -> {
|
||||||
|
var normalized = normalizePath(path);
|
||||||
|
if (mode == Mode.READ_WRITE) {
|
||||||
|
writePaths.add(normalized);
|
||||||
|
}
|
||||||
|
readPaths.add(normalized);
|
||||||
|
};
|
||||||
|
BiConsumer<Path, Mode> addPathAndMaybeLink = (path, mode) -> {
|
||||||
|
addPath.accept(path, mode);
|
||||||
|
// also try to follow symlinks. Lucene does this and writes to the target path.
|
||||||
|
if (Files.exists(path)) {
|
||||||
|
try {
|
||||||
|
Path realPath = path.toRealPath();
|
||||||
|
if (realPath.equals(path) == false) {
|
||||||
|
addPath.accept(realPath, mode);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
for (FilesEntitlement.FileData fileData : filesEntitlement.filesData()) {
|
for (FilesEntitlement.FileData fileData : filesEntitlement.filesData()) {
|
||||||
var platform = fileData.platform();
|
var platform = fileData.platform();
|
||||||
if (platform != null && platform.isCurrent() == false) {
|
if (platform != null && platform.isCurrent() == false) {
|
||||||
|
@ -38,18 +68,20 @@ public final class FileAccessTree {
|
||||||
var mode = fileData.mode();
|
var mode = fileData.mode();
|
||||||
var paths = fileData.resolvePaths(pathLookup);
|
var paths = fileData.resolvePaths(pathLookup);
|
||||||
paths.forEach(path -> {
|
paths.forEach(path -> {
|
||||||
var normalized = normalizePath(path);
|
if (path == null) {
|
||||||
if (mode == FilesEntitlement.Mode.READ_WRITE) {
|
// TODO: null paths shouldn't be allowed, but they can occur due to repo paths
|
||||||
writePaths.add(normalized);
|
return;
|
||||||
}
|
}
|
||||||
readPaths.add(normalized);
|
addPathAndMaybeLink.accept(path, mode);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// everything has access to the temp dir
|
// everything has access to the temp dir and the jdk
|
||||||
String tempDir = normalizePath(pathLookup.tempDir());
|
addPathAndMaybeLink.accept(pathLookup.tempDir(), Mode.READ_WRITE);
|
||||||
readPaths.add(tempDir);
|
|
||||||
writePaths.add(tempDir);
|
// TODO: watcher uses javax.activation which looks for known mime types configuration, should this be global or explicit in watcher?
|
||||||
|
Path jdk = Paths.get(System.getProperty("java.home"));
|
||||||
|
addPathAndMaybeLink.accept(jdk.resolve("conf"), Mode.READ);
|
||||||
|
|
||||||
readPaths.sort(PATH_ORDER);
|
readPaths.sort(PATH_ORDER);
|
||||||
writePaths.sort(PATH_ORDER);
|
writePaths.sort(PATH_ORDER);
|
||||||
|
|
|
@ -11,8 +11,6 @@ package org.elasticsearch.entitlement.runtime.policy;
|
||||||
|
|
||||||
import org.elasticsearch.core.Strings;
|
import org.elasticsearch.core.Strings;
|
||||||
import org.elasticsearch.core.SuppressForbidden;
|
import org.elasticsearch.core.SuppressForbidden;
|
||||||
import org.elasticsearch.entitlement.bootstrap.EntitlementBootstrap;
|
|
||||||
import org.elasticsearch.entitlement.bridge.EntitlementChecker;
|
|
||||||
import org.elasticsearch.entitlement.instrumentation.InstrumentationService;
|
import org.elasticsearch.entitlement.instrumentation.InstrumentationService;
|
||||||
import org.elasticsearch.entitlement.runtime.api.NotEntitledException;
|
import org.elasticsearch.entitlement.runtime.api.NotEntitledException;
|
||||||
import org.elasticsearch.entitlement.runtime.policy.entitlements.CreateClassLoaderEntitlement;
|
import org.elasticsearch.entitlement.runtime.policy.entitlements.CreateClassLoaderEntitlement;
|
||||||
|
@ -115,6 +113,7 @@ public class PolicyManager {
|
||||||
private final Function<Class<?>, String> pluginResolver;
|
private final Function<Class<?>, String> pluginResolver;
|
||||||
private final PathLookup pathLookup;
|
private final PathLookup pathLookup;
|
||||||
private final FileAccessTree defaultFileAccess;
|
private final FileAccessTree defaultFileAccess;
|
||||||
|
private final Set<Class<?>> mutedClasses;
|
||||||
|
|
||||||
public static final String ALL_UNNAMED = "ALL-UNNAMED";
|
public static final String ALL_UNNAMED = "ALL-UNNAMED";
|
||||||
|
|
||||||
|
@ -126,11 +125,12 @@ public class PolicyManager {
|
||||||
.stream()
|
.stream()
|
||||||
.map(ModuleReference::descriptor)
|
.map(ModuleReference::descriptor)
|
||||||
.collect(Collectors.toUnmodifiableSet());
|
.collect(Collectors.toUnmodifiableSet());
|
||||||
return ModuleLayer.boot()
|
return Stream.concat(
|
||||||
.modules()
|
// entitlements is a "system" module, we can do anything from it
|
||||||
.stream()
|
Stream.of(PolicyManager.class.getModule()),
|
||||||
.filter(m -> systemModulesDescriptors.contains(m.getDescriptor()))
|
// anything in the boot layer is also part of the system
|
||||||
.collect(Collectors.toUnmodifiableSet());
|
ModuleLayer.boot().modules().stream().filter(m -> systemModulesDescriptors.contains(m.getDescriptor()))
|
||||||
|
).collect(Collectors.toUnmodifiableSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -150,7 +150,8 @@ public class PolicyManager {
|
||||||
Function<Class<?>, String> pluginResolver,
|
Function<Class<?>, String> pluginResolver,
|
||||||
String apmAgentPackageName,
|
String apmAgentPackageName,
|
||||||
Module entitlementsModule,
|
Module entitlementsModule,
|
||||||
PathLookup pathLookup
|
PathLookup pathLookup,
|
||||||
|
Set<Class<?>> suppressFailureLogClasses
|
||||||
) {
|
) {
|
||||||
this.serverEntitlements = buildScopeEntitlementsMap(requireNonNull(serverPolicy));
|
this.serverEntitlements = buildScopeEntitlementsMap(requireNonNull(serverPolicy));
|
||||||
this.apmAgentEntitlements = apmAgentEntitlements;
|
this.apmAgentEntitlements = apmAgentEntitlements;
|
||||||
|
@ -162,6 +163,7 @@ public class PolicyManager {
|
||||||
this.entitlementsModule = entitlementsModule;
|
this.entitlementsModule = entitlementsModule;
|
||||||
this.pathLookup = requireNonNull(pathLookup);
|
this.pathLookup = requireNonNull(pathLookup);
|
||||||
this.defaultFileAccess = FileAccessTree.of(FilesEntitlement.EMPTY, pathLookup);
|
this.defaultFileAccess = FileAccessTree.of(FilesEntitlement.EMPTY, pathLookup);
|
||||||
|
this.mutedClasses = suppressFailureLogClasses;
|
||||||
|
|
||||||
for (var e : serverEntitlements.entrySet()) {
|
for (var e : serverEntitlements.entrySet()) {
|
||||||
validateEntitlementsPerModule(SERVER_COMPONENT_NAME, e.getKey(), e.getValue());
|
validateEntitlementsPerModule(SERVER_COMPONENT_NAME, e.getKey(), e.getValue());
|
||||||
|
@ -386,7 +388,7 @@ public class PolicyManager {
|
||||||
checkFlagEntitlement(classEntitlements, OutboundNetworkEntitlement.class, requestingClass, callerClass);
|
checkFlagEntitlement(classEntitlements, OutboundNetworkEntitlement.class, requestingClass, callerClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkFlagEntitlement(
|
private void checkFlagEntitlement(
|
||||||
ModuleEntitlements classEntitlements,
|
ModuleEntitlements classEntitlements,
|
||||||
Class<? extends Entitlement> entitlementClass,
|
Class<? extends Entitlement> entitlementClass,
|
||||||
Class<?> requestingClass,
|
Class<?> requestingClass,
|
||||||
|
@ -446,10 +448,10 @@ public class PolicyManager {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void notEntitled(String message, Class<?> callerClass) {
|
private void notEntitled(String message, Class<?> callerClass) {
|
||||||
var exception = new NotEntitledException(message);
|
var exception = new NotEntitledException(message);
|
||||||
// don't log self tests in EntitlementBootstrap
|
// Don't emit a log for muted classes, e.g. classes containing self tests
|
||||||
if (EntitlementBootstrap.class.equals(callerClass) == false) {
|
if (mutedClasses.contains(callerClass) == false) {
|
||||||
logger.warn(message, exception);
|
logger.warn(message, exception);
|
||||||
}
|
}
|
||||||
throw exception;
|
throw exception;
|
||||||
|
@ -564,10 +566,6 @@ public class PolicyManager {
|
||||||
logger.debug("Entitlement trivially allowed from system module [{}]", requestingClass.getModule().getName());
|
logger.debug("Entitlement trivially allowed from system module [{}]", requestingClass.getModule().getName());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (EntitlementChecker.class.isAssignableFrom(requestingClass)) {
|
|
||||||
logger.debug("Entitlement trivially allowed for EntitlementChecker class");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
logger.trace("Entitlement not trivially allowed");
|
logger.trace("Entitlement not trivially allowed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,15 @@
|
||||||
package org.elasticsearch.entitlement.runtime.policy;
|
package org.elasticsearch.entitlement.runtime.policy;
|
||||||
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.core.SuppressForbidden;
|
||||||
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement;
|
import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -23,6 +27,7 @@ import java.util.Map;
|
||||||
import static org.elasticsearch.core.PathUtils.getDefaultFileSystem;
|
import static org.elasticsearch.core.PathUtils.getDefaultFileSystem;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
|
|
||||||
|
@ESTestCase.WithoutSecurityManager
|
||||||
public class FileAccessTreeTests extends ESTestCase {
|
public class FileAccessTreeTests extends ESTestCase {
|
||||||
|
|
||||||
static Path root;
|
static Path root;
|
||||||
|
@ -211,6 +216,45 @@ public class FileAccessTreeTests extends ESTestCase {
|
||||||
assertThat(tree.canRead(path("m/n")), is(true));
|
assertThat(tree.canRead(path("m/n")), is(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testJdkAccess() {
|
||||||
|
Path jdkDir = Paths.get(System.getProperty("java.home"));
|
||||||
|
var confDir = jdkDir.resolve("conf");
|
||||||
|
var tree = accessTree(FilesEntitlement.EMPTY);
|
||||||
|
|
||||||
|
assertThat(tree.canRead(confDir), is(true));
|
||||||
|
assertThat(tree.canWrite(confDir), is(false));
|
||||||
|
assertThat(tree.canRead(jdkDir), is(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressForbidden(reason = "don't care about the directory location in tests")
|
||||||
|
public void testFollowLinks() throws IOException {
|
||||||
|
Path baseSourceDir = Files.createTempDirectory("fileaccess_source");
|
||||||
|
Path source1Dir = baseSourceDir.resolve("source1");
|
||||||
|
Files.createDirectory(source1Dir);
|
||||||
|
Path source2Dir = baseSourceDir.resolve("source2");
|
||||||
|
Files.createDirectory(source2Dir);
|
||||||
|
|
||||||
|
Path baseTargetDir = Files.createTempDirectory("fileaccess_target");
|
||||||
|
Path readTarget = baseTargetDir.resolve("read_link");
|
||||||
|
Path writeTarget = baseTargetDir.resolve("write_link");
|
||||||
|
Files.createSymbolicLink(readTarget, source1Dir);
|
||||||
|
Files.createSymbolicLink(writeTarget, source2Dir);
|
||||||
|
var tree = accessTree(entitlement(readTarget.toString(), "read", writeTarget.toString(), "read_write"));
|
||||||
|
|
||||||
|
assertThat(tree.canRead(baseSourceDir), is(false));
|
||||||
|
assertThat(tree.canRead(baseTargetDir), is(false));
|
||||||
|
|
||||||
|
assertThat(tree.canRead(readTarget), is(true));
|
||||||
|
assertThat(tree.canWrite(readTarget), is(false));
|
||||||
|
assertThat(tree.canRead(source1Dir), is(true));
|
||||||
|
assertThat(tree.canWrite(source1Dir), is(false));
|
||||||
|
|
||||||
|
assertThat(tree.canRead(writeTarget), is(true));
|
||||||
|
assertThat(tree.canWrite(writeTarget), is(true));
|
||||||
|
assertThat(tree.canRead(source2Dir), is(true));
|
||||||
|
assertThat(tree.canWrite(source2Dir), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
public void testTempDirAccess() {
|
public void testTempDirAccess() {
|
||||||
var tree = FileAccessTree.of(FilesEntitlement.EMPTY, TEST_PATH_LOOKUP);
|
var tree = FileAccessTree.of(FilesEntitlement.EMPTY, TEST_PATH_LOOKUP);
|
||||||
assertThat(tree.canRead(TEST_PATH_LOOKUP.tempDir()), is(true));
|
assertThat(tree.canRead(TEST_PATH_LOOKUP.tempDir()), is(true));
|
||||||
|
|
|
@ -87,7 +87,8 @@ public class PolicyManagerTests extends ESTestCase {
|
||||||
c -> "plugin1",
|
c -> "plugin1",
|
||||||
TEST_AGENTS_PACKAGE_NAME,
|
TEST_AGENTS_PACKAGE_NAME,
|
||||||
NO_ENTITLEMENTS_MODULE,
|
NO_ENTITLEMENTS_MODULE,
|
||||||
TEST_PATH_LOOKUP
|
TEST_PATH_LOOKUP,
|
||||||
|
Set.of()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Any class from the current module (unnamed) will do
|
// Any class from the current module (unnamed) will do
|
||||||
|
@ -111,7 +112,8 @@ public class PolicyManagerTests extends ESTestCase {
|
||||||
c -> "plugin1",
|
c -> "plugin1",
|
||||||
TEST_AGENTS_PACKAGE_NAME,
|
TEST_AGENTS_PACKAGE_NAME,
|
||||||
NO_ENTITLEMENTS_MODULE,
|
NO_ENTITLEMENTS_MODULE,
|
||||||
TEST_PATH_LOOKUP
|
TEST_PATH_LOOKUP,
|
||||||
|
Set.of()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Any class from the current module (unnamed) will do
|
// Any class from the current module (unnamed) will do
|
||||||
|
@ -131,7 +133,8 @@ public class PolicyManagerTests extends ESTestCase {
|
||||||
c -> "plugin1",
|
c -> "plugin1",
|
||||||
TEST_AGENTS_PACKAGE_NAME,
|
TEST_AGENTS_PACKAGE_NAME,
|
||||||
NO_ENTITLEMENTS_MODULE,
|
NO_ENTITLEMENTS_MODULE,
|
||||||
TEST_PATH_LOOKUP
|
TEST_PATH_LOOKUP,
|
||||||
|
Set.of()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Any class from the current module (unnamed) will do
|
// Any class from the current module (unnamed) will do
|
||||||
|
@ -156,7 +159,8 @@ public class PolicyManagerTests extends ESTestCase {
|
||||||
c -> "plugin2",
|
c -> "plugin2",
|
||||||
TEST_AGENTS_PACKAGE_NAME,
|
TEST_AGENTS_PACKAGE_NAME,
|
||||||
NO_ENTITLEMENTS_MODULE,
|
NO_ENTITLEMENTS_MODULE,
|
||||||
TEST_PATH_LOOKUP
|
TEST_PATH_LOOKUP,
|
||||||
|
Set.of()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Any class from the current module (unnamed) will do
|
// Any class from the current module (unnamed) will do
|
||||||
|
@ -174,7 +178,8 @@ public class PolicyManagerTests extends ESTestCase {
|
||||||
c -> null,
|
c -> null,
|
||||||
TEST_AGENTS_PACKAGE_NAME,
|
TEST_AGENTS_PACKAGE_NAME,
|
||||||
NO_ENTITLEMENTS_MODULE,
|
NO_ENTITLEMENTS_MODULE,
|
||||||
TEST_PATH_LOOKUP
|
TEST_PATH_LOOKUP,
|
||||||
|
Set.of()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Tests do not run modular, so we cannot use a server class.
|
// Tests do not run modular, so we cannot use a server class.
|
||||||
|
@ -204,7 +209,8 @@ public class PolicyManagerTests extends ESTestCase {
|
||||||
c -> null,
|
c -> null,
|
||||||
TEST_AGENTS_PACKAGE_NAME,
|
TEST_AGENTS_PACKAGE_NAME,
|
||||||
NO_ENTITLEMENTS_MODULE,
|
NO_ENTITLEMENTS_MODULE,
|
||||||
TEST_PATH_LOOKUP
|
TEST_PATH_LOOKUP,
|
||||||
|
Set.of()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Tests do not run modular, so we cannot use a server class.
|
// Tests do not run modular, so we cannot use a server class.
|
||||||
|
@ -230,7 +236,8 @@ public class PolicyManagerTests extends ESTestCase {
|
||||||
c -> "mock-plugin",
|
c -> "mock-plugin",
|
||||||
TEST_AGENTS_PACKAGE_NAME,
|
TEST_AGENTS_PACKAGE_NAME,
|
||||||
NO_ENTITLEMENTS_MODULE,
|
NO_ENTITLEMENTS_MODULE,
|
||||||
TEST_PATH_LOOKUP
|
TEST_PATH_LOOKUP,
|
||||||
|
Set.of()
|
||||||
);
|
);
|
||||||
|
|
||||||
var layer = createLayerForJar(jar, "org.example.plugin");
|
var layer = createLayerForJar(jar, "org.example.plugin");
|
||||||
|
@ -249,7 +256,8 @@ public class PolicyManagerTests extends ESTestCase {
|
||||||
c -> "plugin2",
|
c -> "plugin2",
|
||||||
TEST_AGENTS_PACKAGE_NAME,
|
TEST_AGENTS_PACKAGE_NAME,
|
||||||
NO_ENTITLEMENTS_MODULE,
|
NO_ENTITLEMENTS_MODULE,
|
||||||
TEST_PATH_LOOKUP
|
TEST_PATH_LOOKUP,
|
||||||
|
Set.of()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Any class from the current module (unnamed) will do
|
// Any class from the current module (unnamed) will do
|
||||||
|
@ -308,7 +316,8 @@ public class PolicyManagerTests extends ESTestCase {
|
||||||
c -> c.getPackageName().startsWith(TEST_AGENTS_PACKAGE_NAME) ? null : "test",
|
c -> c.getPackageName().startsWith(TEST_AGENTS_PACKAGE_NAME) ? null : "test",
|
||||||
TEST_AGENTS_PACKAGE_NAME,
|
TEST_AGENTS_PACKAGE_NAME,
|
||||||
NO_ENTITLEMENTS_MODULE,
|
NO_ENTITLEMENTS_MODULE,
|
||||||
TEST_PATH_LOOKUP
|
TEST_PATH_LOOKUP,
|
||||||
|
Set.of()
|
||||||
);
|
);
|
||||||
ModuleEntitlements agentsEntitlements = policyManager.getEntitlements(TestAgent.class);
|
ModuleEntitlements agentsEntitlements = policyManager.getEntitlements(TestAgent.class);
|
||||||
assertThat(agentsEntitlements.hasEntitlement(CreateClassLoaderEntitlement.class), is(true));
|
assertThat(agentsEntitlements.hasEntitlement(CreateClassLoaderEntitlement.class), is(true));
|
||||||
|
@ -336,7 +345,8 @@ public class PolicyManagerTests extends ESTestCase {
|
||||||
c -> "test",
|
c -> "test",
|
||||||
TEST_AGENTS_PACKAGE_NAME,
|
TEST_AGENTS_PACKAGE_NAME,
|
||||||
NO_ENTITLEMENTS_MODULE,
|
NO_ENTITLEMENTS_MODULE,
|
||||||
TEST_PATH_LOOKUP
|
TEST_PATH_LOOKUP,
|
||||||
|
Set.of()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
@ -353,7 +363,8 @@ public class PolicyManagerTests extends ESTestCase {
|
||||||
c -> "test",
|
c -> "test",
|
||||||
TEST_AGENTS_PACKAGE_NAME,
|
TEST_AGENTS_PACKAGE_NAME,
|
||||||
NO_ENTITLEMENTS_MODULE,
|
NO_ENTITLEMENTS_MODULE,
|
||||||
TEST_PATH_LOOKUP
|
TEST_PATH_LOOKUP,
|
||||||
|
Set.of()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
@ -387,7 +398,8 @@ public class PolicyManagerTests extends ESTestCase {
|
||||||
c -> "plugin1",
|
c -> "plugin1",
|
||||||
TEST_AGENTS_PACKAGE_NAME,
|
TEST_AGENTS_PACKAGE_NAME,
|
||||||
NO_ENTITLEMENTS_MODULE,
|
NO_ENTITLEMENTS_MODULE,
|
||||||
TEST_PATH_LOOKUP
|
TEST_PATH_LOOKUP,
|
||||||
|
Set.of()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
@ -407,7 +419,8 @@ public class PolicyManagerTests extends ESTestCase {
|
||||||
c -> "test", // Insist that the class is in a plugin
|
c -> "test", // Insist that the class is in a plugin
|
||||||
TEST_AGENTS_PACKAGE_NAME,
|
TEST_AGENTS_PACKAGE_NAME,
|
||||||
NO_ENTITLEMENTS_MODULE,
|
NO_ENTITLEMENTS_MODULE,
|
||||||
TEST_PATH_LOOKUP
|
TEST_PATH_LOOKUP,
|
||||||
|
Set.of()
|
||||||
);
|
);
|
||||||
ModuleEntitlements notAgentsEntitlements = policyManager.getEntitlements(TestAgent.class);
|
ModuleEntitlements notAgentsEntitlements = policyManager.getEntitlements(TestAgent.class);
|
||||||
assertThat(notAgentsEntitlements.hasEntitlement(CreateClassLoaderEntitlement.class), is(false));
|
assertThat(notAgentsEntitlements.hasEntitlement(CreateClassLoaderEntitlement.class), is(false));
|
||||||
|
@ -428,7 +441,8 @@ public class PolicyManagerTests extends ESTestCase {
|
||||||
c -> "test",
|
c -> "test",
|
||||||
agentsPackageName,
|
agentsPackageName,
|
||||||
entitlementsModule,
|
entitlementsModule,
|
||||||
TEST_PATH_LOOKUP
|
TEST_PATH_LOOKUP,
|
||||||
|
Set.of()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
org.elasticsearch.script.expression:
|
org.apache.lucene.expressions:
|
||||||
- create_class_loader
|
- create_class_loader
|
||||||
|
|
|
@ -257,9 +257,6 @@ tests:
|
||||||
- class: org.elasticsearch.test.rest.ClientYamlTestSuiteIT
|
- class: org.elasticsearch.test.rest.ClientYamlTestSuiteIT
|
||||||
method: test {yaml=snapshot.delete/10_basic/Delete a snapshot asynchronously}
|
method: test {yaml=snapshot.delete/10_basic/Delete a snapshot asynchronously}
|
||||||
issue: https://github.com/elastic/elasticsearch/issues/122102
|
issue: https://github.com/elastic/elasticsearch/issues/122102
|
||||||
- class: org.elasticsearch.search.SearchCancellationIT
|
|
||||||
method: testCancelFailedSearchWhenPartialResultDisallowed
|
|
||||||
issue: https://github.com/elastic/elasticsearch/issues/121719
|
|
||||||
- class: org.elasticsearch.datastreams.TSDBPassthroughIndexingIT
|
- class: org.elasticsearch.datastreams.TSDBPassthroughIndexingIT
|
||||||
issue: https://github.com/elastic/elasticsearch/issues/121716
|
issue: https://github.com/elastic/elasticsearch/issues/121716
|
||||||
- class: org.elasticsearch.smoketest.SmokeTestMonitoringWithSecurityIT
|
- class: org.elasticsearch.smoketest.SmokeTestMonitoringWithSecurityIT
|
||||||
|
@ -298,8 +295,6 @@ tests:
|
||||||
- class: org.elasticsearch.search.basic.SearchWithRandomDisconnectsIT
|
- class: org.elasticsearch.search.basic.SearchWithRandomDisconnectsIT
|
||||||
method: testSearchWithRandomDisconnects
|
method: testSearchWithRandomDisconnects
|
||||||
issue: https://github.com/elastic/elasticsearch/issues/122707
|
issue: https://github.com/elastic/elasticsearch/issues/122707
|
||||||
- class: org.elasticsearch.xpack.esql.action.EsqlActionBreakerIT
|
|
||||||
issue: https://github.com/elastic/elasticsearch/issues/122810
|
|
||||||
- class: org.elasticsearch.snapshots.DedicatedClusterSnapshotRestoreIT
|
- class: org.elasticsearch.snapshots.DedicatedClusterSnapshotRestoreIT
|
||||||
method: testRestoreShrinkIndex
|
method: testRestoreShrinkIndex
|
||||||
issue: https://github.com/elastic/elasticsearch/issues/121717
|
issue: https://github.com/elastic/elasticsearch/issues/121717
|
||||||
|
@ -318,9 +313,6 @@ tests:
|
||||||
- class: org.elasticsearch.repositories.gcs.GoogleCloudStorageServiceTests
|
- class: org.elasticsearch.repositories.gcs.GoogleCloudStorageServiceTests
|
||||||
method: testClientsAreNotSharedAcrossRepositories
|
method: testClientsAreNotSharedAcrossRepositories
|
||||||
issue: https://github.com/elastic/elasticsearch/issues/123090
|
issue: https://github.com/elastic/elasticsearch/issues/123090
|
||||||
- class: org.elasticsearch.xpack.esql.action.EnrichIT
|
|
||||||
method: testAvgDurationByArtist
|
|
||||||
issue: https://github.com/elastic/elasticsearch/issues/123093
|
|
||||||
- class: org.elasticsearch.smoketest.DocsClientYamlTestSuiteIT
|
- class: org.elasticsearch.smoketest.DocsClientYamlTestSuiteIT
|
||||||
method: test {yaml=reference/troubleshooting/common-issues/disk-usage-exceeded/line_65}
|
method: test {yaml=reference/troubleshooting/common-issues/disk-usage-exceeded/line_65}
|
||||||
issue: https://github.com/elastic/elasticsearch/issues/123094
|
issue: https://github.com/elastic/elasticsearch/issues/123094
|
||||||
|
@ -345,6 +337,21 @@ tests:
|
||||||
- class: org.elasticsearch.action.admin.indices.diskusage.IndexDiskUsageAnalyzerTests
|
- class: org.elasticsearch.action.admin.indices.diskusage.IndexDiskUsageAnalyzerTests
|
||||||
method: testCompletionField
|
method: testCompletionField
|
||||||
issue: https://github.com/elastic/elasticsearch/issues/123269
|
issue: https://github.com/elastic/elasticsearch/issues/123269
|
||||||
|
- class: org.elasticsearch.index.mapper.IPSyntheticSourceNativeArrayIntegrationTests
|
||||||
|
method: testSynthesizeArray
|
||||||
|
issue: https://github.com/elastic/elasticsearch/issues/123417
|
||||||
|
- class: org.elasticsearch.index.mapper.IPSyntheticSourceNativeArrayIntegrationTests
|
||||||
|
method: testSynthesizeArrayRandom
|
||||||
|
issue: https://github.com/elastic/elasticsearch/issues/123418
|
||||||
|
- class: org.elasticsearch.index.mapper.IPSyntheticSourceNativeArrayIntegrationTests
|
||||||
|
method: testSynthesizeArrayIgnoreMalformed
|
||||||
|
issue: https://github.com/elastic/elasticsearch/issues/123419
|
||||||
|
- class: org.elasticsearch.packaging.test.DockerTests
|
||||||
|
method: test151MachineDependentHeapWithSizeOverride
|
||||||
|
issue: https://github.com/elastic/elasticsearch/issues/123437
|
||||||
|
- class: org.elasticsearch.xpack.esql.action.CrossClusterQueryWithPartialResultsIT
|
||||||
|
method: testOneRemoteClusterPartial
|
||||||
|
issue: https://github.com/elastic/elasticsearch/issues/123451
|
||||||
|
|
||||||
# Examples:
|
# Examples:
|
||||||
#
|
#
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
},
|
},
|
||||||
"stability": "experimental",
|
"stability": "experimental",
|
||||||
"visibility": "public",
|
"visibility": "public",
|
||||||
|
"deprecated": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"description": "Behavioral Analytics has been deprecated and will be removed in a future release."
|
||||||
|
},
|
||||||
"headers": {
|
"headers": {
|
||||||
"accept": [
|
"accept": [
|
||||||
"application/json"
|
"application/json"
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
},
|
},
|
||||||
"stability": "experimental",
|
"stability": "experimental",
|
||||||
"visibility": "public",
|
"visibility": "public",
|
||||||
|
"deprecated": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"description": "Behavioral Analytics has been deprecated and will be removed in a future release."
|
||||||
|
},
|
||||||
"headers": {
|
"headers": {
|
||||||
"accept": [
|
"accept": [
|
||||||
"application/json"
|
"application/json"
|
||||||
|
@ -24,10 +28,10 @@
|
||||||
"methods": [
|
"methods": [
|
||||||
"GET"
|
"GET"
|
||||||
],
|
],
|
||||||
"parts":{
|
"parts": {
|
||||||
"name":{
|
"name": {
|
||||||
"type":"list",
|
"type": "list",
|
||||||
"description":"A comma-separated list of analytics collections to limit the returned information"
|
"description": "A comma-separated list of analytics collections to limit the returned information"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
},
|
},
|
||||||
"stability": "experimental",
|
"stability": "experimental",
|
||||||
"visibility": "public",
|
"visibility": "public",
|
||||||
|
"deprecated": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"description": "Behavioral Analytics has been deprecated and will be removed in a future release."
|
||||||
|
},
|
||||||
"headers": {
|
"headers": {
|
||||||
"accept": [
|
"accept": [
|
||||||
"application/json"
|
"application/json"
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
"description": "Creates a behavioral analytics collection."
|
"description": "Creates a behavioral analytics collection."
|
||||||
},
|
},
|
||||||
"stability": "experimental",
|
"stability": "experimental",
|
||||||
|
"deprecated": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"description": "Behavioral Analytics has been deprecated and will be removed in a future release."
|
||||||
|
},
|
||||||
"visibility": "public",
|
"visibility": "public",
|
||||||
"headers": {
|
"headers": {
|
||||||
"accept": [
|
"accept": [
|
||||||
|
|
|
@ -267,7 +267,7 @@ public class SearchCancellationIT extends AbstractSearchCancellationTestCase {
|
||||||
if (letOneShardProceed.compareAndSet(false, true)) {
|
if (letOneShardProceed.compareAndSet(false, true)) {
|
||||||
// Let one shard continue.
|
// Let one shard continue.
|
||||||
} else {
|
} else {
|
||||||
safeAwait(shardTaskLatch); // Block the other shards.
|
safeAwait(shardTaskLatch, TimeValue.timeValueSeconds(30)); // Block the other shards.
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,7 +275,7 @@ public class TransportVersions {
|
||||||
* Reference to the earliest compatible transport version to this version of the codebase.
|
* Reference to the earliest compatible transport version to this version of the codebase.
|
||||||
* This should be the transport version used by the highest minor version of the previous major.
|
* This should be the transport version used by the highest minor version of the previous major.
|
||||||
*/
|
*/
|
||||||
public static final TransportVersion MINIMUM_COMPATIBLE = BYTE_SIZE_VALUE_ALWAYS_USES_BYTES_1;
|
public static final TransportVersion MINIMUM_COMPATIBLE = INITIAL_ELASTICSEARCH_8_19;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reference to the minimum transport version that can be used with CCS.
|
* Reference to the minimum transport version that can be used with CCS.
|
||||||
|
|
|
@ -92,6 +92,7 @@ public class TransportGetDesiredBalanceAction extends TransportMasterNodeReadAct
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var clusterInfo = clusterInfoService.getClusterInfo();
|
var clusterInfo = clusterInfoService.getClusterInfo();
|
||||||
|
writeLoadForecaster.refreshLicense();
|
||||||
listener.onResponse(
|
listener.onResponse(
|
||||||
new DesiredBalanceResponse(
|
new DesiredBalanceResponse(
|
||||||
desiredBalanceShardsAllocator.getStats(),
|
desiredBalanceShardsAllocator.getStats(),
|
||||||
|
|
|
@ -450,6 +450,7 @@ public class MetadataRolloverService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeLoadForecaster.refreshLicense();
|
||||||
metadataBuilder = writeLoadForecaster.withWriteLoadForecastForWriteIndex(dataStreamName, metadataBuilder);
|
metadataBuilder = writeLoadForecaster.withWriteLoadForecastForWriteIndex(dataStreamName, metadataBuilder);
|
||||||
metadataBuilder = withShardSizeForecastForWriteIndex(dataStreamName, metadataBuilder);
|
metadataBuilder = withShardSizeForecastForWriteIndex(dataStreamName, metadataBuilder);
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,11 @@ import org.elasticsearch.common.transport.BoundTransportAddress;
|
||||||
import org.elasticsearch.common.util.concurrent.RunOnce;
|
import org.elasticsearch.common.util.concurrent.RunOnce;
|
||||||
import org.elasticsearch.core.AbstractRefCounted;
|
import org.elasticsearch.core.AbstractRefCounted;
|
||||||
import org.elasticsearch.core.Booleans;
|
import org.elasticsearch.core.Booleans;
|
||||||
|
import org.elasticsearch.core.CheckedConsumer;
|
||||||
import org.elasticsearch.core.IOUtils;
|
import org.elasticsearch.core.IOUtils;
|
||||||
import org.elasticsearch.core.SuppressForbidden;
|
import org.elasticsearch.core.SuppressForbidden;
|
||||||
import org.elasticsearch.entitlement.bootstrap.EntitlementBootstrap;
|
import org.elasticsearch.entitlement.bootstrap.EntitlementBootstrap;
|
||||||
|
import org.elasticsearch.entitlement.runtime.api.NotEntitledException;
|
||||||
import org.elasticsearch.entitlement.runtime.policy.Policy;
|
import org.elasticsearch.entitlement.runtime.policy.Policy;
|
||||||
import org.elasticsearch.entitlement.runtime.policy.PolicyParserUtils;
|
import org.elasticsearch.entitlement.runtime.policy.PolicyParserUtils;
|
||||||
import org.elasticsearch.entitlement.runtime.policy.entitlements.LoadNativeLibrariesEntitlement;
|
import org.elasticsearch.entitlement.runtime.policy.entitlements.LoadNativeLibrariesEntitlement;
|
||||||
|
@ -54,6 +56,7 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.security.Permission;
|
import java.security.Permission;
|
||||||
|
@ -117,9 +120,9 @@ class Elasticsearch {
|
||||||
final PrintStream out = getStdout();
|
final PrintStream out = getStdout();
|
||||||
final PrintStream err = getStderr();
|
final PrintStream err = getStderr();
|
||||||
final ServerArgs args;
|
final ServerArgs args;
|
||||||
final boolean entitlementsExplicitlyEnabled = Booleans.parseBoolean(System.getProperty("es.entitlements.enabled", "false"));
|
final boolean entitlementsEnabled = Booleans.parseBoolean(System.getProperty("es.entitlements.enabled", "true"));
|
||||||
// java 24+ only supports entitlements, but it may be enabled on earlier versions explicitly
|
// java 24+ only supports entitlements, but it may be enabled on earlier versions explicitly
|
||||||
final boolean useEntitlements = RuntimeVersionFeature.isSecurityManagerAvailable() == false || entitlementsExplicitlyEnabled;
|
final boolean useEntitlements = RuntimeVersionFeature.isSecurityManagerAvailable() == false || entitlementsEnabled;
|
||||||
try {
|
try {
|
||||||
initSecurityProperties();
|
initSecurityProperties();
|
||||||
|
|
||||||
|
@ -251,9 +254,13 @@ class Elasticsearch {
|
||||||
nodeEnv.repoDirs(),
|
nodeEnv.repoDirs(),
|
||||||
nodeEnv.configDir(),
|
nodeEnv.configDir(),
|
||||||
nodeEnv.libDir(),
|
nodeEnv.libDir(),
|
||||||
|
nodeEnv.pluginsDir(),
|
||||||
nodeEnv.logsDir(),
|
nodeEnv.logsDir(),
|
||||||
nodeEnv.tmpDir()
|
nodeEnv.tmpDir(),
|
||||||
|
args.pidFile(),
|
||||||
|
Set.of(EntitlementSelfTester.class)
|
||||||
);
|
);
|
||||||
|
EntitlementSelfTester.entitlementSelfTest();
|
||||||
} else {
|
} else {
|
||||||
assert RuntimeVersionFeature.isSecurityManagerAvailable();
|
assert RuntimeVersionFeature.isSecurityManagerAvailable();
|
||||||
// no need to explicitly enable native access for legacy code
|
// no need to explicitly enable native access for legacy code
|
||||||
|
@ -270,6 +277,36 @@ class Elasticsearch {
|
||||||
bootstrap.setPluginsLoader(pluginsLoader);
|
bootstrap.setPluginsLoader(pluginsLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class EntitlementSelfTester {
|
||||||
|
// check entitlements were loaded correctly. note this must be outside the entitlements lib.
|
||||||
|
private static void entitlementSelfTest() {
|
||||||
|
ensureCannotStartProcess(ProcessBuilder::start);
|
||||||
|
// Try again with reflection
|
||||||
|
ensureCannotStartProcess(EntitlementSelfTester::reflectiveStartProcess);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ensureCannotStartProcess(CheckedConsumer<ProcessBuilder, ?> startProcess) {
|
||||||
|
try {
|
||||||
|
// The command doesn't matter; it doesn't even need to exist
|
||||||
|
startProcess.accept(new ProcessBuilder(""));
|
||||||
|
} catch (NotEntitledException e) {
|
||||||
|
return;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalStateException("Failed entitlement protection self-test", e);
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Entitlement protection self-test was incorrectly permitted");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void reflectiveStartProcess(ProcessBuilder pb) throws Exception {
|
||||||
|
try {
|
||||||
|
var start = ProcessBuilder.class.getMethod("start");
|
||||||
|
start.invoke(pb);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw (Exception) e.getCause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void ensureInitialized(Class<?>... classes) {
|
private static void ensureInitialized(Class<?>... classes) {
|
||||||
for (final var clazz : classes) {
|
for (final var clazz : classes) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -19,7 +19,6 @@ import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.Writeable;
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
import org.elasticsearch.core.Nullable;
|
import org.elasticsearch.core.Nullable;
|
||||||
import org.elasticsearch.core.UpdateForV9;
|
|
||||||
import org.elasticsearch.index.mapper.DataStreamTimestampFieldMapper;
|
import org.elasticsearch.index.mapper.DataStreamTimestampFieldMapper;
|
||||||
import org.elasticsearch.index.mapper.MapperService;
|
import org.elasticsearch.index.mapper.MapperService;
|
||||||
import org.elasticsearch.xcontent.ConstructingObjectParser;
|
import org.elasticsearch.xcontent.ConstructingObjectParser;
|
||||||
|
@ -373,8 +372,6 @@ public class ComposableIndexTemplate implements SimpleDiffable<ComposableIndexTe
|
||||||
|
|
||||||
private static final ParseField HIDDEN = new ParseField("hidden");
|
private static final ParseField HIDDEN = new ParseField("hidden");
|
||||||
private static final ParseField ALLOW_CUSTOM_ROUTING = new ParseField("allow_custom_routing");
|
private static final ParseField ALLOW_CUSTOM_ROUTING = new ParseField("allow_custom_routing");
|
||||||
// Remove this after this PR gets backported
|
|
||||||
@UpdateForV9(owner = UpdateForV9.Owner.DATA_MANAGEMENT)
|
|
||||||
private static final ParseField FAILURE_STORE = new ParseField("failure_store");
|
private static final ParseField FAILURE_STORE = new ParseField("failure_store");
|
||||||
|
|
||||||
public static final ConstructingObjectParser<DataStreamTemplate, Void> PARSER = new ConstructingObjectParser<>(
|
public static final ConstructingObjectParser<DataStreamTemplate, Void> PARSER = new ConstructingObjectParser<>(
|
||||||
|
|
|
@ -70,6 +70,10 @@ public class NodeAllocationStatsAndWeightsCalculator {
|
||||||
ClusterInfo clusterInfo,
|
ClusterInfo clusterInfo,
|
||||||
@Nullable DesiredBalance desiredBalance
|
@Nullable DesiredBalance desiredBalance
|
||||||
) {
|
) {
|
||||||
|
if (metadata.indices().isEmpty() == false) {
|
||||||
|
// must not use licensed features when just starting up
|
||||||
|
writeLoadForecaster.refreshLicense();
|
||||||
|
}
|
||||||
var weightFunction = new WeightFunction(shardBalanceFactor, indexBalanceFactor, writeLoadBalanceFactor, diskUsageBalanceFactor);
|
var weightFunction = new WeightFunction(shardBalanceFactor, indexBalanceFactor, writeLoadBalanceFactor, diskUsageBalanceFactor);
|
||||||
var avgShardsPerNode = WeightFunction.avgShardPerNode(metadata, routingNodes);
|
var avgShardsPerNode = WeightFunction.avgShardPerNode(metadata, routingNodes);
|
||||||
var avgWriteLoadPerNode = WeightFunction.avgWriteLoadPerNode(writeLoadForecaster, metadata, routingNodes);
|
var avgWriteLoadPerNode = WeightFunction.avgWriteLoadPerNode(writeLoadForecaster, metadata, routingNodes);
|
||||||
|
|
|
@ -21,6 +21,8 @@ public interface WriteLoadForecaster {
|
||||||
|
|
||||||
OptionalDouble getForecastedWriteLoad(IndexMetadata indexMetadata);
|
OptionalDouble getForecastedWriteLoad(IndexMetadata indexMetadata);
|
||||||
|
|
||||||
|
void refreshLicense();
|
||||||
|
|
||||||
class DefaultWriteLoadForecaster implements WriteLoadForecaster {
|
class DefaultWriteLoadForecaster implements WriteLoadForecaster {
|
||||||
@Override
|
@Override
|
||||||
public ProjectMetadata.Builder withWriteLoadForecastForWriteIndex(String dataStreamName, ProjectMetadata.Builder metadata) {
|
public ProjectMetadata.Builder withWriteLoadForecastForWriteIndex(String dataStreamName, ProjectMetadata.Builder metadata) {
|
||||||
|
@ -31,5 +33,8 @@ public interface WriteLoadForecaster {
|
||||||
public OptionalDouble getForecastedWriteLoad(IndexMetadata indexMetadata) {
|
public OptionalDouble getForecastedWriteLoad(IndexMetadata indexMetadata) {
|
||||||
return OptionalDouble.empty();
|
return OptionalDouble.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refreshLicense() {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,6 +147,11 @@ public class BalancedShardsAllocator implements ShardsAllocator {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void allocate(RoutingAllocation allocation) {
|
public void allocate(RoutingAllocation allocation) {
|
||||||
|
if (allocation.metadata().indices().isEmpty() == false) {
|
||||||
|
// must not use licensed features when just starting up
|
||||||
|
writeLoadForecaster.refreshLicense();
|
||||||
|
}
|
||||||
|
|
||||||
assert allocation.ignoreDisable() == false;
|
assert allocation.ignoreDisable() == false;
|
||||||
|
|
||||||
if (allocation.routingNodes().size() == 0) {
|
if (allocation.routingNodes().size() == 0) {
|
||||||
|
|
|
@ -150,6 +150,7 @@ public class IndexVersions {
|
||||||
public static final IndexVersion TIMESTAMP_DOC_VALUES_SPARSE_INDEX = def(9_011_0_00, Version.LUCENE_10_1_0);
|
public static final IndexVersion TIMESTAMP_DOC_VALUES_SPARSE_INDEX = def(9_011_0_00, Version.LUCENE_10_1_0);
|
||||||
public static final IndexVersion TIME_SERIES_ID_DOC_VALUES_SPARSE_INDEX = def(9_012_0_00, Version.LUCENE_10_1_0);
|
public static final IndexVersion TIME_SERIES_ID_DOC_VALUES_SPARSE_INDEX = def(9_012_0_00, Version.LUCENE_10_1_0);
|
||||||
public static final IndexVersion SYNTHETIC_SOURCE_STORE_ARRAYS_NATIVELY_KEYWORD = def(9_013_0_00, Version.LUCENE_10_1_0);
|
public static final IndexVersion SYNTHETIC_SOURCE_STORE_ARRAYS_NATIVELY_KEYWORD = def(9_013_0_00, Version.LUCENE_10_1_0);
|
||||||
|
public static final IndexVersion SYNTHETIC_SOURCE_STORE_ARRAYS_NATIVELY_IP = def(9_014_0_00, Version.LUCENE_10_1_0);
|
||||||
/*
|
/*
|
||||||
* STOP! READ THIS FIRST! No, really,
|
* STOP! READ THIS FIRST! No, really,
|
||||||
* ____ _____ ___ ____ _ ____ _____ _ ____ _____ _ _ ___ ____ _____ ___ ____ ____ _____ _
|
* ____ _____ ___ ____ _ ____ _____ _ ____ _____ _ _ ___ ____ _____ ___ ____ ____ _____ _
|
||||||
|
|
|
@ -13,6 +13,8 @@ import org.apache.lucene.document.SortedDocValuesField;
|
||||||
import org.apache.lucene.util.BitUtil;
|
import org.apache.lucene.util.BitUtil;
|
||||||
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.index.IndexVersion;
|
||||||
|
import org.elasticsearch.index.IndexVersions;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -23,9 +25,10 @@ import java.util.TreeMap;
|
||||||
|
|
||||||
public class FieldArrayContext {
|
public class FieldArrayContext {
|
||||||
|
|
||||||
|
private static final String OFFSETS_FIELD_NAME_SUFFIX = ".offsets";
|
||||||
private final Map<String, Offsets> offsetsPerField = new HashMap<>();
|
private final Map<String, Offsets> offsetsPerField = new HashMap<>();
|
||||||
|
|
||||||
void recordOffset(String field, String value) {
|
void recordOffset(String field, Comparable<?> value) {
|
||||||
Offsets arrayOffsets = offsetsPerField.computeIfAbsent(field, k -> new Offsets());
|
Offsets arrayOffsets = offsetsPerField.computeIfAbsent(field, k -> new Offsets());
|
||||||
int nextOffset = arrayOffsets.currentOffset++;
|
int nextOffset = arrayOffsets.currentOffset++;
|
||||||
var offsets = arrayOffsets.valueToOffsets.computeIfAbsent(value, s -> new ArrayList<>(2));
|
var offsets = arrayOffsets.valueToOffsets.computeIfAbsent(value, s -> new ArrayList<>(2));
|
||||||
|
@ -79,13 +82,53 @@ public class FieldArrayContext {
|
||||||
return offsetToOrd;
|
return offsetToOrd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String getOffsetsFieldName(
|
||||||
|
MapperBuilderContext context,
|
||||||
|
Mapper.SourceKeepMode indexSourceKeepMode,
|
||||||
|
boolean hasDocValues,
|
||||||
|
boolean isStored,
|
||||||
|
FieldMapper.Builder fieldMapperBuilder,
|
||||||
|
IndexVersion indexCreatedVersion,
|
||||||
|
IndexVersion minSupportedVersionMain
|
||||||
|
) {
|
||||||
|
var sourceKeepMode = fieldMapperBuilder.sourceKeepMode.orElse(indexSourceKeepMode);
|
||||||
|
if (context.isSourceSynthetic()
|
||||||
|
&& sourceKeepMode == Mapper.SourceKeepMode.ARRAYS
|
||||||
|
&& hasDocValues
|
||||||
|
&& isStored == false
|
||||||
|
&& fieldMapperBuilder.copyTo.copyToFields().isEmpty()
|
||||||
|
&& fieldMapperBuilder.multiFieldsBuilder.hasMultiFields() == false
|
||||||
|
&& indexVersionSupportStoringArraysNatively(indexCreatedVersion, minSupportedVersionMain)) {
|
||||||
|
// Skip stored, we will be synthesizing from stored fields, no point to keep track of the offsets
|
||||||
|
// Skip copy_to and multi fields, supporting that requires more work. However, copy_to usage is rare in metrics and
|
||||||
|
// logging use cases
|
||||||
|
|
||||||
|
// keep track of value offsets so that we can reconstruct arrays from doc values in order as was specified during indexing
|
||||||
|
// (if field is stored then there is no point of doing this)
|
||||||
|
return context.buildFullName(fieldMapperBuilder.leafName() + FieldArrayContext.OFFSETS_FIELD_NAME_SUFFIX);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean indexVersionSupportStoringArraysNatively(
|
||||||
|
IndexVersion indexCreatedVersion,
|
||||||
|
IndexVersion minSupportedVersionMain
|
||||||
|
) {
|
||||||
|
return indexCreatedVersion.onOrAfter(minSupportedVersionMain)
|
||||||
|
|| indexCreatedVersion.between(
|
||||||
|
IndexVersions.SYNTHETIC_SOURCE_STORE_ARRAYS_NATIVELY_KEYWORD_BACKPORT_8_X,
|
||||||
|
IndexVersions.UPGRADE_TO_LUCENE_10_0_0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private static class Offsets {
|
private static class Offsets {
|
||||||
|
|
||||||
int currentOffset;
|
int currentOffset;
|
||||||
// Need to use TreeMap here, so that we maintain the order in which each value (with offset) stored inserted,
|
// Need to use TreeMap here, so that we maintain the order in which each value (with offset) stored inserted,
|
||||||
// (which is in the same order the document gets parsed) so we store offsets in right order. This is the same
|
// (which is in the same order the document gets parsed) so we store offsets in right order. This is the same
|
||||||
// order in what the values get stored in SortedSetDocValues.
|
// order in what the values get stored in SortedSetDocValues.
|
||||||
final Map<String, List<Integer>> valueToOffsets = new TreeMap<>();
|
final Map<Comparable<?>, List<Integer>> valueToOffsets = new TreeMap<>();
|
||||||
final List<Integer> nullValueOffsets = new ArrayList<>(2);
|
final List<Integer> nullValueOffsets = new ArrayList<>(2);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
import static org.elasticsearch.index.mapper.FieldArrayContext.getOffsetsFieldName;
|
||||||
import static org.elasticsearch.index.mapper.IpPrefixAutomatonUtil.buildIpPrefixAutomaton;
|
import static org.elasticsearch.index.mapper.IpPrefixAutomatonUtil.buildIpPrefixAutomaton;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,8 +93,15 @@ public class IpFieldMapper extends FieldMapper {
|
||||||
private final boolean ignoreMalformedByDefault;
|
private final boolean ignoreMalformedByDefault;
|
||||||
private final IndexVersion indexCreatedVersion;
|
private final IndexVersion indexCreatedVersion;
|
||||||
private final ScriptCompiler scriptCompiler;
|
private final ScriptCompiler scriptCompiler;
|
||||||
|
private final SourceKeepMode indexSourceKeepMode;
|
||||||
|
|
||||||
public Builder(String name, ScriptCompiler scriptCompiler, boolean ignoreMalformedByDefault, IndexVersion indexCreatedVersion) {
|
public Builder(
|
||||||
|
String name,
|
||||||
|
ScriptCompiler scriptCompiler,
|
||||||
|
boolean ignoreMalformedByDefault,
|
||||||
|
IndexVersion indexCreatedVersion,
|
||||||
|
SourceKeepMode indexSourceKeepMode
|
||||||
|
) {
|
||||||
super(name);
|
super(name);
|
||||||
this.scriptCompiler = Objects.requireNonNull(scriptCompiler);
|
this.scriptCompiler = Objects.requireNonNull(scriptCompiler);
|
||||||
this.ignoreMalformedByDefault = ignoreMalformedByDefault;
|
this.ignoreMalformedByDefault = ignoreMalformedByDefault;
|
||||||
|
@ -114,6 +122,7 @@ public class IpFieldMapper extends FieldMapper {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
this.indexSourceKeepMode = indexSourceKeepMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
Builder nullValue(String nullValue) {
|
Builder nullValue(String nullValue) {
|
||||||
|
@ -184,6 +193,16 @@ public class IpFieldMapper extends FieldMapper {
|
||||||
}
|
}
|
||||||
hasScript = script.get() != null;
|
hasScript = script.get() != null;
|
||||||
onScriptError = onScriptErrorParam.getValue();
|
onScriptError = onScriptErrorParam.getValue();
|
||||||
|
|
||||||
|
String offsetsFieldName = getOffsetsFieldName(
|
||||||
|
context,
|
||||||
|
indexSourceKeepMode,
|
||||||
|
hasDocValues.getValue(),
|
||||||
|
stored.getValue(),
|
||||||
|
this,
|
||||||
|
indexCreatedVersion,
|
||||||
|
IndexVersions.SYNTHETIC_SOURCE_STORE_ARRAYS_NATIVELY_IP
|
||||||
|
);
|
||||||
return new IpFieldMapper(
|
return new IpFieldMapper(
|
||||||
leafName(),
|
leafName(),
|
||||||
new IpFieldType(
|
new IpFieldType(
|
||||||
|
@ -198,7 +217,8 @@ public class IpFieldMapper extends FieldMapper {
|
||||||
),
|
),
|
||||||
builderParams(this, context),
|
builderParams(this, context),
|
||||||
context.isSourceSynthetic(),
|
context.isSourceSynthetic(),
|
||||||
this
|
this,
|
||||||
|
offsetsFieldName
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +226,7 @@ public class IpFieldMapper extends FieldMapper {
|
||||||
|
|
||||||
public static final TypeParser PARSER = createTypeParserWithLegacySupport((n, c) -> {
|
public static final TypeParser PARSER = createTypeParserWithLegacySupport((n, c) -> {
|
||||||
boolean ignoreMalformedByDefault = IGNORE_MALFORMED_SETTING.get(c.getSettings());
|
boolean ignoreMalformedByDefault = IGNORE_MALFORMED_SETTING.get(c.getSettings());
|
||||||
return new Builder(n, c.scriptCompiler(), ignoreMalformedByDefault, c.indexVersionCreated());
|
return new Builder(n, c.scriptCompiler(), ignoreMalformedByDefault, c.indexVersionCreated(), c.getIndexSettings().sourceKeepMode());
|
||||||
});
|
});
|
||||||
|
|
||||||
public static final class IpFieldType extends SimpleMappedFieldType {
|
public static final class IpFieldType extends SimpleMappedFieldType {
|
||||||
|
@ -501,13 +521,16 @@ public class IpFieldMapper extends FieldMapper {
|
||||||
private final Script script;
|
private final Script script;
|
||||||
private final FieldValues<InetAddress> scriptValues;
|
private final FieldValues<InetAddress> scriptValues;
|
||||||
private final ScriptCompiler scriptCompiler;
|
private final ScriptCompiler scriptCompiler;
|
||||||
|
private final SourceKeepMode indexSourceKeepMode;
|
||||||
|
private final String offsetsFieldName;
|
||||||
|
|
||||||
private IpFieldMapper(
|
private IpFieldMapper(
|
||||||
String simpleName,
|
String simpleName,
|
||||||
MappedFieldType mappedFieldType,
|
MappedFieldType mappedFieldType,
|
||||||
BuilderParams builderParams,
|
BuilderParams builderParams,
|
||||||
boolean storeIgnored,
|
boolean storeIgnored,
|
||||||
Builder builder
|
Builder builder,
|
||||||
|
String offsetsFieldName
|
||||||
) {
|
) {
|
||||||
super(simpleName, mappedFieldType, builderParams);
|
super(simpleName, mappedFieldType, builderParams);
|
||||||
this.ignoreMalformedByDefault = builder.ignoreMalformedByDefault;
|
this.ignoreMalformedByDefault = builder.ignoreMalformedByDefault;
|
||||||
|
@ -523,6 +546,8 @@ public class IpFieldMapper extends FieldMapper {
|
||||||
this.scriptCompiler = builder.scriptCompiler;
|
this.scriptCompiler = builder.scriptCompiler;
|
||||||
this.dimension = builder.dimension.getValue();
|
this.dimension = builder.dimension.getValue();
|
||||||
this.storeIgnored = storeIgnored;
|
this.storeIgnored = storeIgnored;
|
||||||
|
this.indexSourceKeepMode = builder.indexSourceKeepMode;
|
||||||
|
this.offsetsFieldName = offsetsFieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -561,6 +586,14 @@ public class IpFieldMapper extends FieldMapper {
|
||||||
if (address != null) {
|
if (address != null) {
|
||||||
indexValue(context, address);
|
indexValue(context, address);
|
||||||
}
|
}
|
||||||
|
if (offsetsFieldName != null && context.isImmediateParentAnArray() && context.canAddIgnoredField()) {
|
||||||
|
if (address != null) {
|
||||||
|
BytesRef sortableValue = new BytesRef(InetAddressPoint.encode(address));
|
||||||
|
context.getOffSetContext().recordOffset(offsetsFieldName, sortableValue);
|
||||||
|
} else {
|
||||||
|
context.getOffSetContext().recordNull(offsetsFieldName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void indexValue(DocumentParserContext context, InetAddress address) {
|
private void indexValue(DocumentParserContext context, InetAddress address) {
|
||||||
|
@ -593,7 +626,9 @@ public class IpFieldMapper extends FieldMapper {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldMapper.Builder getMergeBuilder() {
|
public FieldMapper.Builder getMergeBuilder() {
|
||||||
return new Builder(leafName(), scriptCompiler, ignoreMalformedByDefault, indexCreatedVersion).dimension(dimension).init(this);
|
return new Builder(leafName(), scriptCompiler, ignoreMalformedByDefault, indexCreatedVersion, indexSourceKeepMode).dimension(
|
||||||
|
dimension
|
||||||
|
).init(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -610,19 +645,24 @@ public class IpFieldMapper extends FieldMapper {
|
||||||
if (hasDocValues) {
|
if (hasDocValues) {
|
||||||
return new SyntheticSourceSupport.Native(() -> {
|
return new SyntheticSourceSupport.Native(() -> {
|
||||||
var layers = new ArrayList<CompositeSyntheticFieldLoader.Layer>();
|
var layers = new ArrayList<CompositeSyntheticFieldLoader.Layer>();
|
||||||
layers.add(new SortedSetDocValuesSyntheticFieldLoaderLayer(fullPath()) {
|
if (offsetsFieldName != null) {
|
||||||
@Override
|
layers.add(
|
||||||
protected BytesRef convert(BytesRef value) {
|
new SortedSetWithOffsetsDocValuesSyntheticFieldLoaderLayer(fullPath(), offsetsFieldName, IpFieldMapper::convert)
|
||||||
byte[] bytes = Arrays.copyOfRange(value.bytes, value.offset, value.offset + value.length);
|
);
|
||||||
return new BytesRef(NetworkAddress.format(InetAddressPoint.decode(bytes)));
|
} else {
|
||||||
}
|
layers.add(new SortedSetDocValuesSyntheticFieldLoaderLayer(fullPath()) {
|
||||||
|
@Override
|
||||||
|
protected BytesRef convert(BytesRef value) {
|
||||||
|
return IpFieldMapper.convert(value);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected BytesRef preserve(BytesRef value) {
|
protected BytesRef preserve(BytesRef value) {
|
||||||
// No need to copy because convert has made a deep copy
|
// No need to copy because convert has made a deep copy
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (ignoreMalformed) {
|
if (ignoreMalformed) {
|
||||||
layers.add(new CompositeSyntheticFieldLoader.MalformedValuesLayer(fullPath()));
|
layers.add(new CompositeSyntheticFieldLoader.MalformedValuesLayer(fullPath()));
|
||||||
|
@ -633,4 +673,14 @@ public class IpFieldMapper extends FieldMapper {
|
||||||
|
|
||||||
return super.syntheticSourceSupport();
|
return super.syntheticSourceSupport();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BytesRef convert(BytesRef value) {
|
||||||
|
byte[] bytes = Arrays.copyOfRange(value.bytes, value.offset, value.offset + value.length);
|
||||||
|
return new BytesRef(NetworkAddress.format(InetAddressPoint.decode(bytes)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOffsetFieldName() {
|
||||||
|
return offsetsFieldName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,7 @@ import static org.apache.lucene.index.IndexWriter.MAX_TERM_LENGTH;
|
||||||
import static org.elasticsearch.core.Strings.format;
|
import static org.elasticsearch.core.Strings.format;
|
||||||
import static org.elasticsearch.index.IndexSettings.IGNORE_ABOVE_SETTING;
|
import static org.elasticsearch.index.IndexSettings.IGNORE_ABOVE_SETTING;
|
||||||
import static org.elasticsearch.index.IndexSettings.USE_DOC_VALUES_SKIPPER;
|
import static org.elasticsearch.index.IndexSettings.USE_DOC_VALUES_SKIPPER;
|
||||||
|
import static org.elasticsearch.index.mapper.FieldArrayContext.getOffsetsFieldName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A field mapper for keywords. This mapper accepts strings and indexes them as-is.
|
* A field mapper for keywords. This mapper accepts strings and indexes them as-is.
|
||||||
|
@ -95,7 +96,6 @@ public final class KeywordFieldMapper extends FieldMapper {
|
||||||
|
|
||||||
public static final String CONTENT_TYPE = "keyword";
|
public static final String CONTENT_TYPE = "keyword";
|
||||||
private static final String HOST_NAME = "host.name";
|
private static final String HOST_NAME = "host.name";
|
||||||
public static final String OFFSETS_FIELD_NAME_SUFFIX = ".offsets";
|
|
||||||
|
|
||||||
public static class Defaults {
|
public static class Defaults {
|
||||||
public static final FieldType FIELD_TYPE;
|
public static final FieldType FIELD_TYPE;
|
||||||
|
@ -439,26 +439,15 @@ public final class KeywordFieldMapper extends FieldMapper {
|
||||||
super.hasScript = script.get() != null;
|
super.hasScript = script.get() != null;
|
||||||
super.onScriptError = onScriptError.getValue();
|
super.onScriptError = onScriptError.getValue();
|
||||||
|
|
||||||
var sourceKeepMode = this.sourceKeepMode.orElse(indexSourceKeepMode);
|
String offsetsFieldName = getOffsetsFieldName(
|
||||||
String offsetsFieldName;
|
context,
|
||||||
if (context.isSourceSynthetic()
|
indexSourceKeepMode,
|
||||||
&& sourceKeepMode == SourceKeepMode.ARRAYS
|
hasDocValues.getValue(),
|
||||||
&& hasDocValues()
|
stored.getValue(),
|
||||||
&& fieldtype.stored() == false
|
this,
|
||||||
&& copyTo.copyToFields().isEmpty()
|
indexCreatedVersion,
|
||||||
&& multiFieldsBuilder.hasMultiFields() == false
|
IndexVersions.SYNTHETIC_SOURCE_STORE_ARRAYS_NATIVELY_KEYWORD
|
||||||
&& indexVersionSupportStoringArraysNatively()) {
|
);
|
||||||
// Skip stored, we will be synthesizing from stored fields, no point to keep track of the offsets
|
|
||||||
// Skip copy_to and multi fields, supporting that requires more work. However, copy_to usage is rare in metrics and
|
|
||||||
// logging use cases
|
|
||||||
|
|
||||||
// keep track of value offsets so that we can reconstruct arrays from doc values in order as was specified during indexing
|
|
||||||
// (if field is stored then there is no point of doing this)
|
|
||||||
offsetsFieldName = context.buildFullName(leafName() + OFFSETS_FIELD_NAME_SUFFIX);
|
|
||||||
} else {
|
|
||||||
offsetsFieldName = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new KeywordFieldMapper(
|
return new KeywordFieldMapper(
|
||||||
leafName(),
|
leafName(),
|
||||||
fieldtype,
|
fieldtype,
|
||||||
|
@ -472,14 +461,6 @@ public final class KeywordFieldMapper extends FieldMapper {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean indexVersionSupportStoringArraysNatively() {
|
|
||||||
return indexCreatedVersion.onOrAfter(IndexVersions.SYNTHETIC_SOURCE_STORE_ARRAYS_NATIVELY_KEYWORD)
|
|
||||||
|| indexCreatedVersion.between(
|
|
||||||
IndexVersions.SYNTHETIC_SOURCE_STORE_ARRAYS_NATIVELY_KEYWORD_BACKPORT_8_X,
|
|
||||||
IndexVersions.UPGRADE_TO_LUCENE_10_0_0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private FieldType resolveFieldType(
|
private FieldType resolveFieldType(
|
||||||
final boolean useDocValuesSkipper,
|
final boolean useDocValuesSkipper,
|
||||||
final IndexVersion indexCreatedVersion,
|
final IndexVersion indexCreatedVersion,
|
||||||
|
@ -1127,7 +1108,7 @@ public final class KeywordFieldMapper extends FieldMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean indexed = indexValue(context, value);
|
boolean indexed = indexValue(context, value);
|
||||||
if (offsetsFieldName != null && context.isImmediateParentAnArray() && context.getRecordedSource() == false) {
|
if (offsetsFieldName != null && context.isImmediateParentAnArray() && context.canAddIgnoredField()) {
|
||||||
if (indexed) {
|
if (indexed) {
|
||||||
context.getOffSetContext().recordOffset(offsetsFieldName, value);
|
context.getOffSetContext().recordOffset(offsetsFieldName, value);
|
||||||
} else if (value == null) {
|
} else if (value == null) {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import org.elasticsearch.xcontent.XContentBuilder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load {@code _source} fields from {@link SortedSetDocValues} and associated {@link BinaryDocValues}. The former contains the unique values
|
* Load {@code _source} fields from {@link SortedSetDocValues} and associated {@link BinaryDocValues}. The former contains the unique values
|
||||||
|
@ -30,11 +31,29 @@ final class SortedSetWithOffsetsDocValuesSyntheticFieldLoaderLayer implements Co
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final String offsetsFieldName;
|
private final String offsetsFieldName;
|
||||||
|
private final Function<BytesRef, BytesRef> converter;
|
||||||
private DocValuesWithOffsetsLoader docValues;
|
private DocValuesWithOffsetsLoader docValues;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name The name of the field to synthesize
|
||||||
|
* @param offsetsFieldName The related offset field used to correctly synthesize the field if it is a leaf array
|
||||||
|
*/
|
||||||
SortedSetWithOffsetsDocValuesSyntheticFieldLoaderLayer(String name, String offsetsFieldName) {
|
SortedSetWithOffsetsDocValuesSyntheticFieldLoaderLayer(String name, String offsetsFieldName) {
|
||||||
|
this(name, offsetsFieldName, Function.identity());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name The name of the field to synthesize
|
||||||
|
* @param offsetsFieldName The related offset field used to correctly synthesize the field if it is a leaf array
|
||||||
|
* @param converter This field value loader layer synthesizes the values read from doc values as utf8 string. If the doc value
|
||||||
|
* values aren't serializable as utf8 string then it is the responsibility of the converter to covert into a
|
||||||
|
* format that can be serialized as utf8 string. For example IP field mapper doc values can't directly be
|
||||||
|
* serialized as utf8 string.
|
||||||
|
*/
|
||||||
|
SortedSetWithOffsetsDocValuesSyntheticFieldLoaderLayer(String name, String offsetsFieldName, Function<BytesRef, BytesRef> converter) {
|
||||||
this.name = Objects.requireNonNull(name);
|
this.name = Objects.requireNonNull(name);
|
||||||
this.offsetsFieldName = Objects.requireNonNull(offsetsFieldName);
|
this.offsetsFieldName = Objects.requireNonNull(offsetsFieldName);
|
||||||
|
this.converter = Objects.requireNonNull(converter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -47,7 +66,7 @@ final class SortedSetWithOffsetsDocValuesSyntheticFieldLoaderLayer implements Co
|
||||||
SortedSetDocValues valueDocValues = DocValues.getSortedSet(leafReader, name);
|
SortedSetDocValues valueDocValues = DocValues.getSortedSet(leafReader, name);
|
||||||
SortedDocValues offsetDocValues = DocValues.getSorted(leafReader, offsetsFieldName);
|
SortedDocValues offsetDocValues = DocValues.getSorted(leafReader, offsetsFieldName);
|
||||||
|
|
||||||
return docValues = new DocValuesWithOffsetsLoader(valueDocValues, offsetDocValues);
|
return docValues = new DocValuesWithOffsetsLoader(valueDocValues, offsetDocValues, converter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -78,15 +97,21 @@ final class SortedSetWithOffsetsDocValuesSyntheticFieldLoaderLayer implements Co
|
||||||
static final class DocValuesWithOffsetsLoader implements DocValuesLoader {
|
static final class DocValuesWithOffsetsLoader implements DocValuesLoader {
|
||||||
private final SortedDocValues offsetDocValues;
|
private final SortedDocValues offsetDocValues;
|
||||||
private final SortedSetDocValues valueDocValues;
|
private final SortedSetDocValues valueDocValues;
|
||||||
|
private final Function<BytesRef, BytesRef> converter;
|
||||||
private final ByteArrayStreamInput scratch = new ByteArrayStreamInput();
|
private final ByteArrayStreamInput scratch = new ByteArrayStreamInput();
|
||||||
|
|
||||||
private boolean hasValue;
|
private boolean hasValue;
|
||||||
private boolean hasOffset;
|
private boolean hasOffset;
|
||||||
private int[] offsetToOrd;
|
private int[] offsetToOrd;
|
||||||
|
|
||||||
DocValuesWithOffsetsLoader(SortedSetDocValues valueDocValues, SortedDocValues offsetDocValues) {
|
DocValuesWithOffsetsLoader(
|
||||||
|
SortedSetDocValues valueDocValues,
|
||||||
|
SortedDocValues offsetDocValues,
|
||||||
|
Function<BytesRef, BytesRef> converter
|
||||||
|
) {
|
||||||
this.valueDocValues = valueDocValues;
|
this.valueDocValues = valueDocValues;
|
||||||
this.offsetDocValues = offsetDocValues;
|
this.offsetDocValues = offsetDocValues;
|
||||||
|
this.converter = converter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -146,7 +171,7 @@ final class SortedSetWithOffsetsDocValuesSyntheticFieldLoaderLayer implements Co
|
||||||
|
|
||||||
long ord = ords[offset];
|
long ord = ords[offset];
|
||||||
BytesRef c = valueDocValues.lookupOrd(ord);
|
BytesRef c = valueDocValues.lookupOrd(ord);
|
||||||
// This is keyword specific and needs to be updated once support is added for other field types:
|
c = converter.apply(c);
|
||||||
b.utf8Value(c.bytes, c.offset, c.length);
|
b.utf8Value(c.bytes, c.offset, c.length);
|
||||||
}
|
}
|
||||||
} else if (offsetToOrd != null) {
|
} else if (offsetToOrd != null) {
|
||||||
|
@ -158,6 +183,7 @@ final class SortedSetWithOffsetsDocValuesSyntheticFieldLoaderLayer implements Co
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < valueDocValues.docValueCount(); i++) {
|
for (int i = 0; i < valueDocValues.docValueCount(); i++) {
|
||||||
BytesRef c = valueDocValues.lookupOrd(valueDocValues.nextOrd());
|
BytesRef c = valueDocValues.lookupOrd(valueDocValues.nextOrd());
|
||||||
|
c = converter.apply(c);
|
||||||
b.utf8Value(c.bytes, c.offset, c.length);
|
b.utf8Value(c.bytes, c.offset, c.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ public final class PipelineConfiguration implements SimpleDiffable<PipelineConfi
|
||||||
static {
|
static {
|
||||||
PARSER.declareString(Builder::setId, new ParseField("id"));
|
PARSER.declareString(Builder::setId, new ParseField("id"));
|
||||||
PARSER.declareField(
|
PARSER.declareField(
|
||||||
(parser, builder, aVoid) -> builder.setConfig(parser.map()),
|
(parser, builder, aVoid) -> builder.setConfig(parser.mapOrdered()),
|
||||||
new ParseField("config"),
|
new ParseField("config"),
|
||||||
ObjectParser.ValueType.OBJECT
|
ObjectParser.ValueType.OBJECT
|
||||||
);
|
);
|
||||||
|
|
|
@ -28,6 +28,7 @@ import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static org.elasticsearch.common.collect.Iterators.single;
|
import static org.elasticsearch.common.collect.Iterators.single;
|
||||||
|
import static org.elasticsearch.script.ScriptContextStats.Fields.CACHE_EVICTIONS_HISTORY;
|
||||||
import static org.elasticsearch.script.ScriptContextStats.Fields.COMPILATIONS_HISTORY;
|
import static org.elasticsearch.script.ScriptContextStats.Fields.COMPILATIONS_HISTORY;
|
||||||
import static org.elasticsearch.script.ScriptStats.Fields.CACHE_EVICTIONS;
|
import static org.elasticsearch.script.ScriptStats.Fields.CACHE_EVICTIONS;
|
||||||
import static org.elasticsearch.script.ScriptStats.Fields.COMPILATIONS;
|
import static org.elasticsearch.script.ScriptStats.Fields.COMPILATIONS;
|
||||||
|
@ -205,7 +206,7 @@ public record ScriptStats(
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
}
|
}
|
||||||
if (cacheEvictionsHistory != null && cacheEvictionsHistory.areTimingsEmpty() == false) {
|
if (cacheEvictionsHistory != null && cacheEvictionsHistory.areTimingsEmpty() == false) {
|
||||||
builder.startObject(COMPILATIONS_HISTORY);
|
builder.startObject(CACHE_EVICTIONS_HISTORY);
|
||||||
cacheEvictionsHistory.toXContent(builder, params);
|
cacheEvictionsHistory.toXContent(builder, params);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* 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", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||||
|
* Public License v 1"; you may not use this file except in compliance with, at
|
||||||
|
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||||
|
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.index.mapper;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.network.NetworkAddress;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder;
|
||||||
|
|
||||||
|
public class IPSyntheticSourceNativeArrayIntegrationTests extends NativeArrayIntegrationTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getFieldTypeName() {
|
||||||
|
return "ip";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getRandomValue() {
|
||||||
|
return NetworkAddress.format(randomIp(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSynthesizeArray() throws Exception {
|
||||||
|
var arrayValues = new Object[][] {
|
||||||
|
new Object[] { "192.168.1.4", "192.168.1.3", null, "192.168.1.2", null, "192.168.1.1" },
|
||||||
|
new Object[] { null, "192.168.1.2", null, "192.168.1.1" },
|
||||||
|
new Object[] { null },
|
||||||
|
new Object[] { null, null, null },
|
||||||
|
new Object[] { "192.168.1.3", "192.168.1.2", "192.168.1.1" } };
|
||||||
|
verifySyntheticArray(arrayValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSynthesizeArrayIgnoreMalformed() throws Exception {
|
||||||
|
var mapping = jsonBuilder().startObject()
|
||||||
|
.startObject("properties")
|
||||||
|
.startObject("field")
|
||||||
|
.field("type", "ip")
|
||||||
|
.field("ignore_malformed", true)
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject();
|
||||||
|
// Note values that would be ignored are added at the end of arrays,
|
||||||
|
// this makes testing easier as ignored values are always synthesized after regular values:
|
||||||
|
var arrayValues = new Object[][] {
|
||||||
|
new Object[] { null, "192.168.1.1", "192.168.1.2", "192.168.1.3", "192.168.1.4", null, "malformed" },
|
||||||
|
new Object[] { "192.168.1.1", "192.168.1.2", "malformed" },
|
||||||
|
new Object[] { "192.168.1.1", "192.168.1.1", "malformed" },
|
||||||
|
new Object[] { null, null, null, "malformed" },
|
||||||
|
new Object[] { "192.168.1.3", "192.168.1.3", "192.168.1.1", "malformed" } };
|
||||||
|
verifySyntheticArray(arrayValues, mapping, "_id", "field._ignore_malformed");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSynthesizeObjectArray() throws Exception {
|
||||||
|
List<List<Object[]>> documents = new ArrayList<>();
|
||||||
|
{
|
||||||
|
List<Object[]> document = new ArrayList<>();
|
||||||
|
document.add(new Object[] { "192.168.1.3", "192.168.1.2", "192.168.1.1" });
|
||||||
|
document.add(new Object[] { "192.168.1.110", "192.168.1.109", "192.168.1.111" });
|
||||||
|
document.add(new Object[] { "192.168.1.2", "192.168.1.2", "192.168.1.1" });
|
||||||
|
documents.add(document);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
List<Object[]> document = new ArrayList<>();
|
||||||
|
document.add(new Object[] { "192.168.1.9", "192.168.1.7", "192.168.1.5" });
|
||||||
|
document.add(new Object[] { "192.168.1.2", "192.168.1.4", "192.168.1.6" });
|
||||||
|
document.add(new Object[] { "192.168.1.7", "192.168.1.6", "192.168.1.5" });
|
||||||
|
documents.add(document);
|
||||||
|
}
|
||||||
|
verifySyntheticObjectArray(documents);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSynthesizeArrayInObjectField() throws Exception {
|
||||||
|
List<Object[]> documents = new ArrayList<>();
|
||||||
|
documents.add(new Object[] { "192.168.1.254", "192.168.1.253", "192.168.1.252" });
|
||||||
|
documents.add(new Object[] { "192.168.1.112", "192.168.1.113", "192.168.1.114" });
|
||||||
|
documents.add(new Object[] { "192.168.1.3", "192.168.1.2", "192.168.1.1" });
|
||||||
|
documents.add(new Object[] { "192.168.1.9", "192.168.1.7", "192.168.1.5" });
|
||||||
|
documents.add(new Object[] { "192.168.1.2", "192.168.1.4", "192.168.1.6" });
|
||||||
|
documents.add(new Object[] { "192.168.1.7", "192.168.1.6", "192.168.1.5" });
|
||||||
|
verifySyntheticArrayInObject(documents);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -439,4 +439,9 @@ public class IpFieldMapperTests extends MapperTestCase {
|
||||||
protected Function<Object, Object> loadBlockExpected() {
|
protected Function<Object, Object> loadBlockExpected() {
|
||||||
return v -> InetAddresses.toAddrString(InetAddressPoint.decode(BytesRef.deepCopyOf((BytesRef) v).bytes));
|
return v -> InetAddresses.toAddrString(InetAddressPoint.decode(BytesRef.deepCopyOf((BytesRef) v).bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String randomSyntheticSourceKeep() {
|
||||||
|
return "all";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -349,16 +349,24 @@ public class IpFieldTypeTests extends FieldTypeTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFetchSourceValue() throws IOException {
|
public void testFetchSourceValue() throws IOException {
|
||||||
MappedFieldType mapper = new IpFieldMapper.Builder("field", ScriptCompiler.NONE, true, IndexVersion.current()).build(
|
MappedFieldType mapper = new IpFieldMapper.Builder(
|
||||||
MapperBuilderContext.root(false, false)
|
"field",
|
||||||
).fieldType();
|
ScriptCompiler.NONE,
|
||||||
|
true,
|
||||||
|
IndexVersion.current(),
|
||||||
|
Mapper.SourceKeepMode.NONE
|
||||||
|
).build(MapperBuilderContext.root(false, false)).fieldType();
|
||||||
assertEquals(List.of("2001:db8::2:1"), fetchSourceValue(mapper, "2001:db8::2:1"));
|
assertEquals(List.of("2001:db8::2:1"), fetchSourceValue(mapper, "2001:db8::2:1"));
|
||||||
assertEquals(List.of("2001:db8::2:1"), fetchSourceValue(mapper, "2001:db8:0:0:0:0:2:1"));
|
assertEquals(List.of("2001:db8::2:1"), fetchSourceValue(mapper, "2001:db8:0:0:0:0:2:1"));
|
||||||
assertEquals(List.of("::1"), fetchSourceValue(mapper, "0:0:0:0:0:0:0:1"));
|
assertEquals(List.of("::1"), fetchSourceValue(mapper, "0:0:0:0:0:0:0:1"));
|
||||||
|
|
||||||
MappedFieldType nullValueMapper = new IpFieldMapper.Builder("field", ScriptCompiler.NONE, true, IndexVersion.current()).nullValue(
|
MappedFieldType nullValueMapper = new IpFieldMapper.Builder(
|
||||||
"2001:db8:0:0:0:0:2:7"
|
"field",
|
||||||
).build(MapperBuilderContext.root(false, false)).fieldType();
|
ScriptCompiler.NONE,
|
||||||
|
true,
|
||||||
|
IndexVersion.current(),
|
||||||
|
Mapper.SourceKeepMode.NONE
|
||||||
|
).nullValue("2001:db8:0:0:0:0:2:7").build(MapperBuilderContext.root(false, false)).fieldType();
|
||||||
assertEquals(List.of("2001:db8::2:7"), fetchSourceValue(nullValueMapper, null));
|
assertEquals(List.of("2001:db8::2:7"), fetchSourceValue(nullValueMapper, null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* 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", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||||
|
* Public License v 1"; you may not use this file except in compliance with, at
|
||||||
|
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||||
|
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.index.mapper;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.network.NetworkAddress;
|
||||||
|
|
||||||
|
public class IpOffsetDocValuesLoaderTests extends OffsetDocValuesLoaderTestCase {
|
||||||
|
|
||||||
|
public void testOffsetArray() throws Exception {
|
||||||
|
verifyOffsets("{\"field\":[\"192.168.1.1\",\"192.168.1.3\",\"192.168.1.2\",\"192.168.1.1\",\"192.168.1.9\",\"192.168.1.3\"]}");
|
||||||
|
verifyOffsets("{\"field\":[\"192.168.1.4\",null,\"192.168.1.3\",\"192.168.1.2\",null,\"192.168.1.1\"]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOffsetNestedArray() throws Exception {
|
||||||
|
verifyOffsets(
|
||||||
|
"{\"field\":[\"192.168.1.2\",[\"192.168.1.1\"],[\"192.168.1.0\"],null,\"192.168.1.0\"]}",
|
||||||
|
"{\"field\":[\"192.168.1.2\",\"192.168.1.1\",\"192.168.1.0\",null,\"192.168.1.0\"]}"
|
||||||
|
);
|
||||||
|
verifyOffsets(
|
||||||
|
"{\"field\":[\"192.168.1.6\",[\"192.168.1.5\", [\"192.168.1.4\"]],[\"192.168.1.3\", [\"192.168.1.2\"]],null,\"192.168.1.1\"]}",
|
||||||
|
"{\"field\":[\"192.168.1.6\",\"192.168.1.5\",\"192.168.1.4\",\"192.168.1.3\",\"192.168.1.2\",null,\"192.168.1.1\"]}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getFieldTypeName() {
|
||||||
|
return "ip";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String randomValue() {
|
||||||
|
return NetworkAddress.format(randomIp(true));
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,145 +9,7 @@
|
||||||
|
|
||||||
package org.elasticsearch.index.mapper;
|
package org.elasticsearch.index.mapper;
|
||||||
|
|
||||||
import org.apache.lucene.index.DirectoryReader;
|
public class KeywordOffsetDocValuesLoaderTests extends OffsetDocValuesLoaderTestCase {
|
||||||
import org.elasticsearch.common.Strings;
|
|
||||||
import org.elasticsearch.common.bytes.BytesArray;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.index.mapper.SortedSetWithOffsetsDocValuesSyntheticFieldLoaderLayer.DocValuesWithOffsetsLoader;
|
|
||||||
import org.elasticsearch.xcontent.XContentBuilder;
|
|
||||||
import org.elasticsearch.xcontent.XContentType;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder;
|
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
|
||||||
|
|
||||||
public class KeywordOffsetDocValuesLoaderTests extends MapperServiceTestCase {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Settings getIndexSettings() {
|
|
||||||
return Settings.builder()
|
|
||||||
.put("index.mapping.source.mode", "synthetic")
|
|
||||||
.put("index.mapping.synthetic_source_keep", "arrays")
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testOffsetArrayNoDocValues() throws Exception {
|
|
||||||
String mapping = """
|
|
||||||
{
|
|
||||||
"_doc": {
|
|
||||||
"properties": {
|
|
||||||
"field": {
|
|
||||||
"type": "keyword",
|
|
||||||
"doc_values": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
try (var mapperService = createMapperService(mapping)) {
|
|
||||||
var fieldMapper = mapperService.mappingLookup().getMapper("field");
|
|
||||||
assertThat(fieldMapper.getOffsetFieldName(), nullValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testOffsetArrayStored() throws Exception {
|
|
||||||
String mapping = """
|
|
||||||
{
|
|
||||||
"_doc": {
|
|
||||||
"properties": {
|
|
||||||
"field": {
|
|
||||||
"type": "keyword",
|
|
||||||
"store": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
try (var mapperService = createMapperService(mapping)) {
|
|
||||||
var fieldMapper = mapperService.mappingLookup().getMapper("field");
|
|
||||||
assertThat(fieldMapper.getOffsetFieldName(), nullValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testOffsetMultiFields() throws Exception {
|
|
||||||
String mapping = """
|
|
||||||
{
|
|
||||||
"_doc": {
|
|
||||||
"properties": {
|
|
||||||
"field": {
|
|
||||||
"type": "keyword",
|
|
||||||
"fields": {
|
|
||||||
"sub": {
|
|
||||||
"type": "text"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
try (var mapperService = createMapperService(mapping)) {
|
|
||||||
var fieldMapper = mapperService.mappingLookup().getMapper("field");
|
|
||||||
assertThat(fieldMapper.getOffsetFieldName(), nullValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testOffsetArrayNoSyntheticSource() throws Exception {
|
|
||||||
String mapping = """
|
|
||||||
{
|
|
||||||
"_doc": {
|
|
||||||
"properties": {
|
|
||||||
"field": {
|
|
||||||
"type": "keyword"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
try (var mapperService = createMapperService(Settings.EMPTY, mapping)) {
|
|
||||||
var fieldMapper = mapperService.mappingLookup().getMapper("field");
|
|
||||||
assertThat(fieldMapper.getOffsetFieldName(), nullValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testOffsetArrayNoSourceArrayKeep() throws Exception {
|
|
||||||
var settingsBuilder = Settings.builder().put("index.mapping.source.mode", "synthetic");
|
|
||||||
String mapping;
|
|
||||||
if (randomBoolean()) {
|
|
||||||
mapping = """
|
|
||||||
{
|
|
||||||
"_doc": {
|
|
||||||
"properties": {
|
|
||||||
"field": {
|
|
||||||
"type": "keyword",
|
|
||||||
"synthetic_source_keep": "{{synthetic_source_keep}}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""".replace("{{synthetic_source_keep}}", randomBoolean() ? "none" : "all");
|
|
||||||
} else {
|
|
||||||
mapping = """
|
|
||||||
{
|
|
||||||
"_doc": {
|
|
||||||
"properties": {
|
|
||||||
"field": {
|
|
||||||
"type": "keyword"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
if (randomBoolean()) {
|
|
||||||
settingsBuilder.put("index.mapping.synthetic_source_keep", "none");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try (var mapperService = createMapperService(settingsBuilder.build(), mapping)) {
|
|
||||||
var fieldMapper = mapperService.mappingLookup().getMapper("field");
|
|
||||||
assertThat(fieldMapper.getOffsetFieldName(), nullValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testOffsetArray() throws Exception {
|
public void testOffsetArray() throws Exception {
|
||||||
verifyOffsets("{\"field\":[\"z\",\"x\",\"y\",\"c\",\"b\",\"a\"]}");
|
verifyOffsets("{\"field\":[\"z\",\"x\",\"y\",\"c\",\"b\",\"a\"]}");
|
||||||
|
@ -162,76 +24,13 @@ public class KeywordOffsetDocValuesLoaderTests extends MapperServiceTestCase {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testOffsetEmptyArray() throws Exception {
|
@Override
|
||||||
verifyOffsets("{\"field\":[]}");
|
protected String getFieldTypeName() {
|
||||||
|
return "keyword";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testOffsetArrayWithNulls() throws Exception {
|
@Override
|
||||||
verifyOffsets("{\"field\":[null,null,null]}");
|
protected String randomValue() {
|
||||||
|
return randomAlphanumericOfLength(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testOffsetArrayRandom() throws Exception {
|
|
||||||
StringBuilder values = new StringBuilder();
|
|
||||||
int numValues = randomIntBetween(0, 256);
|
|
||||||
for (int i = 0; i < numValues; i++) {
|
|
||||||
if (randomInt(10) == 1) {
|
|
||||||
values.append("null");
|
|
||||||
} else {
|
|
||||||
values.append('"').append(randomAlphanumericOfLength(2)).append('"');
|
|
||||||
}
|
|
||||||
if (i != (numValues - 1)) {
|
|
||||||
values.append(',');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
verifyOffsets("{\"field\":[" + values + "]}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyOffsets(String source) throws IOException {
|
|
||||||
verifyOffsets(source, source);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyOffsets(String source, String expectedSource) throws IOException {
|
|
||||||
String mapping = """
|
|
||||||
{
|
|
||||||
"_doc": {
|
|
||||||
"properties": {
|
|
||||||
"field": {
|
|
||||||
"type": "keyword"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
verifyOffsets(mapping, source, expectedSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyOffsets(String mapping, String source, String expectedSource) throws IOException {
|
|
||||||
try (var mapperService = createMapperService(mapping)) {
|
|
||||||
var mapper = mapperService.documentMapper();
|
|
||||||
|
|
||||||
try (var directory = newDirectory()) {
|
|
||||||
var iw = indexWriterForSyntheticSource(directory);
|
|
||||||
var doc = mapper.parse(new SourceToParse("_id", new BytesArray(source), XContentType.JSON));
|
|
||||||
doc.updateSeqID(0, 0);
|
|
||||||
doc.version().setLongValue(0);
|
|
||||||
iw.addDocuments(doc.docs());
|
|
||||||
iw.close();
|
|
||||||
try (var indexReader = wrapInMockESDirectoryReader(DirectoryReader.open(directory))) {
|
|
||||||
var layer = new SortedSetWithOffsetsDocValuesSyntheticFieldLoaderLayer("field", "field.offsets");
|
|
||||||
var leafReader = indexReader.leaves().getFirst().reader();
|
|
||||||
var loader = (DocValuesWithOffsetsLoader) layer.docValuesLoader(leafReader, new int[] { 0 });
|
|
||||||
assertTrue(loader.advanceToDoc(0));
|
|
||||||
assertTrue(loader.count() > 0);
|
|
||||||
XContentBuilder builder = jsonBuilder().startObject();
|
|
||||||
builder.startArray("field");
|
|
||||||
loader.write(builder);
|
|
||||||
builder.endArray().endObject();
|
|
||||||
|
|
||||||
var actual = Strings.toString(builder);
|
|
||||||
assertEquals(expectedSource, actual);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,38 +9,24 @@
|
||||||
|
|
||||||
package org.elasticsearch.index.mapper;
|
package org.elasticsearch.index.mapper;
|
||||||
|
|
||||||
import org.apache.lucene.index.DocValuesType;
|
import com.carrotsearch.randomizedtesting.generators.RandomStrings;
|
||||||
import org.apache.lucene.index.FieldInfo;
|
|
||||||
import org.apache.lucene.index.FieldInfos;
|
|
||||||
import org.apache.lucene.index.IndexableField;
|
|
||||||
import org.apache.lucene.index.LeafReader;
|
|
||||||
import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeRequest;
|
|
||||||
import org.elasticsearch.action.index.IndexRequest;
|
|
||||||
import org.elasticsearch.action.search.SearchRequest;
|
|
||||||
import org.elasticsearch.action.support.WriteRequest;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.index.IndexSettings;
|
|
||||||
import org.elasticsearch.index.query.IdsQueryBuilder;
|
|
||||||
import org.elasticsearch.test.ESSingleNodeTestCase;
|
|
||||||
import org.elasticsearch.xcontent.XContentBuilder;
|
|
||||||
import org.hamcrest.Matchers;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder;
|
import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder;
|
||||||
import static org.hamcrest.Matchers.contains;
|
|
||||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
|
||||||
import static org.hamcrest.Matchers.empty;
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
|
||||||
import static org.hamcrest.Matchers.hasKey;
|
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
|
||||||
|
|
||||||
public class KeywordSyntheticSourceNativeArrayIntegrationTests extends ESSingleNodeTestCase {
|
public class KeywordSyntheticSourceNativeArrayIntegrationTests extends NativeArrayIntegrationTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getFieldTypeName() {
|
||||||
|
return "keyword";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getRandomValue() {
|
||||||
|
return RandomStrings.randomAsciiOfLength(random(), 8);
|
||||||
|
}
|
||||||
|
|
||||||
public void testSynthesizeArray() throws Exception {
|
public void testSynthesizeArray() throws Exception {
|
||||||
var arrayValues = new Object[][] {
|
var arrayValues = new Object[][] {
|
||||||
|
@ -52,16 +38,6 @@ public class KeywordSyntheticSourceNativeArrayIntegrationTests extends ESSingleN
|
||||||
verifySyntheticArray(arrayValues);
|
verifySyntheticArray(arrayValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSynthesizeEmptyArray() throws Exception {
|
|
||||||
var arrayValues = new Object[][] { new Object[] {} };
|
|
||||||
verifySyntheticArray(arrayValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testSynthesizeArrayRandom() throws Exception {
|
|
||||||
var arrayValues = new Object[][] { generateRandomStringArray(64, 8, false, true) };
|
|
||||||
verifySyntheticArray(arrayValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testSynthesizeArrayIgnoreAbove() throws Exception {
|
public void testSynthesizeArrayIgnoreAbove() throws Exception {
|
||||||
var mapping = jsonBuilder().startObject()
|
var mapping = jsonBuilder().startObject()
|
||||||
.startObject("properties")
|
.startObject("properties")
|
||||||
|
@ -79,7 +55,7 @@ public class KeywordSyntheticSourceNativeArrayIntegrationTests extends ESSingleN
|
||||||
new Object[] { "123", "1234", "12345" },
|
new Object[] { "123", "1234", "12345" },
|
||||||
new Object[] { null, null, null, "blabla" },
|
new Object[] { null, null, null, "blabla" },
|
||||||
new Object[] { "1", "2", "3", "blabla" } };
|
new Object[] { "1", "2", "3", "blabla" } };
|
||||||
verifySyntheticArray(arrayValues, mapping, 4, "_id", "field._original");
|
verifySyntheticArray(arrayValues, mapping, "_id", "field._original");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSynthesizeObjectArray() throws Exception {
|
public void testSynthesizeObjectArray() throws Exception {
|
||||||
|
@ -112,237 +88,4 @@ public class KeywordSyntheticSourceNativeArrayIntegrationTests extends ESSingleN
|
||||||
verifySyntheticArrayInObject(documents);
|
verifySyntheticArrayInObject(documents);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSynthesizeArrayInObjectFieldRandom() throws Exception {
|
|
||||||
List<Object[]> documents = new ArrayList<>();
|
|
||||||
int numDocs = randomIntBetween(8, 256);
|
|
||||||
for (int i = 0; i < numDocs; i++) {
|
|
||||||
documents.add(generateRandomStringArray(64, 8, false, true));
|
|
||||||
}
|
|
||||||
verifySyntheticArrayInObject(documents);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifySyntheticArray(Object[][] arrays) throws IOException {
|
|
||||||
var mapping = jsonBuilder().startObject()
|
|
||||||
.startObject("properties")
|
|
||||||
.startObject("field")
|
|
||||||
.field("type", "keyword")
|
|
||||||
.endObject()
|
|
||||||
.endObject()
|
|
||||||
.endObject();
|
|
||||||
verifySyntheticArray(arrays, mapping, null, "_id");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifySyntheticArray(Object[][] arrays, XContentBuilder mapping, Integer ignoreAbove, String... expectedStoredFields)
|
|
||||||
throws IOException {
|
|
||||||
var indexService = createIndex(
|
|
||||||
"test-index",
|
|
||||||
Settings.builder().put("index.mapping.source.mode", "synthetic").put("index.mapping.synthetic_source_keep", "arrays").build(),
|
|
||||||
mapping
|
|
||||||
);
|
|
||||||
for (int i = 0; i < arrays.length; i++) {
|
|
||||||
var array = arrays[i];
|
|
||||||
|
|
||||||
var indexRequest = new IndexRequest("test-index");
|
|
||||||
indexRequest.id("my-id-" + i);
|
|
||||||
var source = jsonBuilder().startObject();
|
|
||||||
if (array != null) {
|
|
||||||
source.startArray("field");
|
|
||||||
for (Object arrayValue : array) {
|
|
||||||
source.value(arrayValue);
|
|
||||||
}
|
|
||||||
source.endArray();
|
|
||||||
} else {
|
|
||||||
source.field("field").nullValue();
|
|
||||||
}
|
|
||||||
indexRequest.source(source.endObject());
|
|
||||||
indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
|
||||||
client().index(indexRequest).actionGet();
|
|
||||||
|
|
||||||
var searchRequest = new SearchRequest("test-index");
|
|
||||||
searchRequest.source().query(new IdsQueryBuilder().addIds("my-id-" + i));
|
|
||||||
var searchResponse = client().search(searchRequest).actionGet();
|
|
||||||
try {
|
|
||||||
var hit = searchResponse.getHits().getHits()[0];
|
|
||||||
assertThat(hit.getId(), equalTo("my-id-" + i));
|
|
||||||
var sourceAsMap = hit.getSourceAsMap();
|
|
||||||
assertThat(sourceAsMap, hasKey("field"));
|
|
||||||
var actualArray = (List<?>) sourceAsMap.get("field");
|
|
||||||
if (array == null) {
|
|
||||||
assertThat(actualArray, nullValue());
|
|
||||||
} else if (array.length == 0) {
|
|
||||||
assertThat(actualArray, empty());
|
|
||||||
} else {
|
|
||||||
assertThat(actualArray, Matchers.contains(array));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
searchResponse.decRef();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try (var searcher = indexService.getShard(0).acquireSearcher(getTestName())) {
|
|
||||||
var reader = searcher.getDirectoryReader();
|
|
||||||
for (int i = 0; i < arrays.length; i++) {
|
|
||||||
var document = reader.storedFields().document(i);
|
|
||||||
// Verify that there is no ignored source:
|
|
||||||
Set<String> storedFieldNames = new LinkedHashSet<>(document.getFields().stream().map(IndexableField::name).toList());
|
|
||||||
if (IndexSettings.RECOVERY_USE_SYNTHETIC_SOURCE.isEnabled()) {
|
|
||||||
assertThat(storedFieldNames, contains(expectedStoredFields));
|
|
||||||
} else {
|
|
||||||
String[] copyExpectedStoredFields = new String[expectedStoredFields.length + 1];
|
|
||||||
System.arraycopy(expectedStoredFields, 0, copyExpectedStoredFields, 0, expectedStoredFields.length);
|
|
||||||
copyExpectedStoredFields[copyExpectedStoredFields.length - 1] = "_recovery_source";
|
|
||||||
assertThat(storedFieldNames, containsInAnyOrder(copyExpectedStoredFields));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var fieldInfo = FieldInfos.getMergedFieldInfos(reader).fieldInfo("field.offsets");
|
|
||||||
assertThat(fieldInfo.getDocValuesType(), equalTo(DocValuesType.SORTED));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifySyntheticObjectArray(List<List<Object[]>> documents) throws IOException {
|
|
||||||
var indexService = createIndex(
|
|
||||||
"test-index",
|
|
||||||
Settings.builder().put("index.mapping.source.mode", "synthetic").put("index.mapping.synthetic_source_keep", "arrays").build(),
|
|
||||||
jsonBuilder().startObject()
|
|
||||||
.startObject("properties")
|
|
||||||
.startObject("object")
|
|
||||||
.startObject("properties")
|
|
||||||
.startObject("field")
|
|
||||||
.field("type", "keyword")
|
|
||||||
.endObject()
|
|
||||||
.endObject()
|
|
||||||
.endObject()
|
|
||||||
.endObject()
|
|
||||||
.endObject()
|
|
||||||
);
|
|
||||||
for (int i = 0; i < documents.size(); i++) {
|
|
||||||
var document = documents.get(i);
|
|
||||||
|
|
||||||
var indexRequest = new IndexRequest("test-index");
|
|
||||||
indexRequest.id("my-id-" + i);
|
|
||||||
var source = jsonBuilder().startObject();
|
|
||||||
source.startArray("object");
|
|
||||||
for (Object[] arrayValue : document) {
|
|
||||||
source.startObject();
|
|
||||||
source.array("field", arrayValue);
|
|
||||||
source.endObject();
|
|
||||||
}
|
|
||||||
source.endArray();
|
|
||||||
indexRequest.source(source.endObject());
|
|
||||||
indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
|
||||||
client().index(indexRequest).actionGet();
|
|
||||||
|
|
||||||
var searchRequest = new SearchRequest("test-index");
|
|
||||||
searchRequest.source().query(new IdsQueryBuilder().addIds("my-id-" + i));
|
|
||||||
var searchResponse = client().search(searchRequest).actionGet();
|
|
||||||
try {
|
|
||||||
var hit = searchResponse.getHits().getHits()[0];
|
|
||||||
assertThat(hit.getId(), equalTo("my-id-" + i));
|
|
||||||
var sourceAsMap = hit.getSourceAsMap();
|
|
||||||
var objectArray = (List<?>) sourceAsMap.get("object");
|
|
||||||
for (int j = 0; j < document.size(); j++) {
|
|
||||||
var expected = document.get(j);
|
|
||||||
List<?> actual = (List<?>) ((Map<?, ?>) objectArray.get(j)).get("field");
|
|
||||||
assertThat(actual, Matchers.contains(expected));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
searchResponse.decRef();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
indexService.getShard(0).forceMerge(new ForceMergeRequest("test-index").maxNumSegments(1));
|
|
||||||
try (var searcher = indexService.getShard(0).acquireSearcher(getTestName())) {
|
|
||||||
var reader = searcher.getDirectoryReader();
|
|
||||||
for (int i = 0; i < documents.size(); i++) {
|
|
||||||
var document = reader.storedFields().document(i);
|
|
||||||
// Verify that there is ignored source because of leaf array being wrapped by object array:
|
|
||||||
List<String> storedFieldNames = document.getFields().stream().map(IndexableField::name).toList();
|
|
||||||
if (IndexSettings.RECOVERY_USE_SYNTHETIC_SOURCE.isEnabled()) {
|
|
||||||
assertThat(storedFieldNames, contains("_id", "_ignored_source"));
|
|
||||||
} else {
|
|
||||||
assertThat(storedFieldNames, containsInAnyOrder("_id", "_ignored_source", "_recovery_source"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that there is no offset field:
|
|
||||||
LeafReader leafReader = reader.leaves().get(0).reader();
|
|
||||||
for (FieldInfo fieldInfo : leafReader.getFieldInfos()) {
|
|
||||||
String name = fieldInfo.getName();
|
|
||||||
assertFalse("expected no field that contains [offsets] in name, but found [" + name + "]", name.contains("offsets"));
|
|
||||||
}
|
|
||||||
|
|
||||||
var binaryDocValues = leafReader.getBinaryDocValues("object.field.offsets");
|
|
||||||
assertThat(binaryDocValues, nullValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifySyntheticArrayInObject(List<Object[]> documents) throws IOException {
|
|
||||||
var indexService = createIndex(
|
|
||||||
"test-index",
|
|
||||||
Settings.builder().put("index.mapping.source.mode", "synthetic").put("index.mapping.synthetic_source_keep", "arrays").build(),
|
|
||||||
jsonBuilder().startObject()
|
|
||||||
.startObject("properties")
|
|
||||||
.startObject("object")
|
|
||||||
.startObject("properties")
|
|
||||||
.startObject("field")
|
|
||||||
.field("type", "keyword")
|
|
||||||
.endObject()
|
|
||||||
.endObject()
|
|
||||||
.endObject()
|
|
||||||
.endObject()
|
|
||||||
.endObject()
|
|
||||||
);
|
|
||||||
for (int i = 0; i < documents.size(); i++) {
|
|
||||||
var arrayValue = documents.get(i);
|
|
||||||
|
|
||||||
var indexRequest = new IndexRequest("test-index");
|
|
||||||
indexRequest.id("my-id-" + i);
|
|
||||||
var source = jsonBuilder().startObject();
|
|
||||||
source.startObject("object");
|
|
||||||
source.array("field", arrayValue);
|
|
||||||
source.endObject();
|
|
||||||
indexRequest.source(source.endObject());
|
|
||||||
indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
|
||||||
client().index(indexRequest).actionGet();
|
|
||||||
|
|
||||||
var searchRequest = new SearchRequest("test-index");
|
|
||||||
searchRequest.source().query(new IdsQueryBuilder().addIds("my-id-" + i));
|
|
||||||
var searchResponse = client().search(searchRequest).actionGet();
|
|
||||||
try {
|
|
||||||
var hit = searchResponse.getHits().getHits()[0];
|
|
||||||
assertThat(hit.getId(), equalTo("my-id-" + i));
|
|
||||||
var sourceAsMap = hit.getSourceAsMap();
|
|
||||||
var objectArray = (Map<?, ?>) sourceAsMap.get("object");
|
|
||||||
|
|
||||||
List<?> actual = (List<?>) objectArray.get("field");
|
|
||||||
if (arrayValue == null) {
|
|
||||||
assertThat(actual, nullValue());
|
|
||||||
} else if (arrayValue.length == 0) {
|
|
||||||
assertThat(actual, empty());
|
|
||||||
} else {
|
|
||||||
assertThat(actual, Matchers.contains(arrayValue));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
searchResponse.decRef();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
indexService.getShard(0).forceMerge(new ForceMergeRequest("test-index").maxNumSegments(1));
|
|
||||||
try (var searcher = indexService.getShard(0).acquireSearcher(getTestName())) {
|
|
||||||
var reader = searcher.getDirectoryReader();
|
|
||||||
for (int i = 0; i < documents.size(); i++) {
|
|
||||||
var document = reader.storedFields().document(i);
|
|
||||||
// Verify that there is no ignored source:
|
|
||||||
Set<String> storedFieldNames = new LinkedHashSet<>(document.getFields().stream().map(IndexableField::name).toList());
|
|
||||||
if (IndexSettings.RECOVERY_USE_SYNTHETIC_SOURCE.isEnabled()) {
|
|
||||||
assertThat(storedFieldNames, contains("_id"));
|
|
||||||
} else {
|
|
||||||
assertThat(storedFieldNames, containsInAnyOrder("_id", "_recovery_source"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var fieldInfo = FieldInfos.getMergedFieldInfos(reader).fieldInfo("object.field.offsets");
|
|
||||||
assertThat(fieldInfo.getDocValuesType(), equalTo(DocValuesType.SORTED));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,299 @@
|
||||||
|
/*
|
||||||
|
* 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", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||||
|
* Public License v 1"; you may not use this file except in compliance with, at
|
||||||
|
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||||
|
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.index.mapper;
|
||||||
|
|
||||||
|
import org.apache.lucene.index.DocValuesType;
|
||||||
|
import org.apache.lucene.index.FieldInfo;
|
||||||
|
import org.apache.lucene.index.FieldInfos;
|
||||||
|
import org.apache.lucene.index.IndexableField;
|
||||||
|
import org.apache.lucene.index.LeafReader;
|
||||||
|
import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeRequest;
|
||||||
|
import org.elasticsearch.action.index.IndexRequest;
|
||||||
|
import org.elasticsearch.action.search.SearchRequest;
|
||||||
|
import org.elasticsearch.action.support.WriteRequest;
|
||||||
|
import org.elasticsearch.common.network.NetworkAddress;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.index.IndexSettings;
|
||||||
|
import org.elasticsearch.index.query.IdsQueryBuilder;
|
||||||
|
import org.elasticsearch.test.ESSingleNodeTestCase;
|
||||||
|
import org.elasticsearch.xcontent.XContentBuilder;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder;
|
||||||
|
import static org.hamcrest.Matchers.contains;
|
||||||
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
|
import static org.hamcrest.Matchers.empty;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.hasKey;
|
||||||
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
|
||||||
|
public abstract class NativeArrayIntegrationTestCase extends ESSingleNodeTestCase {
|
||||||
|
|
||||||
|
public void testSynthesizeEmptyArray() throws Exception {
|
||||||
|
var arrayValues = new Object[][] { new Object[] {} };
|
||||||
|
verifySyntheticArray(arrayValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSynthesizeArrayRandom() throws Exception {
|
||||||
|
var arrayValues = new Object[randomInt(64)];
|
||||||
|
for (int j = 0; j < arrayValues.length; j++) {
|
||||||
|
arrayValues[j] = NetworkAddress.format(randomIp(true));
|
||||||
|
}
|
||||||
|
verifySyntheticArray(new Object[][] { arrayValues });
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSynthesizeArrayInObjectFieldRandom() throws Exception {
|
||||||
|
List<Object[]> documents = new ArrayList<>();
|
||||||
|
int numDocs = randomIntBetween(8, 256);
|
||||||
|
for (int i = 0; i < numDocs; i++) {
|
||||||
|
Object[] document = new Object[randomInt(64)];
|
||||||
|
for (int j = 0; j < document.length; j++) {
|
||||||
|
document[j] = getRandomValue();
|
||||||
|
}
|
||||||
|
documents.add(document);
|
||||||
|
}
|
||||||
|
verifySyntheticArrayInObject(documents);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String getFieldTypeName();
|
||||||
|
|
||||||
|
protected abstract String getRandomValue();
|
||||||
|
|
||||||
|
protected void verifySyntheticArray(Object[][] arrays) throws IOException {
|
||||||
|
var mapping = jsonBuilder().startObject()
|
||||||
|
.startObject("properties")
|
||||||
|
.startObject("field")
|
||||||
|
.field("type", getFieldTypeName())
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject();
|
||||||
|
verifySyntheticArray(arrays, mapping, "_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void verifySyntheticArray(Object[][] arrays, XContentBuilder mapping, String... expectedStoredFields) throws IOException {
|
||||||
|
var indexService = createIndex(
|
||||||
|
"test-index",
|
||||||
|
Settings.builder().put("index.mapping.source.mode", "synthetic").put("index.mapping.synthetic_source_keep", "arrays").build(),
|
||||||
|
mapping
|
||||||
|
);
|
||||||
|
for (int i = 0; i < arrays.length; i++) {
|
||||||
|
var array = arrays[i];
|
||||||
|
|
||||||
|
var indexRequest = new IndexRequest("test-index");
|
||||||
|
indexRequest.id("my-id-" + i);
|
||||||
|
var source = jsonBuilder().startObject();
|
||||||
|
if (array != null) {
|
||||||
|
source.startArray("field");
|
||||||
|
for (Object arrayValue : array) {
|
||||||
|
source.value(arrayValue);
|
||||||
|
}
|
||||||
|
source.endArray();
|
||||||
|
} else {
|
||||||
|
source.field("field").nullValue();
|
||||||
|
}
|
||||||
|
indexRequest.source(source.endObject());
|
||||||
|
indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
||||||
|
client().index(indexRequest).actionGet();
|
||||||
|
|
||||||
|
var searchRequest = new SearchRequest("test-index");
|
||||||
|
searchRequest.source().query(new IdsQueryBuilder().addIds("my-id-" + i));
|
||||||
|
var searchResponse = client().search(searchRequest).actionGet();
|
||||||
|
try {
|
||||||
|
var hit = searchResponse.getHits().getHits()[0];
|
||||||
|
assertThat(hit.getId(), equalTo("my-id-" + i));
|
||||||
|
var sourceAsMap = hit.getSourceAsMap();
|
||||||
|
assertThat(sourceAsMap, hasKey("field"));
|
||||||
|
var actualArray = (List<?>) sourceAsMap.get("field");
|
||||||
|
if (array == null) {
|
||||||
|
assertThat(actualArray, nullValue());
|
||||||
|
} else if (array.length == 0) {
|
||||||
|
assertThat(actualArray, empty());
|
||||||
|
} else {
|
||||||
|
assertThat(actualArray, Matchers.contains(array));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
searchResponse.decRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try (var searcher = indexService.getShard(0).acquireSearcher(getTestName())) {
|
||||||
|
var reader = searcher.getDirectoryReader();
|
||||||
|
for (int i = 0; i < arrays.length; i++) {
|
||||||
|
var document = reader.storedFields().document(i);
|
||||||
|
// Verify that there is no ignored source:
|
||||||
|
Set<String> storedFieldNames = new LinkedHashSet<>(document.getFields().stream().map(IndexableField::name).toList());
|
||||||
|
if (IndexSettings.RECOVERY_USE_SYNTHETIC_SOURCE.isEnabled()) {
|
||||||
|
assertThat(storedFieldNames, contains(expectedStoredFields));
|
||||||
|
} else {
|
||||||
|
var copyExpectedStoredFields = new String[expectedStoredFields.length + 1];
|
||||||
|
System.arraycopy(expectedStoredFields, 0, copyExpectedStoredFields, 0, expectedStoredFields.length);
|
||||||
|
copyExpectedStoredFields[copyExpectedStoredFields.length - 1] = "_ignored_source";
|
||||||
|
assertThat(storedFieldNames, containsInAnyOrder(copyExpectedStoredFields));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var fieldInfo = FieldInfos.getMergedFieldInfos(reader).fieldInfo("field.offsets");
|
||||||
|
assertThat(fieldInfo.getDocValuesType(), equalTo(DocValuesType.SORTED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void verifySyntheticObjectArray(List<List<Object[]>> documents) throws IOException {
|
||||||
|
var indexService = createIndex(
|
||||||
|
"test-index",
|
||||||
|
Settings.builder().put("index.mapping.source.mode", "synthetic").put("index.mapping.synthetic_source_keep", "arrays").build(),
|
||||||
|
jsonBuilder().startObject()
|
||||||
|
.startObject("properties")
|
||||||
|
.startObject("object")
|
||||||
|
.startObject("properties")
|
||||||
|
.startObject("field")
|
||||||
|
.field("type", getFieldTypeName())
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
);
|
||||||
|
for (int i = 0; i < documents.size(); i++) {
|
||||||
|
var document = documents.get(i);
|
||||||
|
|
||||||
|
var indexRequest = new IndexRequest("test-index");
|
||||||
|
indexRequest.id("my-id-" + i);
|
||||||
|
var source = jsonBuilder().startObject();
|
||||||
|
source.startArray("object");
|
||||||
|
for (Object[] arrayValue : document) {
|
||||||
|
source.startObject();
|
||||||
|
source.array("field", arrayValue);
|
||||||
|
source.endObject();
|
||||||
|
}
|
||||||
|
source.endArray();
|
||||||
|
indexRequest.source(source.endObject());
|
||||||
|
indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
||||||
|
client().index(indexRequest).actionGet();
|
||||||
|
|
||||||
|
var searchRequest = new SearchRequest("test-index");
|
||||||
|
searchRequest.source().query(new IdsQueryBuilder().addIds("my-id-" + i));
|
||||||
|
var searchResponse = client().search(searchRequest).actionGet();
|
||||||
|
try {
|
||||||
|
var hit = searchResponse.getHits().getHits()[0];
|
||||||
|
assertThat(hit.getId(), equalTo("my-id-" + i));
|
||||||
|
var sourceAsMap = hit.getSourceAsMap();
|
||||||
|
var objectArray = (List<?>) sourceAsMap.get("object");
|
||||||
|
for (int j = 0; j < document.size(); j++) {
|
||||||
|
var expected = document.get(j);
|
||||||
|
List<?> actual = (List<?>) ((Map<?, ?>) objectArray.get(j)).get("field");
|
||||||
|
assertThat(actual, Matchers.contains(expected));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
searchResponse.decRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
indexService.getShard(0).forceMerge(new ForceMergeRequest("test-index").maxNumSegments(1));
|
||||||
|
try (var searcher = indexService.getShard(0).acquireSearcher(getTestName())) {
|
||||||
|
var reader = searcher.getDirectoryReader();
|
||||||
|
for (int i = 0; i < documents.size(); i++) {
|
||||||
|
var document = reader.storedFields().document(i);
|
||||||
|
// Verify that there is ignored source because of leaf array being wrapped by object array:
|
||||||
|
List<String> storedFieldNames = document.getFields().stream().map(IndexableField::name).toList();
|
||||||
|
if (IndexSettings.RECOVERY_USE_SYNTHETIC_SOURCE.isEnabled()) {
|
||||||
|
assertThat(storedFieldNames, contains("_id", "_ignored_source"));
|
||||||
|
} else {
|
||||||
|
assertThat(storedFieldNames, containsInAnyOrder("_id", "_ignored_source", "_recovery_source"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that there is no offset field:
|
||||||
|
LeafReader leafReader = reader.leaves().get(0).reader();
|
||||||
|
for (FieldInfo fieldInfo : leafReader.getFieldInfos()) {
|
||||||
|
String name = fieldInfo.getName();
|
||||||
|
assertFalse("expected no field that contains [offsets] in name, but found [" + name + "]", name.contains("offsets"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var binaryDocValues = leafReader.getBinaryDocValues("object.field.offsets");
|
||||||
|
assertThat(binaryDocValues, nullValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void verifySyntheticArrayInObject(List<Object[]> documents) throws IOException {
|
||||||
|
var indexService = createIndex(
|
||||||
|
"test-index",
|
||||||
|
Settings.builder().put("index.mapping.source.mode", "synthetic").put("index.mapping.synthetic_source_keep", "arrays").build(),
|
||||||
|
jsonBuilder().startObject()
|
||||||
|
.startObject("properties")
|
||||||
|
.startObject("object")
|
||||||
|
.startObject("properties")
|
||||||
|
.startObject("field")
|
||||||
|
.field("type", "keyword")
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
);
|
||||||
|
for (int i = 0; i < documents.size(); i++) {
|
||||||
|
var arrayValue = documents.get(i);
|
||||||
|
|
||||||
|
var indexRequest = new IndexRequest("test-index");
|
||||||
|
indexRequest.id("my-id-" + i);
|
||||||
|
var source = jsonBuilder().startObject();
|
||||||
|
source.startObject("object");
|
||||||
|
source.array("field", arrayValue);
|
||||||
|
source.endObject();
|
||||||
|
indexRequest.source(source.endObject());
|
||||||
|
indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
||||||
|
client().index(indexRequest).actionGet();
|
||||||
|
|
||||||
|
var searchRequest = new SearchRequest("test-index");
|
||||||
|
searchRequest.source().query(new IdsQueryBuilder().addIds("my-id-" + i));
|
||||||
|
var searchResponse = client().search(searchRequest).actionGet();
|
||||||
|
try {
|
||||||
|
var hit = searchResponse.getHits().getHits()[0];
|
||||||
|
assertThat(hit.getId(), equalTo("my-id-" + i));
|
||||||
|
var sourceAsMap = hit.getSourceAsMap();
|
||||||
|
var objectArray = (Map<?, ?>) sourceAsMap.get("object");
|
||||||
|
|
||||||
|
List<?> actual = (List<?>) objectArray.get("field");
|
||||||
|
if (arrayValue == null) {
|
||||||
|
assertThat(actual, nullValue());
|
||||||
|
} else if (arrayValue.length == 0) {
|
||||||
|
assertThat(actual, empty());
|
||||||
|
} else {
|
||||||
|
assertThat(actual, Matchers.contains(arrayValue));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
searchResponse.decRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
indexService.getShard(0).forceMerge(new ForceMergeRequest("test-index").maxNumSegments(1));
|
||||||
|
try (var searcher = indexService.getShard(0).acquireSearcher(getTestName())) {
|
||||||
|
var reader = searcher.getDirectoryReader();
|
||||||
|
for (int i = 0; i < documents.size(); i++) {
|
||||||
|
var document = reader.storedFields().document(i);
|
||||||
|
// Verify that there is no ignored source:
|
||||||
|
Set<String> storedFieldNames = new LinkedHashSet<>(document.getFields().stream().map(IndexableField::name).toList());
|
||||||
|
if (IndexSettings.RECOVERY_USE_SYNTHETIC_SOURCE.isEnabled()) {
|
||||||
|
assertThat(storedFieldNames, contains("_id"));
|
||||||
|
} else {
|
||||||
|
assertThat(storedFieldNames, containsInAnyOrder("_id", "_recovery_source"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var fieldInfo = FieldInfos.getMergedFieldInfos(reader).fieldInfo("object.field.offsets");
|
||||||
|
assertThat(fieldInfo.getDocValuesType(), equalTo(DocValuesType.SORTED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,230 @@
|
||||||
|
/*
|
||||||
|
* 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", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||||
|
* Public License v 1"; you may not use this file except in compliance with, at
|
||||||
|
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||||
|
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.index.mapper;
|
||||||
|
|
||||||
|
import org.apache.lucene.index.DirectoryReader;
|
||||||
|
import org.elasticsearch.common.Strings;
|
||||||
|
import org.elasticsearch.common.bytes.BytesArray;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.xcontent.XContentType;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder;
|
||||||
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
|
||||||
|
public abstract class OffsetDocValuesLoaderTestCase extends MapperServiceTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Settings getIndexSettings() {
|
||||||
|
return Settings.builder()
|
||||||
|
.put("index.mapping.source.mode", "synthetic")
|
||||||
|
.put("index.mapping.synthetic_source_keep", "arrays")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOffsetArrayNoDocValues() throws Exception {
|
||||||
|
String mapping = """
|
||||||
|
{
|
||||||
|
"_doc": {
|
||||||
|
"properties": {
|
||||||
|
"field": {
|
||||||
|
"type": "{{type}}",
|
||||||
|
"doc_values": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".replace("{{type}}", getFieldTypeName());
|
||||||
|
try (var mapperService = createMapperService(mapping)) {
|
||||||
|
var fieldMapper = mapperService.mappingLookup().getMapper("field");
|
||||||
|
assertThat(fieldMapper.getOffsetFieldName(), nullValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOffsetArrayStored() throws Exception {
|
||||||
|
String mapping = """
|
||||||
|
{
|
||||||
|
"_doc": {
|
||||||
|
"properties": {
|
||||||
|
"field": {
|
||||||
|
"type": "{{type}}",
|
||||||
|
"store": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".replace("{{type}}", getFieldTypeName());
|
||||||
|
;
|
||||||
|
try (var mapperService = createMapperService(mapping)) {
|
||||||
|
var fieldMapper = mapperService.mappingLookup().getMapper("field");
|
||||||
|
assertThat(fieldMapper.getOffsetFieldName(), nullValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOffsetMultiFields() throws Exception {
|
||||||
|
String mapping = """
|
||||||
|
{
|
||||||
|
"_doc": {
|
||||||
|
"properties": {
|
||||||
|
"field": {
|
||||||
|
"type": "{{type}}",
|
||||||
|
"fields": {
|
||||||
|
"sub": {
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".replace("{{type}}", getFieldTypeName());
|
||||||
|
try (var mapperService = createMapperService(mapping)) {
|
||||||
|
var fieldMapper = mapperService.mappingLookup().getMapper("field");
|
||||||
|
assertThat(fieldMapper.getOffsetFieldName(), nullValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOffsetArrayNoSyntheticSource() throws Exception {
|
||||||
|
String mapping = """
|
||||||
|
{
|
||||||
|
"_doc": {
|
||||||
|
"properties": {
|
||||||
|
"field": {
|
||||||
|
"type": "{{type}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".replace("{{type}}", getFieldTypeName());
|
||||||
|
try (var mapperService = createMapperService(Settings.EMPTY, mapping)) {
|
||||||
|
var fieldMapper = mapperService.mappingLookup().getMapper("field");
|
||||||
|
assertThat(fieldMapper.getOffsetFieldName(), nullValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOffsetArrayNoSourceArrayKeep() throws Exception {
|
||||||
|
var settingsBuilder = Settings.builder().put("index.mapping.source.mode", "synthetic");
|
||||||
|
String mapping;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
mapping = """
|
||||||
|
{
|
||||||
|
"_doc": {
|
||||||
|
"properties": {
|
||||||
|
"field": {
|
||||||
|
"type": "{{type}}",
|
||||||
|
"synthetic_source_keep": "{{synthetic_source_keep}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".replace("{{synthetic_source_keep}}", randomBoolean() ? "none" : "all").replace("{{type}}", getFieldTypeName());
|
||||||
|
} else {
|
||||||
|
mapping = """
|
||||||
|
{
|
||||||
|
"_doc": {
|
||||||
|
"properties": {
|
||||||
|
"field": {
|
||||||
|
"type": "{{type}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".replace("{{type}}", getFieldTypeName());
|
||||||
|
if (randomBoolean()) {
|
||||||
|
settingsBuilder.put("index.mapping.synthetic_source_keep", "none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try (var mapperService = createMapperService(settingsBuilder.build(), mapping)) {
|
||||||
|
var fieldMapper = mapperService.mappingLookup().getMapper("field");
|
||||||
|
assertThat(fieldMapper.getOffsetFieldName(), nullValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOffsetEmptyArray() throws Exception {
|
||||||
|
verifyOffsets("{\"field\":[]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOffsetArrayWithNulls() throws Exception {
|
||||||
|
verifyOffsets("{\"field\":[null,null,null]}");
|
||||||
|
verifyOffsets("{\"field\":[null,[null],null]}", "{\"field\":[null,null,null]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOffsetArrayRandom() throws Exception {
|
||||||
|
StringBuilder values = new StringBuilder();
|
||||||
|
int numValues = randomIntBetween(0, 256);
|
||||||
|
for (int i = 0; i < numValues; i++) {
|
||||||
|
if (randomInt(10) == 1) {
|
||||||
|
values.append("null");
|
||||||
|
} else {
|
||||||
|
String randomValue = randomValue();
|
||||||
|
values.append('"').append(randomValue).append('"');
|
||||||
|
}
|
||||||
|
if (i != (numValues - 1)) {
|
||||||
|
values.append(',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
verifyOffsets("{\"field\":[" + values + "]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String getFieldTypeName();
|
||||||
|
|
||||||
|
protected abstract String randomValue();
|
||||||
|
|
||||||
|
protected void verifyOffsets(String source) throws IOException {
|
||||||
|
verifyOffsets(source, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void verifyOffsets(String source, String expectedSource) throws IOException {
|
||||||
|
String mapping = """
|
||||||
|
{
|
||||||
|
"_doc": {
|
||||||
|
"properties": {
|
||||||
|
"field": {
|
||||||
|
"type": "{{type}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".replace("{{type}}", getFieldTypeName());
|
||||||
|
verifyOffsets(mapping, source, expectedSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyOffsets(String mapping, String source, String expectedSource) throws IOException {
|
||||||
|
try (var mapperService = createMapperService(mapping)) {
|
||||||
|
var mapper = mapperService.documentMapper();
|
||||||
|
|
||||||
|
try (var directory = newDirectory()) {
|
||||||
|
var iw = indexWriterForSyntheticSource(directory);
|
||||||
|
var doc = mapper.parse(new SourceToParse("_id", new BytesArray(source), XContentType.JSON));
|
||||||
|
doc.updateSeqID(0, 0);
|
||||||
|
doc.version().setLongValue(0);
|
||||||
|
iw.addDocuments(doc.docs());
|
||||||
|
iw.close();
|
||||||
|
try (var indexReader = wrapInMockESDirectoryReader(DirectoryReader.open(directory))) {
|
||||||
|
FieldMapper fieldMapper = (FieldMapper) mapper.mappers().getMapper("field");
|
||||||
|
var syntheticSourceLoader = fieldMapper.syntheticFieldLoader();
|
||||||
|
var leafReader = indexReader.leaves().getFirst().reader();
|
||||||
|
var docValueLoader = syntheticSourceLoader.docValuesLoader(leafReader, new int[] { 0 });
|
||||||
|
assertTrue(docValueLoader.advanceToDoc(0));
|
||||||
|
assertTrue(syntheticSourceLoader.hasValue());
|
||||||
|
XContentBuilder builder = jsonBuilder().startObject();
|
||||||
|
syntheticSourceLoader.write(builder);
|
||||||
|
builder.endObject();
|
||||||
|
|
||||||
|
var actual = Strings.toString(builder);
|
||||||
|
assertEquals(expectedSource, actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -28,9 +28,11 @@ import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.anEmptyMap;
|
import static org.hamcrest.Matchers.anEmptyMap;
|
||||||
|
import static org.hamcrest.Matchers.contains;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.hamcrest.Matchers.sameInstance;
|
import static org.hamcrest.Matchers.sameInstance;
|
||||||
|
@ -143,6 +145,41 @@ public class PipelineConfigurationTests extends AbstractXContentTestCase<Pipelin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void testMapKeyOrderingRoundTrip() throws IOException {
|
||||||
|
// make up two random keys
|
||||||
|
String key1 = randomAlphaOfLength(10);
|
||||||
|
String key2 = randomValueOtherThan(key1, () -> randomAlphaOfLength(10));
|
||||||
|
// stick them as mappings onto themselves in the _meta of a pipeline configuration
|
||||||
|
// this happens to use the _meta as a convenient map to test that the ordering of the key sets is the same
|
||||||
|
String configJson = Strings.format("""
|
||||||
|
{"description": "blah", "_meta" : {"foo": "bar", "%s": "%s", "%s": "%s"}}""", key1, key1, key2, key2);
|
||||||
|
PipelineConfiguration configuration = new PipelineConfiguration(
|
||||||
|
"1",
|
||||||
|
new BytesArray(configJson.getBytes(StandardCharsets.UTF_8)),
|
||||||
|
XContentType.JSON
|
||||||
|
);
|
||||||
|
|
||||||
|
// serialize it to bytes
|
||||||
|
XContentType xContentType = randomFrom(XContentType.values());
|
||||||
|
final BytesReference bytes;
|
||||||
|
try (XContentBuilder builder = XContentBuilder.builder(xContentType.xContent())) {
|
||||||
|
configuration.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||||
|
bytes = BytesReference.bytes(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// deserialize it back
|
||||||
|
ContextParser<Void, PipelineConfiguration> parser = PipelineConfiguration.getParser();
|
||||||
|
XContentParser xContentParser = xContentType.xContent()
|
||||||
|
.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, bytes.streamInput());
|
||||||
|
PipelineConfiguration parsed = parser.parse(xContentParser, null);
|
||||||
|
|
||||||
|
// make sure the _meta key sets are in the same order
|
||||||
|
Set<String> keys1 = ((Map<String, Object>) configuration.getConfig().get("_meta")).keySet();
|
||||||
|
Set<String> keys2 = ((Map<String, Object>) parsed.getConfig().get("_meta")).keySet();
|
||||||
|
assertThat(keys1, contains(keys2.toArray(new String[0])));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PipelineConfiguration createTestInstance() {
|
protected PipelineConfiguration createTestInstance() {
|
||||||
BytesArray config;
|
BytesArray config;
|
||||||
|
|
|
@ -78,6 +78,37 @@ public class ScriptStatsTests extends ESTestCase {
|
||||||
assertThat(Strings.toString(builder), equalTo(expected));
|
assertThat(Strings.toString(builder), equalTo(expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testXContentChunkedHistory() throws Exception {
|
||||||
|
ScriptStats stats = new ScriptStats(5, 6, 7, new TimeSeries(10, 20, 30, 40), new TimeSeries(100, 200, 300, 400));
|
||||||
|
final XContentBuilder builder = XContentFactory.jsonBuilder().prettyPrint();
|
||||||
|
|
||||||
|
builder.startObject();
|
||||||
|
for (var it = stats.toXContentChunked(ToXContent.EMPTY_PARAMS); it.hasNext();) {
|
||||||
|
it.next().toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||||
|
}
|
||||||
|
builder.endObject();
|
||||||
|
String expected = """
|
||||||
|
{
|
||||||
|
"script" : {
|
||||||
|
"compilations" : 5,
|
||||||
|
"cache_evictions" : 6,
|
||||||
|
"compilation_limit_triggered" : 7,
|
||||||
|
"compilations_history" : {
|
||||||
|
"5m" : 10,
|
||||||
|
"15m" : 20,
|
||||||
|
"24h" : 30
|
||||||
|
},
|
||||||
|
"cache_evictions_history" : {
|
||||||
|
"5m" : 100,
|
||||||
|
"15m" : 200,
|
||||||
|
"24h" : 300
|
||||||
|
},
|
||||||
|
"contexts" : [ ]
|
||||||
|
}
|
||||||
|
}""";
|
||||||
|
assertThat(Strings.toString(builder), equalTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
public void testSerializeEmptyTimeSeries() throws IOException {
|
public void testSerializeEmptyTimeSeries() throws IOException {
|
||||||
ScriptContextStats stats = new ScriptContextStats("c", 3333, new TimeSeries(1111), new TimeSeries(2222));
|
ScriptContextStats stats = new ScriptContextStats("c", 3333, new TimeSeries(1111), new TimeSeries(2222));
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,9 @@ public abstract class ESAllocationTestCase extends ESTestCase {
|
||||||
public OptionalDouble getForecastedWriteLoad(IndexMetadata indexMetadata) {
|
public OptionalDouble getForecastedWriteLoad(IndexMetadata indexMetadata) {
|
||||||
return indexMetadata.getForecastedWriteLoad();
|
return indexMetadata.getForecastedWriteLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refreshLicense() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static MockAllocationService createAllocationService() {
|
public static MockAllocationService createAllocationService() {
|
||||||
|
|
|
@ -65,7 +65,7 @@ import org.elasticsearch.core.IOUtils;
|
||||||
import org.elasticsearch.core.Nullable;
|
import org.elasticsearch.core.Nullable;
|
||||||
import org.elasticsearch.core.PathUtils;
|
import org.elasticsearch.core.PathUtils;
|
||||||
import org.elasticsearch.core.TimeValue;
|
import org.elasticsearch.core.TimeValue;
|
||||||
import org.elasticsearch.core.UpdateForV9;
|
import org.elasticsearch.core.UpdateForV10;
|
||||||
import org.elasticsearch.features.NodeFeature;
|
import org.elasticsearch.features.NodeFeature;
|
||||||
import org.elasticsearch.health.node.selection.HealthNode;
|
import org.elasticsearch.health.node.selection.HealthNode;
|
||||||
import org.elasticsearch.index.IndexSettings;
|
import org.elasticsearch.index.IndexSettings;
|
||||||
|
@ -2024,11 +2024,12 @@ public abstract class ESRestTestCase extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deprecation message emitted since 7.12.0 for the rest of the 7.x series. Can be removed in v9 since it is not
|
* Deprecation message emitted since 7.12.0 for the rest of the 7.x series. Can be removed in v10 since it is not
|
||||||
* emitted in v8. Note that this message is also permitted in certain YAML test cases, it can be removed there too.
|
* emitted in v8 or v9 and N-2 versions are now supported.
|
||||||
* See https://github.com/elastic/elasticsearch/issues/66419 for more details.
|
* Note that this message is also permitted in certain YAML test cases, it can be removed there too.
|
||||||
|
* See https://github.com/elastic/elasticsearch/issues/66419 and https://github.com/elastic/elasticsearch/pull/119594 for more details.
|
||||||
*/
|
*/
|
||||||
@UpdateForV9(owner = UpdateForV9.Owner.DATA_MANAGEMENT)
|
@UpdateForV10(owner = UpdateForV10.Owner.DISTRIBUTED_COORDINATION)
|
||||||
private static final String WAIT_FOR_ACTIVE_SHARDS_DEFAULT_DEPRECATION_MESSAGE = "the default value for the ?wait_for_active_shards "
|
private static final String WAIT_FOR_ACTIVE_SHARDS_DEFAULT_DEPRECATION_MESSAGE = "the default value for the ?wait_for_active_shards "
|
||||||
+ "parameter will change from '0' to 'index-setting' in version 8; specify '?wait_for_active_shards=index-setting' "
|
+ "parameter will change from '0' to 'index-setting' in version 8; specify '?wait_for_active_shards=index-setting' "
|
||||||
+ "to adopt the future default behaviour, or '?wait_for_active_shards=0' to preserve today's behaviour";
|
+ "to adopt the future default behaviour, or '?wait_for_active_shards=0' to preserve today's behaviour";
|
||||||
|
|
|
@ -102,6 +102,8 @@ tasks.named("yamlRestCompatTestTransform").configure({ task ->
|
||||||
task.skipTest("esql/190_lookup_join/alias-pattern-multiple", "LOOKUP JOIN does not support index aliases for now")
|
task.skipTest("esql/190_lookup_join/alias-pattern-multiple", "LOOKUP JOIN does not support index aliases for now")
|
||||||
task.skipTest("esql/190_lookup_join/alias-pattern-single", "LOOKUP JOIN does not support index aliases for now")
|
task.skipTest("esql/190_lookup_join/alias-pattern-single", "LOOKUP JOIN does not support index aliases for now")
|
||||||
task.skipTest("esql/180_match_operator/match with disjunctions", "Disjunctions in full text functions work now")
|
task.skipTest("esql/180_match_operator/match with disjunctions", "Disjunctions in full text functions work now")
|
||||||
|
task.skipTest("esql/130_spatial/values unsupported for geo_point", "Spatial types are now supported in VALUES aggregation")
|
||||||
|
task.skipTest("esql/130_spatial/values unsupported for geo_point status code", "Spatial types are now supported in VALUES aggregation")
|
||||||
// Expected deprecation warning to compat yaml tests:
|
// Expected deprecation warning to compat yaml tests:
|
||||||
task.addAllowedWarningRegex(".*rollup functionality will be removed in Elasticsearch.*")
|
task.addAllowedWarningRegex(".*rollup functionality will be removed in Elasticsearch.*")
|
||||||
task.skipTest("esql/40_tsdb/from doc with aggregate_metric_double", "TODO: support for subset of metric fields")
|
task.skipTest("esql/40_tsdb/from doc with aggregate_metric_double", "TODO: support for subset of metric fields")
|
||||||
|
|
|
@ -55,7 +55,8 @@ public record TextEmbeddingBitResults(List<TextEmbeddingByteResults.Embedding> e
|
||||||
if (embeddings.isEmpty()) {
|
if (embeddings.isEmpty()) {
|
||||||
throw new IllegalStateException("Embeddings list is empty");
|
throw new IllegalStateException("Embeddings list is empty");
|
||||||
}
|
}
|
||||||
return embeddings.getFirst().values().length;
|
// bit embeddings are encoded as bytes so convert this to bits
|
||||||
|
return Byte.SIZE * embeddings.getFirst().values().length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -310,6 +310,9 @@
|
||||||
"upgrade_status": {
|
"upgrade_status": {
|
||||||
"type": "keyword"
|
"type": "keyword"
|
||||||
},
|
},
|
||||||
|
"upgrade_attempts": {
|
||||||
|
"type": "date"
|
||||||
|
},
|
||||||
"user_provided_metadata": {
|
"user_provided_metadata": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"enabled": false
|
"enabled": false
|
||||||
|
|
|
@ -37,3 +37,11 @@ testClusters.configureEach {
|
||||||
artifacts {
|
artifacts {
|
||||||
restXpackTests(new File(projectDir, "src/yamlRestTest/resources/rest-api-spec/test"))
|
restXpackTests(new File(projectDir, "src/yamlRestTest/resources/rest-api-spec/test"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tasks.named("yamlRestCompatTestTransform").configure(
|
||||||
|
{ task ->
|
||||||
|
// Behavioral Analytics is deprecated with 9.0.0.
|
||||||
|
task.addAllowedWarning("Behavioral Analytics is deprecated and will be removed in a future release.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
|
@ -27,6 +27,8 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"xpack usage includes Enterprise Search":
|
"xpack usage includes Enterprise Search":
|
||||||
|
- requires:
|
||||||
|
test_runner_features: [ allowed_warnings ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
xpack.usage: { }
|
xpack.usage: { }
|
||||||
|
@ -79,6 +81,8 @@ teardown:
|
||||||
query: "{{query_string}}"
|
query: "{{query_string}}"
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.put_behavioral_analytics:
|
search_application.put_behavioral_analytics:
|
||||||
name: test-analytics-collection
|
name: test-analytics-collection
|
||||||
|
|
||||||
|
@ -113,6 +117,8 @@ teardown:
|
||||||
}
|
}
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.delete_behavioral_analytics:
|
search_application.delete_behavioral_analytics:
|
||||||
name: test-analytics-collection
|
name: test-analytics-collection
|
||||||
|
|
||||||
|
|
|
@ -1,39 +1,55 @@
|
||||||
setup:
|
setup:
|
||||||
|
- requires:
|
||||||
|
test_runner_features: [ allowed_warnings ]
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.put_behavioral_analytics:
|
search_application.put_behavioral_analytics:
|
||||||
name: my-test-analytics-collection
|
name: my-test-analytics-collection
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.put_behavioral_analytics:
|
search_application.put_behavioral_analytics:
|
||||||
name: my-test-analytics-collection2
|
name: my-test-analytics-collection2
|
||||||
|
|
||||||
---
|
---
|
||||||
teardown:
|
teardown:
|
||||||
|
- requires:
|
||||||
|
test_runner_features: [ allowed_warnings ]
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.delete_behavioral_analytics:
|
search_application.delete_behavioral_analytics:
|
||||||
name: my-test-analytics-collection
|
name: my-test-analytics-collection
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.delete_behavioral_analytics:
|
search_application.delete_behavioral_analytics:
|
||||||
name: my-test-analytics-collection2
|
name: my-test-analytics-collection2
|
||||||
|
|
||||||
---
|
---
|
||||||
"Get Analytics Collection for a particular collection":
|
"Get Analytics Collection for a particular collection":
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.get_behavioral_analytics:
|
search_application.get_behavioral_analytics:
|
||||||
name: my-test-analytics-collection
|
name: my-test-analytics-collection
|
||||||
|
|
||||||
- match: {
|
- match: {
|
||||||
"my-test-analytics-collection": {
|
"my-test-analytics-collection": {
|
||||||
event_data_stream: {
|
event_data_stream: {
|
||||||
name: "behavioral_analytics-events-my-test-analytics-collection"
|
name: "behavioral_analytics-events-my-test-analytics-collection"
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
"Get Analytics Collection list":
|
"Get Analytics Collection list":
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.get_behavioral_analytics:
|
search_application.get_behavioral_analytics:
|
||||||
name:
|
name:
|
||||||
|
|
||||||
|
@ -56,6 +72,8 @@ teardown:
|
||||||
"Get Analytics Collection - Resource does not exist":
|
"Get Analytics Collection - Resource does not exist":
|
||||||
- do:
|
- do:
|
||||||
catch: "missing"
|
catch: "missing"
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.get_behavioral_analytics:
|
search_application.get_behavioral_analytics:
|
||||||
name: test-nonexistent-analytics-collection
|
name: test-nonexistent-analytics-collection
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
teardown:
|
teardown:
|
||||||
|
- requires:
|
||||||
|
test_runner_features: [ allowed_warnings ]
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.delete_behavioral_analytics:
|
search_application.delete_behavioral_analytics:
|
||||||
name: test-analytics-collection
|
name: test-analytics-collection
|
||||||
|
|
||||||
---
|
---
|
||||||
"Create Analytics Collection":
|
"Create Analytics Collection":
|
||||||
|
- requires:
|
||||||
|
test_runner_features: [ allowed_warnings ]
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.put_behavioral_analytics:
|
search_application.put_behavioral_analytics:
|
||||||
name: test-analytics-collection
|
name: test-analytics-collection
|
||||||
|
|
||||||
|
@ -14,7 +22,11 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Create Analytics Collection - analytics collection already exists":
|
"Create Analytics Collection - analytics collection already exists":
|
||||||
|
- requires:
|
||||||
|
test_runner_features: [ allowed_warnings ]
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.put_behavioral_analytics:
|
search_application.put_behavioral_analytics:
|
||||||
name: test-analytics-collection
|
name: test-analytics-collection
|
||||||
|
|
||||||
|
@ -22,6 +34,8 @@ teardown:
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
catch: bad_request
|
catch: bad_request
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.put_behavioral_analytics:
|
search_application.put_behavioral_analytics:
|
||||||
name: test-analytics-collection
|
name: test-analytics-collection
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,30 @@
|
||||||
setup:
|
setup:
|
||||||
|
- requires:
|
||||||
|
test_runner_features: [ allowed_warnings ]
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.put_behavioral_analytics:
|
search_application.put_behavioral_analytics:
|
||||||
name: my-test-analytics-collection
|
name: my-test-analytics-collection
|
||||||
|
|
||||||
---
|
---
|
||||||
teardown:
|
teardown:
|
||||||
|
- requires:
|
||||||
|
test_runner_features: [ allowed_warnings ]
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.delete_behavioral_analytics:
|
search_application.delete_behavioral_analytics:
|
||||||
name: my-test-analytics-collection
|
name: my-test-analytics-collection
|
||||||
ignore: 404
|
ignore: 404
|
||||||
|
|
||||||
---
|
---
|
||||||
"Delete Analytics Collection":
|
"Delete Analytics Collection":
|
||||||
|
- requires:
|
||||||
|
test_runner_features: [ allowed_warnings ]
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.delete_behavioral_analytics:
|
search_application.delete_behavioral_analytics:
|
||||||
name: my-test-analytics-collection
|
name: my-test-analytics-collection
|
||||||
|
|
||||||
|
@ -20,13 +32,19 @@ teardown:
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
catch: "missing"
|
catch: "missing"
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.get_behavioral_analytics:
|
search_application.get_behavioral_analytics:
|
||||||
name: my-test-analytics-collection
|
name: my-test-analytics-collection
|
||||||
|
|
||||||
---
|
---
|
||||||
"Delete Analytics Collection - Analytics Collection does not exist":
|
"Delete Analytics Collection - Analytics Collection does not exist":
|
||||||
|
- requires:
|
||||||
|
test_runner_features: [ allowed_warnings ]
|
||||||
- do:
|
- do:
|
||||||
catch: "missing"
|
catch: "missing"
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.delete_behavioral_analytics:
|
search_application.delete_behavioral_analytics:
|
||||||
name: test-nonexistent-analytics-collection
|
name: test-nonexistent-analytics-collection
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
setup:
|
setup:
|
||||||
|
- requires:
|
||||||
|
test_runner_features: [ allowed_warnings ]
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.put_behavioral_analytics:
|
search_application.put_behavioral_analytics:
|
||||||
name: my-test-analytics-collection
|
name: my-test-analytics-collection
|
||||||
|
|
||||||
---
|
---
|
||||||
teardown:
|
teardown:
|
||||||
|
- requires:
|
||||||
|
test_runner_features: [ allowed_warnings ]
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.delete_behavioral_analytics:
|
search_application.delete_behavioral_analytics:
|
||||||
name: my-test-analytics-collection
|
name: my-test-analytics-collection
|
||||||
|
|
||||||
|
@ -13,30 +21,34 @@ teardown:
|
||||||
# Page view event tests #########################################
|
# Page view event tests #########################################
|
||||||
---
|
---
|
||||||
"Post page_view analytics event":
|
"Post page_view analytics event":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "page_view"
|
event_type: "page_view"
|
||||||
body:
|
body:
|
||||||
session:
|
session:
|
||||||
id: "123"
|
id: "123"
|
||||||
user:
|
user:
|
||||||
id: "456"
|
id: "456"
|
||||||
page:
|
page:
|
||||||
url: "https://www.elastic.co"
|
url: "https://www.elastic.co"
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post page_view analytics event - Missing page.url":
|
"Post page_view analytics event - Missing page.url":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
catch: "bad_request"
|
catch: "bad_request"
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "page_view"
|
event_type: "page_view"
|
||||||
|
@ -49,11 +61,13 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post page_view analytics event - With document":
|
"Post page_view analytics event - With document":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "page_view"
|
event_type: "page_view"
|
||||||
|
@ -70,11 +84,13 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post page_view analytics event - With page title":
|
"Post page_view analytics event - With page title":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "page_view"
|
event_type: "page_view"
|
||||||
|
@ -89,11 +105,13 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post page_view analytics event - With referrer":
|
"Post page_view analytics event - With referrer":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "page_view"
|
event_type: "page_view"
|
||||||
|
@ -108,14 +126,16 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post page_view analytics event - debug and session information":
|
"Post page_view analytics event - debug and session information":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers:
|
headers:
|
||||||
X-Forwarded-For: 192.23.12.12
|
X-Forwarded-For: 192.23.12.12
|
||||||
User-Agent: Mozilla/5.0
|
User-Agent: Mozilla/5.0
|
||||||
Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" # user
|
Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "page_view"
|
event_type: "page_view"
|
||||||
|
@ -152,11 +172,13 @@ teardown:
|
||||||
# Search event tests ############################################
|
# Search event tests ############################################
|
||||||
---
|
---
|
||||||
"Post search analytics event":
|
"Post search analytics event":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "search"
|
event_type: "search"
|
||||||
|
@ -170,12 +192,14 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post search analytics event – Missing search query":
|
"Post search analytics event – Missing search query":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
catch: "bad_request"
|
catch: "bad_request"
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "search"
|
event_type: "search"
|
||||||
|
@ -188,11 +212,13 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post search analytics event - With sort order":
|
"Post search analytics event - With sort order":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "search"
|
event_type: "search"
|
||||||
|
@ -208,11 +234,13 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post search analytics event - With sort name and direction":
|
"Post search analytics event - With sort name and direction":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "search"
|
event_type: "search"
|
||||||
|
@ -229,11 +257,13 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post search analytics event - With pagination":
|
"Post search analytics event - With pagination":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "search"
|
event_type: "search"
|
||||||
|
@ -250,11 +280,13 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post search analytics event - With search application":
|
"Post search analytics event - With search application":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "search"
|
event_type: "search"
|
||||||
|
@ -269,10 +301,12 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post search analytics event - With search results":
|
"Post search analytics event - With search results":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
|
@ -287,7 +321,7 @@ teardown:
|
||||||
results:
|
results:
|
||||||
total_results: 150
|
total_results: 150
|
||||||
items:
|
items:
|
||||||
- document :
|
- document:
|
||||||
id: doc-1
|
id: doc-1
|
||||||
- document:
|
- document:
|
||||||
id: doc-2
|
id: doc-2
|
||||||
|
@ -302,11 +336,13 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post search analytics event - With filters":
|
"Post search analytics event - With filters":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "search"
|
event_type: "search"
|
||||||
|
@ -324,14 +360,16 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post search analytics event - debug and session information":
|
"Post search analytics event - debug and session information":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers:
|
headers:
|
||||||
X-Forwarded-For: 192.23.12.12
|
X-Forwarded-For: 192.23.12.12
|
||||||
User-Agent: Mozilla/5.0
|
User-Agent: Mozilla/5.0
|
||||||
Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" # user
|
Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "search"
|
event_type: "search"
|
||||||
|
@ -393,11 +431,13 @@ teardown:
|
||||||
# Search click event tests #######################################
|
# Search click event tests #######################################
|
||||||
---
|
---
|
||||||
"Post search_click analytics event":
|
"Post search_click analytics event":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "search_click"
|
event_type: "search_click"
|
||||||
|
@ -415,14 +455,16 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post search_click analytics event - debug and session information":
|
"Post search_click analytics event - debug and session information":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers:
|
headers:
|
||||||
X-Forwarded-For: 192.23.12.12
|
X-Forwarded-For: 192.23.12.12
|
||||||
User-Agent: Mozilla/5.0
|
User-Agent: Mozilla/5.0
|
||||||
Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" # user
|
Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "search_click"
|
event_type: "search_click"
|
||||||
|
@ -455,11 +497,13 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post search_click analytics event - Page Only":
|
"Post search_click analytics event - Page Only":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "search_click"
|
event_type: "search_click"
|
||||||
|
@ -475,11 +519,13 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post search_click analytics event - Document Only":
|
"Post search_click analytics event - Document Only":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "search_click"
|
event_type: "search_click"
|
||||||
|
@ -496,12 +542,14 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post search_click analytics event – Missing search query":
|
"Post search_click analytics event – Missing search query":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
catch: "bad_request"
|
catch: "bad_request"
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "search_click"
|
event_type: "search_click"
|
||||||
|
@ -516,12 +564,14 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post search_click analytics event – Missing page url and document":
|
"Post search_click analytics event – Missing page url and document":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
catch: "bad_request"
|
catch: "bad_request"
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "search_click"
|
event_type: "search_click"
|
||||||
|
@ -537,12 +587,14 @@ teardown:
|
||||||
# Generic errors tests ###############################################
|
# Generic errors tests ###############################################
|
||||||
---
|
---
|
||||||
"Post analytics event - Analytics collection does not exist":
|
"Post analytics event - Analytics collection does not exist":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
catch: "missing"
|
catch: "missing"
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: test-nonexistent-analytics-collection
|
collection_name: test-nonexistent-analytics-collection
|
||||||
event_type: "page_view"
|
event_type: "page_view"
|
||||||
|
@ -556,12 +608,14 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post analytics event - Event type does not exist":
|
"Post analytics event - Event type does not exist":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
catch: "bad_request"
|
catch: "bad_request"
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "nonexistent-event-type"
|
event_type: "nonexistent-event-type"
|
||||||
|
@ -577,12 +631,14 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post page_view analytics event - Missing session.id":
|
"Post page_view analytics event - Missing session.id":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
catch: "bad_request"
|
catch: "bad_request"
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "page_view"
|
event_type: "page_view"
|
||||||
|
@ -595,12 +651,14 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post page_view analytics event - Missing user.id":
|
"Post page_view analytics event - Missing user.id":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
catch: "bad_request"
|
catch: "bad_request"
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "page_view"
|
event_type: "page_view"
|
||||||
|
@ -613,12 +671,14 @@ teardown:
|
||||||
|
|
||||||
---
|
---
|
||||||
"Post analytics event - Unknown event field":
|
"Post analytics event - Unknown event field":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ allowed_warnings, headers ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
catch: "bad_request"
|
catch: "bad_request"
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.post_behavioral_analytics_event:
|
search_application.post_behavioral_analytics_event:
|
||||||
collection_name: my-test-analytics-collection
|
collection_name: my-test-analytics-collection
|
||||||
event_type: "nonexistent-event-type"
|
event_type: "nonexistent-event-type"
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
setup:
|
setup:
|
||||||
|
- requires:
|
||||||
|
test_runner_features: [ allowed_warnings ]
|
||||||
- do:
|
- do:
|
||||||
indices.create:
|
indices.create:
|
||||||
index: test-search-index1
|
index: test-search-index1
|
||||||
|
@ -27,6 +29,8 @@ setup:
|
||||||
number_of_replicas: 0
|
number_of_replicas: 0
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.put:
|
search_application.put:
|
||||||
name: test-search-application
|
name: test-search-application
|
||||||
body:
|
body:
|
||||||
|
@ -51,6 +55,8 @@ setup:
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.put:
|
search_application.put:
|
||||||
name: test-search-application-1
|
name: test-search-application-1
|
||||||
body:
|
body:
|
||||||
|
@ -110,10 +116,14 @@ setup:
|
||||||
refresh: true
|
refresh: true
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.put_behavioral_analytics:
|
search_application.put_behavioral_analytics:
|
||||||
name: my-test-analytics-collection
|
name: my-test-analytics-collection
|
||||||
---
|
---
|
||||||
teardown:
|
teardown:
|
||||||
|
- requires:
|
||||||
|
test_runner_features: [ allowed_warnings ]
|
||||||
- do:
|
- do:
|
||||||
search_application.delete:
|
search_application.delete:
|
||||||
name: test-search-application
|
name: test-search-application
|
||||||
|
@ -145,18 +155,20 @@ teardown:
|
||||||
ignore: 404
|
ignore: 404
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.delete_behavioral_analytics:
|
search_application.delete_behavioral_analytics:
|
||||||
name: my-test-analytics-collection
|
name: my-test-analytics-collection
|
||||||
|
|
||||||
---
|
---
|
||||||
"Query Search Application with API key":
|
"Query Search Application with API key":
|
||||||
- skip:
|
- requires:
|
||||||
features: headers
|
test_runner_features: [ headers, allowed_warnings ]
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
security.create_api_key:
|
security.create_api_key:
|
||||||
body: >
|
body: >
|
||||||
{
|
{
|
||||||
"name": "search-application-api-key",
|
"name": "search-application-api-key",
|
||||||
"role_descriptors": {
|
"role_descriptors": {
|
||||||
|
@ -176,10 +188,10 @@ teardown:
|
||||||
}
|
}
|
||||||
|
|
||||||
- match: { name: "search-application-api-key" }
|
- match: { name: "search-application-api-key" }
|
||||||
- set: { encoded: api_key_encoded }
|
- set: { encoded: api_key_encoded }
|
||||||
- set: { id: api_key_id }
|
- set: { id: api_key_id }
|
||||||
|
|
||||||
# Query Search Application with default parameters:
|
# Query Search Application with default parameters:
|
||||||
- do:
|
- do:
|
||||||
headers:
|
headers:
|
||||||
Authorization: ApiKey ${api_key_encoded}
|
Authorization: ApiKey ${api_key_encoded}
|
||||||
|
@ -191,7 +203,7 @@ teardown:
|
||||||
- match: { hits.hits.1._id: "doc2" }
|
- match: { hits.hits.1._id: "doc2" }
|
||||||
|
|
||||||
|
|
||||||
# Query Search Application overriding part of the parameters:
|
# Query Search Application overriding part of the parameters:
|
||||||
- do:
|
- do:
|
||||||
headers:
|
headers:
|
||||||
Authorization: ApiKey ${api_key_encoded}
|
Authorization: ApiKey ${api_key_encoded}
|
||||||
|
@ -205,7 +217,7 @@ teardown:
|
||||||
- match: { hits.total.value: 1 }
|
- match: { hits.total.value: 1 }
|
||||||
- match: { hits.hits.0._id: "doc1" }
|
- match: { hits.hits.0._id: "doc1" }
|
||||||
|
|
||||||
# Query Search Application overriding all parameters:
|
# Query Search Application overriding all parameters:
|
||||||
- do:
|
- do:
|
||||||
headers:
|
headers:
|
||||||
Authorization: ApiKey ${api_key_encoded}
|
Authorization: ApiKey ${api_key_encoded}
|
||||||
|
@ -220,7 +232,7 @@ teardown:
|
||||||
- match: { hits.total.value: 1 }
|
- match: { hits.total.value: 1 }
|
||||||
- match: { hits.hits.0._id: "doc2" }
|
- match: { hits.hits.0._id: "doc2" }
|
||||||
|
|
||||||
# Query Search Application with list of parameters:
|
# Query Search Application with list of parameters:
|
||||||
- do:
|
- do:
|
||||||
headers:
|
headers:
|
||||||
Authorization: ApiKey ${api_key_encoded}
|
Authorization: ApiKey ${api_key_encoded}
|
||||||
|
@ -241,7 +253,7 @@ teardown:
|
||||||
- match: { hits.total.value: 1 }
|
- match: { hits.total.value: 1 }
|
||||||
- match: { hits.hits.0._id: "doc2" }
|
- match: { hits.hits.0._id: "doc2" }
|
||||||
|
|
||||||
# Query Search Application with invalid parameter validation:
|
# Query Search Application with invalid parameter validation:
|
||||||
- do:
|
- do:
|
||||||
catch: "bad_request"
|
catch: "bad_request"
|
||||||
headers:
|
headers:
|
||||||
|
@ -253,7 +265,7 @@ teardown:
|
||||||
field_name: field3
|
field_name: field3
|
||||||
field_value: 35
|
field_value: 35
|
||||||
|
|
||||||
# Query Search Application without required parameter:
|
# Query Search Application without required parameter:
|
||||||
- do:
|
- do:
|
||||||
catch: "bad_request"
|
catch: "bad_request"
|
||||||
headers:
|
headers:
|
||||||
|
@ -264,7 +276,7 @@ teardown:
|
||||||
params:
|
params:
|
||||||
field_value: test
|
field_value: test
|
||||||
|
|
||||||
# Query Search Application - not found:
|
# Query Search Application - not found:
|
||||||
- do:
|
- do:
|
||||||
catch: forbidden
|
catch: forbidden
|
||||||
headers:
|
headers:
|
||||||
|
@ -276,11 +288,13 @@ teardown:
|
||||||
field_name: field3
|
field_name: field3
|
||||||
field_value: value3
|
field_value: value3
|
||||||
|
|
||||||
# Get Analytics Collection should be rejected due to a workflow restriction
|
# Get Analytics Collection should be rejected due to a workflow restriction
|
||||||
- do:
|
- do:
|
||||||
catch: forbidden
|
catch: forbidden
|
||||||
headers:
|
headers:
|
||||||
Authorization: ApiKey ${api_key_encoded}
|
Authorization: ApiKey ${api_key_encoded}
|
||||||
|
allowed_warnings:
|
||||||
|
- "Behavioral Analytics is deprecated and will be removed in a future release."
|
||||||
search_application.get_behavioral_analytics:
|
search_application.get_behavioral_analytics:
|
||||||
name:
|
name:
|
||||||
- match: { status: 403 }
|
- match: { status: 403 }
|
||||||
|
@ -288,7 +302,7 @@ teardown:
|
||||||
- match: { error.root_cause.0.type: role_restriction_exception }
|
- match: { error.root_cause.0.type: role_restriction_exception }
|
||||||
- match: { error.root_cause.0.reason: "access restricted by workflow" }
|
- match: { error.root_cause.0.reason: "access restricted by workflow" }
|
||||||
|
|
||||||
# Get API key should not be allowed
|
# Get API key should not be allowed
|
||||||
- do:
|
- do:
|
||||||
catch: forbidden
|
catch: forbidden
|
||||||
headers:
|
headers:
|
||||||
|
@ -300,18 +314,18 @@ teardown:
|
||||||
- match: { error.root_cause.0.type: role_restriction_exception }
|
- match: { error.root_cause.0.type: role_restriction_exception }
|
||||||
- match: { error.root_cause.0.reason: "access restricted by workflow" }
|
- match: { error.root_cause.0.reason: "access restricted by workflow" }
|
||||||
|
|
||||||
# Authenticate with API key should not be allowed
|
# Authenticate with API key should not be allowed
|
||||||
- do:
|
- do:
|
||||||
catch: forbidden
|
catch: forbidden
|
||||||
headers:
|
headers:
|
||||||
Authorization: ApiKey ${api_key_encoded}
|
Authorization: ApiKey ${api_key_encoded}
|
||||||
security.authenticate: {}
|
security.authenticate: { }
|
||||||
- match: { status: 403 }
|
- match: { status: 403 }
|
||||||
- match: { error.type: security_exception }
|
- match: { error.type: security_exception }
|
||||||
- match: { error.root_cause.0.type: role_restriction_exception }
|
- match: { error.root_cause.0.type: role_restriction_exception }
|
||||||
- match: { error.root_cause.0.reason: "access restricted by workflow" }
|
- match: { error.root_cause.0.reason: "access restricted by workflow" }
|
||||||
|
|
||||||
# Direct index search should be rejected due to a workflow restriction
|
# Direct index search should be rejected due to a workflow restriction
|
||||||
- do:
|
- do:
|
||||||
catch: forbidden
|
catch: forbidden
|
||||||
headers:
|
headers:
|
||||||
|
@ -327,11 +341,11 @@ teardown:
|
||||||
- match: { error.root_cause.0.type: role_restriction_exception }
|
- match: { error.root_cause.0.type: role_restriction_exception }
|
||||||
- match: { error.root_cause.0.reason: "access restricted by workflow" }
|
- match: { error.root_cause.0.reason: "access restricted by workflow" }
|
||||||
|
|
||||||
# Creating an API key which can only search 'test-search-application-1'
|
# Creating an API key which can only search 'test-search-application-1'
|
||||||
- do:
|
- do:
|
||||||
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
headers: { Authorization: "Basic ZW50c2VhcmNoLXVzZXI6ZW50c2VhcmNoLXVzZXItcGFzc3dvcmQ=" } # user
|
||||||
security.create_api_key:
|
security.create_api_key:
|
||||||
body: >
|
body: >
|
||||||
{
|
{
|
||||||
"name": "search-application-1-api-key",
|
"name": "search-application-1-api-key",
|
||||||
"role_descriptors": {
|
"role_descriptors": {
|
||||||
|
@ -350,10 +364,10 @@ teardown:
|
||||||
}
|
}
|
||||||
|
|
||||||
- match: { name: "search-application-1-api-key" }
|
- match: { name: "search-application-1-api-key" }
|
||||||
- set: { encoded: api_key_encoded_1 }
|
- set: { encoded: api_key_encoded_1 }
|
||||||
- set: { id: api_key_id_1 }
|
- set: { id: api_key_id_1 }
|
||||||
|
|
||||||
# Query Search Application 'test-search-application' should be denied since API key (api_key_encoded_1) does not have required index privilege
|
# Query Search Application 'test-search-application' should be denied since API key (api_key_encoded_1) does not have required index privilege
|
||||||
- do:
|
- do:
|
||||||
catch: forbidden
|
catch: forbidden
|
||||||
headers:
|
headers:
|
||||||
|
@ -364,7 +378,7 @@ teardown:
|
||||||
- match: { error.type: security_exception }
|
- match: { error.type: security_exception }
|
||||||
- match: { error.reason: "action [indices:data/read/xpack/application/search_application/search] is unauthorized for API key id [${api_key_id_1}] of user [entsearch-user] on indices [test-search-application], this action is granted by the index privileges [read,all]" }
|
- match: { error.reason: "action [indices:data/read/xpack/application/search_application/search] is unauthorized for API key id [${api_key_id_1}] of user [entsearch-user] on indices [test-search-application], this action is granted by the index privileges [read,all]" }
|
||||||
|
|
||||||
# Query Search Application 'test-search-application-1' with new API key (api_key_encoded_1) should be allowed:
|
# Query Search Application 'test-search-application-1' with new API key (api_key_encoded_1) should be allowed:
|
||||||
- do:
|
- do:
|
||||||
headers:
|
headers:
|
||||||
Authorization: ApiKey ${api_key_encoded_1}
|
Authorization: ApiKey ${api_key_encoded_1}
|
||||||
|
|
|
@ -233,6 +233,10 @@ public class EnterpriseSearch extends Plugin implements ActionPlugin, SystemInde
|
||||||
|
|
||||||
private final boolean enabled;
|
private final boolean enabled;
|
||||||
|
|
||||||
|
// NOTE: Behavioral Analytics is deprecated in 9.0 but not 8.x.
|
||||||
|
public static final String BEHAVIORAL_ANALYTICS_DEPRECATION_MESSAGE =
|
||||||
|
"Behavioral Analytics is deprecated and will be removed in a future release.";
|
||||||
|
|
||||||
public EnterpriseSearch(Settings settings) {
|
public EnterpriseSearch(Settings settings) {
|
||||||
this.enabled = XPackSettings.ENTERPRISE_SEARCH_ENABLED.get(settings);
|
this.enabled = XPackSettings.ENTERPRISE_SEARCH_ENABLED.get(settings);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,9 @@ import static org.elasticsearch.xpack.application.analytics.AnalyticsConstants.E
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link AnalyticsCollection} model.
|
* The {@link AnalyticsCollection} model.
|
||||||
|
* @deprecated in 9.0
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class AnalyticsCollection implements Writeable, ToXContentObject {
|
public class AnalyticsCollection implements Writeable, ToXContentObject {
|
||||||
|
|
||||||
private static final ObjectParser<AnalyticsCollection, String> PARSER = ObjectParser.fromBuilder(
|
private static final ObjectParser<AnalyticsCollection, String> PARSER = ObjectParser.fromBuilder(
|
||||||
|
|
|
@ -28,7 +28,9 @@ import static org.elasticsearch.xpack.application.analytics.AnalyticsConstants.E
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A service that allows the resolution of {@link AnalyticsCollection} by name.
|
* A service that allows the resolution of {@link AnalyticsCollection} by name.
|
||||||
|
* @deprecated in 9.0
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class AnalyticsCollectionResolver {
|
public class AnalyticsCollectionResolver {
|
||||||
private final IndexNameExpressionResolver indexNameExpressionResolver;
|
private final IndexNameExpressionResolver indexNameExpressionResolver;
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,9 @@ import static org.elasticsearch.xpack.core.ClientHelper.ENT_SEARCH_ORIGIN;
|
||||||
* Until we have more specific need the {@link AnalyticsCollection} is just another representation
|
* Until we have more specific need the {@link AnalyticsCollection} is just another representation
|
||||||
* of a {@link org.elasticsearch.cluster.metadata.DataStream}.
|
* of a {@link org.elasticsearch.cluster.metadata.DataStream}.
|
||||||
* As a consequence, this service is mostly a facade for the data stream API.
|
* As a consequence, this service is mostly a facade for the data stream API.
|
||||||
|
* @deprecated in 9.0
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class AnalyticsCollectionService {
|
public class AnalyticsCollectionService {
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger(AnalyticsCollectionService.class);
|
private static final Logger logger = LogManager.getLogger(AnalyticsCollectionService.class);
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
|
|
||||||
package org.elasticsearch.xpack.application.analytics;
|
package org.elasticsearch.xpack.application.analytics;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in 9.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public class AnalyticsConstants {
|
public class AnalyticsConstants {
|
||||||
|
|
||||||
private AnalyticsConstants() {}
|
private AnalyticsConstants() {}
|
||||||
|
|
|
@ -17,7 +17,9 @@ import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event emitter will index Analytics events submitted through a @{PostAnalyticsEventAction.Request} request.
|
* Event emitter will index Analytics events submitted through a @{PostAnalyticsEventAction.Request} request.
|
||||||
|
* @deprecated in 9.0
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class AnalyticsEventIngestService {
|
public class AnalyticsEventIngestService {
|
||||||
private final AnalyticsCollectionResolver collectionResolver;
|
private final AnalyticsCollectionResolver collectionResolver;
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,10 @@ import static org.elasticsearch.xpack.application.analytics.AnalyticsConstants.R
|
||||||
import static org.elasticsearch.xpack.application.analytics.AnalyticsConstants.TEMPLATE_VERSION_VARIABLE;
|
import static org.elasticsearch.xpack.application.analytics.AnalyticsConstants.TEMPLATE_VERSION_VARIABLE;
|
||||||
import static org.elasticsearch.xpack.core.ClientHelper.ENT_SEARCH_ORIGIN;
|
import static org.elasticsearch.xpack.core.ClientHelper.ENT_SEARCH_ORIGIN;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in 9.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public class AnalyticsTemplateRegistry extends IndexTemplateRegistry {
|
public class AnalyticsTemplateRegistry extends IndexTemplateRegistry {
|
||||||
|
|
||||||
// This number must be incremented when we make changes to built-in templates.
|
// This number must be incremented when we make changes to built-in templates.
|
||||||
|
|
|
@ -24,6 +24,10 @@ import java.util.Objects;
|
||||||
|
|
||||||
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in 9.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public class DeleteAnalyticsCollectionAction {
|
public class DeleteAnalyticsCollectionAction {
|
||||||
|
|
||||||
public static final String NAME = "cluster:admin/xpack/application/analytics/delete";
|
public static final String NAME = "cluster:admin/xpack/application/analytics/delete";
|
||||||
|
|
|
@ -25,6 +25,10 @@ import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in 9.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public class GetAnalyticsCollectionAction {
|
public class GetAnalyticsCollectionAction {
|
||||||
|
|
||||||
public static final String NAME = "cluster:admin/xpack/application/analytics/get";
|
public static final String NAME = "cluster:admin/xpack/application/analytics/get";
|
||||||
|
|
|
@ -36,6 +36,10 @@ import java.util.Objects;
|
||||||
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||||
import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg;
|
import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in 9.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public class PostAnalyticsEventAction {
|
public class PostAnalyticsEventAction {
|
||||||
|
|
||||||
public static final String NAME = "cluster:admin/xpack/application/analytics/post_event";
|
public static final String NAME = "cluster:admin/xpack/application/analytics/post_event";
|
||||||
|
|
|
@ -23,6 +23,10 @@ import java.util.Objects;
|
||||||
|
|
||||||
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in 9.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public class PutAnalyticsCollectionAction {
|
public class PutAnalyticsCollectionAction {
|
||||||
|
|
||||||
public static final String NAME = "cluster:admin/xpack/application/analytics/put";
|
public static final String NAME = "cluster:admin/xpack/application/analytics/put";
|
||||||
|
|
|
@ -23,6 +23,10 @@ import java.util.List;
|
||||||
|
|
||||||
import static org.elasticsearch.rest.RestRequest.Method.DELETE;
|
import static org.elasticsearch.rest.RestRequest.Method.DELETE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in 9.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
@ServerlessScope(Scope.PUBLIC)
|
@ServerlessScope(Scope.PUBLIC)
|
||||||
public class RestDeleteAnalyticsCollectionAction extends EnterpriseSearchBaseRestHandler {
|
public class RestDeleteAnalyticsCollectionAction extends EnterpriseSearchBaseRestHandler {
|
||||||
public RestDeleteAnalyticsCollectionAction(XPackLicenseState licenseState) {
|
public RestDeleteAnalyticsCollectionAction(XPackLicenseState licenseState) {
|
||||||
|
|
|
@ -23,6 +23,10 @@ import java.util.List;
|
||||||
|
|
||||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in 9.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
@ServerlessScope(Scope.PUBLIC)
|
@ServerlessScope(Scope.PUBLIC)
|
||||||
public class RestGetAnalyticsCollectionAction extends EnterpriseSearchBaseRestHandler {
|
public class RestGetAnalyticsCollectionAction extends EnterpriseSearchBaseRestHandler {
|
||||||
public RestGetAnalyticsCollectionAction(XPackLicenseState licenseState) {
|
public RestGetAnalyticsCollectionAction(XPackLicenseState licenseState) {
|
||||||
|
|
|
@ -29,6 +29,10 @@ import java.util.Map;
|
||||||
|
|
||||||
import static org.elasticsearch.rest.RestRequest.Method.POST;
|
import static org.elasticsearch.rest.RestRequest.Method.POST;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in 9.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
@ServerlessScope(Scope.PUBLIC)
|
@ServerlessScope(Scope.PUBLIC)
|
||||||
public class RestPostAnalyticsEventAction extends EnterpriseSearchBaseRestHandler {
|
public class RestPostAnalyticsEventAction extends EnterpriseSearchBaseRestHandler {
|
||||||
public RestPostAnalyticsEventAction(XPackLicenseState licenseState) {
|
public RestPostAnalyticsEventAction(XPackLicenseState licenseState) {
|
||||||
|
|
|
@ -24,6 +24,10 @@ import java.util.List;
|
||||||
|
|
||||||
import static org.elasticsearch.rest.RestRequest.Method.PUT;
|
import static org.elasticsearch.rest.RestRequest.Method.PUT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in 9.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
@ServerlessScope(Scope.PUBLIC)
|
@ServerlessScope(Scope.PUBLIC)
|
||||||
public class RestPutAnalyticsCollectionAction extends EnterpriseSearchBaseRestHandler {
|
public class RestPutAnalyticsCollectionAction extends EnterpriseSearchBaseRestHandler {
|
||||||
public RestPutAnalyticsCollectionAction(XPackLicenseState licenseState) {
|
public RestPutAnalyticsCollectionAction(XPackLicenseState licenseState) {
|
||||||
|
|
|
@ -15,6 +15,8 @@ import org.elasticsearch.cluster.ClusterState;
|
||||||
import org.elasticsearch.cluster.block.ClusterBlockException;
|
import org.elasticsearch.cluster.block.ClusterBlockException;
|
||||||
import org.elasticsearch.cluster.block.ClusterBlockLevel;
|
import org.elasticsearch.cluster.block.ClusterBlockLevel;
|
||||||
import org.elasticsearch.cluster.service.ClusterService;
|
import org.elasticsearch.cluster.service.ClusterService;
|
||||||
|
import org.elasticsearch.common.logging.DeprecationCategory;
|
||||||
|
import org.elasticsearch.common.logging.DeprecationLogger;
|
||||||
import org.elasticsearch.common.util.concurrent.EsExecutors;
|
import org.elasticsearch.common.util.concurrent.EsExecutors;
|
||||||
import org.elasticsearch.injection.guice.Inject;
|
import org.elasticsearch.injection.guice.Inject;
|
||||||
import org.elasticsearch.tasks.Task;
|
import org.elasticsearch.tasks.Task;
|
||||||
|
@ -22,6 +24,13 @@ import org.elasticsearch.threadpool.ThreadPool;
|
||||||
import org.elasticsearch.transport.TransportService;
|
import org.elasticsearch.transport.TransportService;
|
||||||
import org.elasticsearch.xpack.application.analytics.AnalyticsCollectionService;
|
import org.elasticsearch.xpack.application.analytics.AnalyticsCollectionService;
|
||||||
|
|
||||||
|
import static org.elasticsearch.xpack.application.EnterpriseSearch.BEHAVIORAL_ANALYTICS_API_ENDPOINT;
|
||||||
|
import static org.elasticsearch.xpack.application.EnterpriseSearch.BEHAVIORAL_ANALYTICS_DEPRECATION_MESSAGE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in 9.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public class TransportDeleteAnalyticsCollectionAction extends AcknowledgedTransportMasterNodeAction<
|
public class TransportDeleteAnalyticsCollectionAction extends AcknowledgedTransportMasterNodeAction<
|
||||||
DeleteAnalyticsCollectionAction.Request> {
|
DeleteAnalyticsCollectionAction.Request> {
|
||||||
|
|
||||||
|
@ -59,6 +68,8 @@ public class TransportDeleteAnalyticsCollectionAction extends AcknowledgedTransp
|
||||||
ClusterState state,
|
ClusterState state,
|
||||||
ActionListener<AcknowledgedResponse> listener
|
ActionListener<AcknowledgedResponse> listener
|
||||||
) {
|
) {
|
||||||
|
DeprecationLogger.getLogger(TransportDeleteAnalyticsCollectionAction.class)
|
||||||
|
.warn(DeprecationCategory.API, BEHAVIORAL_ANALYTICS_API_ENDPOINT, BEHAVIORAL_ANALYTICS_DEPRECATION_MESSAGE);
|
||||||
analyticsCollectionService.deleteAnalyticsCollection(state, request, listener.map(v -> AcknowledgedResponse.TRUE));
|
analyticsCollectionService.deleteAnalyticsCollection(state, request, listener.map(v -> AcknowledgedResponse.TRUE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ import org.elasticsearch.action.support.master.TransportMasterNodeReadAction;
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
import org.elasticsearch.cluster.ClusterState;
|
||||||
import org.elasticsearch.cluster.block.ClusterBlockException;
|
import org.elasticsearch.cluster.block.ClusterBlockException;
|
||||||
import org.elasticsearch.cluster.service.ClusterService;
|
import org.elasticsearch.cluster.service.ClusterService;
|
||||||
|
import org.elasticsearch.common.logging.DeprecationCategory;
|
||||||
|
import org.elasticsearch.common.logging.DeprecationLogger;
|
||||||
import org.elasticsearch.common.util.concurrent.EsExecutors;
|
import org.elasticsearch.common.util.concurrent.EsExecutors;
|
||||||
import org.elasticsearch.injection.guice.Inject;
|
import org.elasticsearch.injection.guice.Inject;
|
||||||
import org.elasticsearch.tasks.Task;
|
import org.elasticsearch.tasks.Task;
|
||||||
|
@ -20,6 +22,13 @@ import org.elasticsearch.threadpool.ThreadPool;
|
||||||
import org.elasticsearch.transport.TransportService;
|
import org.elasticsearch.transport.TransportService;
|
||||||
import org.elasticsearch.xpack.application.analytics.AnalyticsCollectionService;
|
import org.elasticsearch.xpack.application.analytics.AnalyticsCollectionService;
|
||||||
|
|
||||||
|
import static org.elasticsearch.xpack.application.EnterpriseSearch.BEHAVIORAL_ANALYTICS_API_ENDPOINT;
|
||||||
|
import static org.elasticsearch.xpack.application.EnterpriseSearch.BEHAVIORAL_ANALYTICS_DEPRECATION_MESSAGE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in 9.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public class TransportGetAnalyticsCollectionAction extends TransportMasterNodeReadAction<
|
public class TransportGetAnalyticsCollectionAction extends TransportMasterNodeReadAction<
|
||||||
GetAnalyticsCollectionAction.Request,
|
GetAnalyticsCollectionAction.Request,
|
||||||
GetAnalyticsCollectionAction.Response> {
|
GetAnalyticsCollectionAction.Response> {
|
||||||
|
@ -54,6 +63,8 @@ public class TransportGetAnalyticsCollectionAction extends TransportMasterNodeRe
|
||||||
ClusterState state,
|
ClusterState state,
|
||||||
ActionListener<GetAnalyticsCollectionAction.Response> listener
|
ActionListener<GetAnalyticsCollectionAction.Response> listener
|
||||||
) {
|
) {
|
||||||
|
DeprecationLogger.getLogger(TransportDeleteAnalyticsCollectionAction.class)
|
||||||
|
.warn(DeprecationCategory.API, BEHAVIORAL_ANALYTICS_API_ENDPOINT, BEHAVIORAL_ANALYTICS_DEPRECATION_MESSAGE);
|
||||||
analyticsCollectionService.getAnalyticsCollection(state, request, listener);
|
analyticsCollectionService.getAnalyticsCollection(state, request, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,17 +10,25 @@ package org.elasticsearch.xpack.application.analytics.action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
import org.elasticsearch.action.ActionListener;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
import org.elasticsearch.action.support.ActionFilters;
|
||||||
import org.elasticsearch.action.support.HandledTransportAction;
|
import org.elasticsearch.action.support.HandledTransportAction;
|
||||||
|
import org.elasticsearch.cluster.service.ClusterService;
|
||||||
|
import org.elasticsearch.common.logging.DeprecationCategory;
|
||||||
|
import org.elasticsearch.common.logging.DeprecationLogger;
|
||||||
import org.elasticsearch.common.util.concurrent.EsExecutors;
|
import org.elasticsearch.common.util.concurrent.EsExecutors;
|
||||||
import org.elasticsearch.injection.guice.Inject;
|
import org.elasticsearch.injection.guice.Inject;
|
||||||
import org.elasticsearch.tasks.Task;
|
import org.elasticsearch.tasks.Task;
|
||||||
import org.elasticsearch.transport.TransportService;
|
import org.elasticsearch.transport.TransportService;
|
||||||
import org.elasticsearch.xpack.application.analytics.AnalyticsEventIngestService;
|
import org.elasticsearch.xpack.application.analytics.AnalyticsEventIngestService;
|
||||||
|
|
||||||
|
import static org.elasticsearch.xpack.application.EnterpriseSearch.BEHAVIORAL_ANALYTICS_API_ENDPOINT;
|
||||||
|
import static org.elasticsearch.xpack.application.EnterpriseSearch.BEHAVIORAL_ANALYTICS_DEPRECATION_MESSAGE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transport implementation for the {@link PostAnalyticsEventAction}.
|
* Transport implementation for the {@link PostAnalyticsEventAction}.
|
||||||
* It executes the {@link AnalyticsEventIngestService#addEvent} method if the XPack license is valid, else it calls
|
* It executes the {@link AnalyticsEventIngestService#addEvent} method if the XPack license is valid, else it calls
|
||||||
* the listener's onFailure method with the appropriate exception.
|
* the listener's onFailure method with the appropriate exception.
|
||||||
|
* @deprecated in 9.0
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class TransportPostAnalyticsEventAction extends HandledTransportAction<
|
public class TransportPostAnalyticsEventAction extends HandledTransportAction<
|
||||||
PostAnalyticsEventAction.Request,
|
PostAnalyticsEventAction.Request,
|
||||||
PostAnalyticsEventAction.Response> {
|
PostAnalyticsEventAction.Response> {
|
||||||
|
@ -31,7 +39,8 @@ public class TransportPostAnalyticsEventAction extends HandledTransportAction<
|
||||||
public TransportPostAnalyticsEventAction(
|
public TransportPostAnalyticsEventAction(
|
||||||
TransportService transportService,
|
TransportService transportService,
|
||||||
ActionFilters actionFilters,
|
ActionFilters actionFilters,
|
||||||
AnalyticsEventIngestService eventEmitterService
|
AnalyticsEventIngestService eventEmitterService,
|
||||||
|
ClusterService clusterService
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
PostAnalyticsEventAction.NAME,
|
PostAnalyticsEventAction.NAME,
|
||||||
|
@ -49,6 +58,8 @@ public class TransportPostAnalyticsEventAction extends HandledTransportAction<
|
||||||
PostAnalyticsEventAction.Request request,
|
PostAnalyticsEventAction.Request request,
|
||||||
ActionListener<PostAnalyticsEventAction.Response> listener
|
ActionListener<PostAnalyticsEventAction.Response> listener
|
||||||
) {
|
) {
|
||||||
|
DeprecationLogger.getLogger(TransportDeleteAnalyticsCollectionAction.class)
|
||||||
|
.warn(DeprecationCategory.API, BEHAVIORAL_ANALYTICS_API_ENDPOINT, BEHAVIORAL_ANALYTICS_DEPRECATION_MESSAGE);
|
||||||
this.eventEmitterService.addEvent(request, listener);
|
this.eventEmitterService.addEvent(request, listener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,23 @@ import org.elasticsearch.cluster.ClusterState;
|
||||||
import org.elasticsearch.cluster.block.ClusterBlockException;
|
import org.elasticsearch.cluster.block.ClusterBlockException;
|
||||||
import org.elasticsearch.cluster.block.ClusterBlockLevel;
|
import org.elasticsearch.cluster.block.ClusterBlockLevel;
|
||||||
import org.elasticsearch.cluster.service.ClusterService;
|
import org.elasticsearch.cluster.service.ClusterService;
|
||||||
|
import org.elasticsearch.common.logging.DeprecationCategory;
|
||||||
|
import org.elasticsearch.common.logging.DeprecationLogger;
|
||||||
import org.elasticsearch.common.util.concurrent.EsExecutors;
|
import org.elasticsearch.common.util.concurrent.EsExecutors;
|
||||||
|
import org.elasticsearch.features.FeatureService;
|
||||||
import org.elasticsearch.injection.guice.Inject;
|
import org.elasticsearch.injection.guice.Inject;
|
||||||
import org.elasticsearch.tasks.Task;
|
import org.elasticsearch.tasks.Task;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
import org.elasticsearch.transport.TransportService;
|
import org.elasticsearch.transport.TransportService;
|
||||||
import org.elasticsearch.xpack.application.analytics.AnalyticsCollectionService;
|
import org.elasticsearch.xpack.application.analytics.AnalyticsCollectionService;
|
||||||
|
|
||||||
|
import static org.elasticsearch.xpack.application.EnterpriseSearch.BEHAVIORAL_ANALYTICS_API_ENDPOINT;
|
||||||
|
import static org.elasticsearch.xpack.application.EnterpriseSearch.BEHAVIORAL_ANALYTICS_DEPRECATION_MESSAGE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in 9.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public class TransportPutAnalyticsCollectionAction extends TransportMasterNodeAction<
|
public class TransportPutAnalyticsCollectionAction extends TransportMasterNodeAction<
|
||||||
PutAnalyticsCollectionAction.Request,
|
PutAnalyticsCollectionAction.Request,
|
||||||
PutAnalyticsCollectionAction.Response> {
|
PutAnalyticsCollectionAction.Response> {
|
||||||
|
@ -33,7 +43,8 @@ public class TransportPutAnalyticsCollectionAction extends TransportMasterNodeAc
|
||||||
ClusterService clusterService,
|
ClusterService clusterService,
|
||||||
ThreadPool threadPool,
|
ThreadPool threadPool,
|
||||||
ActionFilters actionFilters,
|
ActionFilters actionFilters,
|
||||||
AnalyticsCollectionService analyticsCollectionService
|
AnalyticsCollectionService analyticsCollectionService,
|
||||||
|
FeatureService featureService
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
PutAnalyticsCollectionAction.NAME,
|
PutAnalyticsCollectionAction.NAME,
|
||||||
|
@ -60,6 +71,8 @@ public class TransportPutAnalyticsCollectionAction extends TransportMasterNodeAc
|
||||||
ClusterState state,
|
ClusterState state,
|
||||||
ActionListener<PutAnalyticsCollectionAction.Response> listener
|
ActionListener<PutAnalyticsCollectionAction.Response> listener
|
||||||
) {
|
) {
|
||||||
|
DeprecationLogger.getLogger(TransportDeleteAnalyticsCollectionAction.class)
|
||||||
|
.warn(DeprecationCategory.API, BEHAVIORAL_ANALYTICS_API_ENDPOINT, BEHAVIORAL_ANALYTICS_DEPRECATION_MESSAGE);
|
||||||
analyticsCollectionService.putAnalyticsCollection(state, request, listener);
|
analyticsCollectionService.putAnalyticsCollection(state, request, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,9 @@ import static org.elasticsearch.xpack.application.analytics.AnalyticsConstants.E
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents Analytics events object meant to be emitted to the event queue.
|
* This class represents Analytics events object meant to be emitted to the event queue.
|
||||||
|
* @deprecated in 9.0
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class AnalyticsEvent implements Writeable, ToXContentObject {
|
public class AnalyticsEvent implements Writeable, ToXContentObject {
|
||||||
|
|
||||||
public static final ParseField TIMESTAMP_FIELD = new ParseField("@timestamp");
|
public static final ParseField TIMESTAMP_FIELD = new ParseField("@timestamp");
|
||||||
|
|
|
@ -29,7 +29,9 @@ import static org.elasticsearch.xpack.application.analytics.event.AnalyticsEvent
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A utility class for parsing {@link AnalyticsEvent} objects from payloads (such as HTTP POST request bodies) or input streams.
|
* A utility class for parsing {@link AnalyticsEvent} objects from payloads (such as HTTP POST request bodies) or input streams.
|
||||||
|
* @deprecated in 9.0
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class AnalyticsEventFactory {
|
public class AnalyticsEventFactory {
|
||||||
|
|
||||||
public static final AnalyticsEventFactory INSTANCE = new AnalyticsEventFactory();
|
public static final AnalyticsEventFactory INSTANCE = new AnalyticsEventFactory();
|
||||||
|
|
|
@ -22,6 +22,10 @@ import static org.elasticsearch.xpack.application.analytics.event.parser.field.P
|
||||||
import static org.elasticsearch.xpack.application.analytics.event.parser.field.SessionAnalyticsEventField.SESSION_FIELD;
|
import static org.elasticsearch.xpack.application.analytics.event.parser.field.SessionAnalyticsEventField.SESSION_FIELD;
|
||||||
import static org.elasticsearch.xpack.application.analytics.event.parser.field.UserAnalyticsEventField.USER_FIELD;
|
import static org.elasticsearch.xpack.application.analytics.event.parser.field.UserAnalyticsEventField.USER_FIELD;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in 9.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public class PageViewAnalyticsEvent {
|
public class PageViewAnalyticsEvent {
|
||||||
private static final ObjectParser<AnalyticsEvent.Builder, AnalyticsEvent.Context> PARSER = ObjectParser.fromBuilder(
|
private static final ObjectParser<AnalyticsEvent.Builder, AnalyticsEvent.Context> PARSER = ObjectParser.fromBuilder(
|
||||||
"page_view_event",
|
"page_view_event",
|
||||||
|
|
|
@ -20,6 +20,10 @@ import static org.elasticsearch.xpack.application.analytics.event.parser.field.S
|
||||||
import static org.elasticsearch.xpack.application.analytics.event.parser.field.SessionAnalyticsEventField.SESSION_FIELD;
|
import static org.elasticsearch.xpack.application.analytics.event.parser.field.SessionAnalyticsEventField.SESSION_FIELD;
|
||||||
import static org.elasticsearch.xpack.application.analytics.event.parser.field.UserAnalyticsEventField.USER_FIELD;
|
import static org.elasticsearch.xpack.application.analytics.event.parser.field.UserAnalyticsEventField.USER_FIELD;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in 9.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public class SearchAnalyticsEvent {
|
public class SearchAnalyticsEvent {
|
||||||
private static final ObjectParser<AnalyticsEvent.Builder, AnalyticsEvent.Context> PARSER = ObjectParser.fromBuilder(
|
private static final ObjectParser<AnalyticsEvent.Builder, AnalyticsEvent.Context> PARSER = ObjectParser.fromBuilder(
|
||||||
"search_event",
|
"search_event",
|
||||||
|
|
|
@ -24,6 +24,10 @@ import static org.elasticsearch.xpack.application.analytics.event.parser.field.S
|
||||||
import static org.elasticsearch.xpack.application.analytics.event.parser.field.SessionAnalyticsEventField.SESSION_FIELD;
|
import static org.elasticsearch.xpack.application.analytics.event.parser.field.SessionAnalyticsEventField.SESSION_FIELD;
|
||||||
import static org.elasticsearch.xpack.application.analytics.event.parser.field.UserAnalyticsEventField.USER_FIELD;
|
import static org.elasticsearch.xpack.application.analytics.event.parser.field.UserAnalyticsEventField.USER_FIELD;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in 9.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public class SearchClickAnalyticsEvent {
|
public class SearchClickAnalyticsEvent {
|
||||||
|
|
||||||
private static final ObjectParser<AnalyticsEvent.Builder, AnalyticsEvent.Context> PARSER = ObjectParser.fromBuilder(
|
private static final ObjectParser<AnalyticsEvent.Builder, AnalyticsEvent.Context> PARSER = ObjectParser.fromBuilder(
|
||||||
|
|
|
@ -18,6 +18,10 @@ import java.util.Map;
|
||||||
|
|
||||||
import static org.elasticsearch.common.Strings.requireNonBlank;
|
import static org.elasticsearch.common.Strings.requireNonBlank;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated in 9.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public class DocumentAnalyticsEventField {
|
public class DocumentAnalyticsEventField {
|
||||||
|
|
||||||
public static final ParseField DOCUMENT_FIELD = new ParseField("document");
|
public static final ParseField DOCUMENT_FIELD = new ParseField("document");
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue