diff --git a/build-tools-internal/version.properties b/build-tools-internal/version.properties index 544cc47d4a9c0..f78a98f8dc827 100644 --- a/build-tools-internal/version.properties +++ b/build-tools-internal/version.properties @@ -1,5 +1,5 @@ elasticsearch = 8.0.0 -lucene = 9.0.0-snapshot-cfd9f9f98f7 +lucene = 9.0.0-snapshot-8b68bf60c98 bundled_jdk_vendor = adoptium bundled_jdk = 17+35 diff --git a/build.gradle b/build.gradle index 60a2735f8cbe2..1569cec42e9a5 100644 --- a/build.gradle +++ b/build.gradle @@ -132,9 +132,9 @@ tasks.register("verifyVersions") { * after the backport of the backcompat code is complete. */ -boolean bwc_tests_enabled = false +boolean bwc_tests_enabled = true // place a PR link here when committing bwc changes: -String bwc_tests_disabled_issue = "https://github.com/elastic/elasticsearch/pull/79385" +String bwc_tests_disabled_issue = "" /* * FIPS 140-2 behavior was fixed in 7.11.0. Before that there is no way to run elasticsearch in a * JVM that is properly configured to be in fips mode with BCFIPS. For now we need to disable diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/migration/GetFeatureUpgradeStatusResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/migration/GetFeatureUpgradeStatusResponse.java index e75d2c7ce2858..545837d7e5b87 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/migration/GetFeatureUpgradeStatusResponse.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/migration/GetFeatureUpgradeStatusResponse.java @@ -25,7 +25,7 @@ public class GetFeatureUpgradeStatusResponse { private static final ParseField FEATURE_UPGRADE_STATUSES = new ParseField("features"); - private static final ParseField UPGRADE_STATUS = new ParseField("upgrade_status"); + private static final ParseField UPGRADE_STATUS = new ParseField("migration_status"); private final List featureUpgradeStatuses; private final String upgradeStatus; @@ -76,7 +76,7 @@ public static class FeatureUpgradeStatus { private static final ParseField FEATURE_NAME = new ParseField("feature_name"); private static final ParseField MINIMUM_INDEX_VERSION = new ParseField("minimum_index_version"); - private static final ParseField UPGRADE_STATUS = new ParseField("upgrade_status"); + private static final ParseField UPGRADE_STATUS = new ParseField("migration_status"); private static final ParseField INDEX_VERSIONS = new ParseField("indices"); @SuppressWarnings("unchecked") diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/MigrationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/MigrationIT.java index 06ee1c97039f6..67d4818d26fc0 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/MigrationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/MigrationIT.java @@ -23,8 +23,8 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.nullValue; public class MigrationIT extends ESRestHighLevelClientTestCase { @@ -42,7 +42,7 @@ public void testGetDeprecationInfo() throws IOException { public void testGetFeatureUpgradeStatus() throws IOException { GetFeatureUpgradeStatusRequest request = new GetFeatureUpgradeStatusRequest(); GetFeatureUpgradeStatusResponse response = highLevelClient().migration().getFeatureUpgradeStatus(request, RequestOptions.DEFAULT); - assertThat(response.getUpgradeStatus(), equalTo("NO_UPGRADE_NEEDED")); + assertThat(response.getUpgradeStatus(), equalTo("NO_MIGRATION_NEEDED")); assertThat(response.getFeatureUpgradeStatuses().size(), greaterThanOrEqualTo(1)); Optional optionalTasksStatus = response.getFeatureUpgradeStatuses().stream() .filter(status -> "tasks".equals(status.getFeatureName())) @@ -52,7 +52,7 @@ public void testGetFeatureUpgradeStatus() throws IOException { GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus tasksStatus = optionalTasksStatus.get(); - assertThat(tasksStatus.getUpgradeStatus(), equalTo("NO_UPGRADE_NEEDED")); + assertThat(tasksStatus.getUpgradeStatus(), equalTo("NO_MIGRATION_NEEDED")); assertThat(tasksStatus.getMinimumIndexVersion(), equalTo(Version.CURRENT.toString())); assertThat(tasksStatus.getFeatureName(), equalTo("tasks")); } @@ -60,11 +60,8 @@ public void testGetFeatureUpgradeStatus() throws IOException { public void testPostFeatureUpgradeStatus() throws IOException { PostFeatureUpgradeRequest request = new PostFeatureUpgradeRequest(); PostFeatureUpgradeResponse response = highLevelClient().migration().postFeatureUpgrade(request, RequestOptions.DEFAULT); - assertThat(response.isAccepted(), equalTo(true)); - assertThat(response.getFeatures().size(), equalTo(1)); - PostFeatureUpgradeResponse.Feature feature = response.getFeatures().get(0); - assertThat(feature.getFeatureName(), equalTo("security")); - assertThat(response.getReason(), nullValue()); - assertThat(response.getElasticsearchException(), nullValue()); + assertThat(response.isAccepted(), equalTo(false)); + assertThat(response.getFeatures(), hasSize(0)); + assertThat(response.getReason(), equalTo("No system indices require migration")); } } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetComponentTemplatesResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetComponentTemplatesResponseTests.java index 8099370e02fa9..5f5070d3f4a11 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetComponentTemplatesResponseTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetComponentTemplatesResponseTests.java @@ -13,6 +13,7 @@ import org.elasticsearch.cluster.metadata.Template; import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.test.ESTestCase; @@ -79,7 +80,7 @@ private static void toXContent(GetComponentTemplatesResponse response, XContentB builder.startObject(); builder.field("name", e.getKey()); builder.field("component_template"); - e.getValue().toXContent(builder, null); + e.getValue().toXContent(builder, ToXContent.EMPTY_PARAMS); builder.endObject(); } builder.endArray(); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetComposableIndexTemplatesResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetComposableIndexTemplatesResponseTests.java index b93af425dd932..a241fb235b2b6 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetComposableIndexTemplatesResponseTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetComposableIndexTemplatesResponseTests.java @@ -10,6 +10,7 @@ import org.elasticsearch.cluster.metadata.ComposableIndexTemplate; import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.test.ESTestCase; import java.io.IOException; @@ -53,7 +54,7 @@ private static void toXContent(GetComposableIndexTemplatesResponse response, XCo builder.startObject(); builder.field("name", e.getKey()); builder.field("index_template"); - e.getValue().toXContent(builder, null); + e.getValue().toXContent(builder, ToXContent.EMPTY_PARAMS); builder.endObject(); } builder.endArray(); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/migration/GetFeatureUpgradeStatusResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/migration/GetFeatureUpgradeStatusResponseTests.java index f6483dd1651b5..7b3bb7cf6004b 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/migration/GetFeatureUpgradeStatusResponseTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/migration/GetFeatureUpgradeStatusResponseTests.java @@ -40,10 +40,14 @@ protected org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStat randomAlphaOfLengthBetween(3, 20), randomFrom(Version.CURRENT, Version.CURRENT.minimumCompatibilityVersion()), randomFrom(org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.values()), - randomList(4, - () -> new org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.IndexVersion( + randomList( + 4, + () -> new org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.IndexInfo( randomAlphaOfLengthBetween(3, 20), - randomFrom(Version.CURRENT, Version.CURRENT.minimumCompatibilityVersion()))) + randomFrom(Version.CURRENT, Version.CURRENT.minimumCompatibilityVersion()), + null + ) + ) )), randomFrom(org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.values()) ); @@ -78,12 +82,12 @@ protected void assertInstances( assertThat(clientStatus.getIndexVersions(), hasSize(serverTestStatus.getIndexVersions().size())); for (int j = 0; i < clientStatus.getIndexVersions().size(); i++) { - org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.IndexVersion serverIndexVersion + org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.IndexInfo serverIndexInfo = serverTestStatus.getIndexVersions().get(j); GetFeatureUpgradeStatusResponse.IndexVersion clientIndexVersion = clientStatus.getIndexVersions().get(j); - assertThat(clientIndexVersion.getIndexName(), equalTo(serverIndexVersion.getIndexName())); - assertThat(clientIndexVersion.getVersion(), equalTo(serverIndexVersion.getVersion().toString())); + assertThat(clientIndexVersion.getIndexName(), equalTo(serverIndexInfo.getIndexName())); + assertThat(clientIndexVersion.getVersion(), equalTo(serverIndexInfo.getVersion().toString())); } } } diff --git a/docs/reference/migration/apis/feature_upgrade.asciidoc b/docs/reference/migration/apis/feature_upgrade.asciidoc index 88cd5d477f4d2..738227c5eae25 100644 --- a/docs/reference/migration/apis/feature_upgrade.asciidoc +++ b/docs/reference/migration/apis/feature_upgrade.asciidoc @@ -24,7 +24,7 @@ and to trigger an automated system upgrade that might potentially involve downti ==== {api-prereq-title} * If the {es} {security-features} are enabled, you must have the `manage` -<> to use this API. (TODO: true?) +<> to use this API. [[feature-upgrade-api-example]] ==== {api-examples-title} @@ -46,79 +46,80 @@ Example response: { "feature_name" : "async_search", "minimum_index_version" : "8.0.0", - "upgrade_status" : "NO_UPGRADE_NEEDED", + "migration_status" : "NO_MIGRATION_NEEDED", "indices" : [ ] }, { "feature_name" : "enrich", "minimum_index_version" : "8.0.0", - "upgrade_status" : "NO_UPGRADE_NEEDED", + "migration_status" : "NO_MIGRATION_NEEDED", "indices" : [ ] }, { "feature_name" : "fleet", "minimum_index_version" : "8.0.0", - "upgrade_status" : "NO_UPGRADE_NEEDED", + "migration_status" : "NO_MIGRATION_NEEDED", "indices" : [ ] }, { "feature_name" : "geoip", "minimum_index_version" : "8.0.0", - "upgrade_status" : "NO_UPGRADE_NEEDED", + "migration_status" : "NO_MIGRATION_NEEDED", "indices" : [ ] }, { "feature_name" : "kibana", "minimum_index_version" : "8.0.0", - "upgrade_status" : "NO_UPGRADE_NEEDED", + "migration_status" : "NO_MIGRATION_NEEDED", "indices" : [ ] }, { "feature_name" : "logstash_management", "minimum_index_version" : "8.0.0", - "upgrade_status" : "NO_UPGRADE_NEEDED", + "migration_status" : "NO_MIGRATION_NEEDED", "indices" : [ ] }, { "feature_name" : "machine_learning", "minimum_index_version" : "8.0.0", - "upgrade_status" : "NO_UPGRADE_NEEDED", + "migration_status" : "NO_MIGRATION_NEEDED", "indices" : [ ] }, { "feature_name" : "searchable_snapshots", "minimum_index_version" : "8.0.0", - "upgrade_status" : "NO_UPGRADE_NEEDED", + "migration_status" : "NO_MIGRATION_NEEDED", "indices" : [ ] }, { "feature_name" : "security", "minimum_index_version" : "8.0.0", - "upgrade_status" : "NO_UPGRADE_NEEDED", + "migration_status" : "NO_MIGRATION_NEEDED", "indices" : [ ] }, { "feature_name" : "tasks", "minimum_index_version" : "8.0.0", - "upgrade_status" : "NO_UPGRADE_NEEDED", + "migration_status" : "NO_MIGRATION_NEEDED", "indices" : [ ] }, { "feature_name" : "transform", "minimum_index_version" : "8.0.0", - "upgrade_status" : "NO_UPGRADE_NEEDED", + "migration_status" : "NO_MIGRATION_NEEDED", "indices" : [ ] }, { "feature_name" : "watcher", "minimum_index_version" : "8.0.0", - "upgrade_status" : "NO_UPGRADE_NEEDED", + "migration_status" : "NO_MIGRATION_NEEDED", "indices" : [ ] } ], - "upgrade_status" : "NO_UPGRADE_NEEDED" + "migration_status" : "NO_MIGRATION_NEEDED" } -------------------------------------------------- +// TESTRESPONSE[s/"minimum_index_version" : "8.0.0"/"minimum_index_version" : $body.$_path/] This response tells us that Elasticsearch security needs its internal indices upgraded before we can upgrade the cluster to 8.0. @@ -143,6 +144,7 @@ Example response: ] } -------------------------------------------------- +// TESTRESPONSE[skip: can't actually upgrade system indices in these tests] This tells us that the security index is being upgraded. To check the overall status of the upgrade, call the endpoint with GET. diff --git a/docs/reference/migration/migrate_8_0.asciidoc b/docs/reference/migration/migrate_8_0.asciidoc index e166a6eb83740..dad7b225b936a 100644 --- a/docs/reference/migration/migrate_8_0.asciidoc +++ b/docs/reference/migration/migrate_8_0.asciidoc @@ -25,7 +25,6 @@ coming[8.0.0] * <> * <> * <> -* <> * <> * <> * <> @@ -128,7 +127,6 @@ include::migrate_8_0/indices.asciidoc[] include::migrate_8_0/ingest.asciidoc[] include::migrate_8_0/java.asciidoc[] include::migrate_8_0/mappings.asciidoc[] -include::migrate_8_0/monitoring.asciidoc[] include::migrate_8_0/network.asciidoc[] include::migrate_8_0/node.asciidoc[] include::migrate_8_0/packaging.asciidoc[] diff --git a/docs/reference/migration/migrate_8_0/monitoring.asciidoc b/docs/reference/migration/migrate_8_0/monitoring.asciidoc deleted file mode 100644 index cdedfe29982c5..0000000000000 --- a/docs/reference/migration/migrate_8_0/monitoring.asciidoc +++ /dev/null @@ -1,47 +0,0 @@ -[discrete] -[[breaking_80_monitoring_changes]] -=== Monitoring changes - -//NOTE: The notable-breaking-changes tagged regions are re-used in the -//Installation and Upgrade Guide - -//tag::notable-breaking-changes[] -.The `use_ingest` setting on Monitoring exporter configurations has been removed. -[%collapsible] -==== -*Details* + -The `xpack.monitoring.exporters.*.use_ingest` property was deprecated in 7.16.0 and -has been removed. This parameter controlled the creation of pipelines for monitoring -indices that previously had no function. - -*Impact* + -Discontinue the use of the `xpack.monitoring.exporters.*.use_ingest` setting. -==== - -.The `index.pipeline.master_timeout` setting on Monitoring HTTP exporter configurations has been removed. -[%collapsible] -==== -*Details* + -The `xpack.monitoring.exporters.*.index.pipeline.master_timeout` property was -deprecated in 7.16.0. This parameter set the timeout when waiting for the remote -Monitoring cluster to create pipelines. Those pipelines for monitoring indices previously -had no function and are now removed in 8.0.0. - -*Impact* + -Discontinue the use of the `xpack.monitoring.exporters.*.index.pipeline.master_timeout` setting. -==== - -.The `index.template.create_legacy_templates` setting on Monitoring HTTP exporter configurations has been removed. -[%collapsible] -==== -*Details* + -The `xpack.monitoring.exporters.*.index.template.create_legacy_templates` property was -deprecated in 7.16.0. This parameter instructed the exporter to install the previous version -of monitoring templates on the monitoring cluster. These older templates were meant to assist -in transitioning to the current monitoring data format. They are currently empty and are no -longer of any use. - -*Impact* + -Discontinue the use of the `xpack.monitoring.exporters.*.index.template.create_legacy_templates` setting. -==== -//end::notable-breaking-changes[] diff --git a/docs/reference/migration/migrate_8_0/security.asciidoc b/docs/reference/migration/migrate_8_0/security.asciidoc index 3bda161e49161..d93fa300e0743 100644 --- a/docs/reference/migration/migrate_8_0/security.asciidoc +++ b/docs/reference/migration/migrate_8_0/security.asciidoc @@ -165,6 +165,37 @@ Specifying this setting in a transport profile in `elasticsearch.yml` will result in an error on startup. ==== +[discrete] +[[saml-realm-nameid-changes]] +.The `nameid_format` SAML realm setting no longer has a default value. +[%collapsible] +==== +*Details* + +In SAML, Identity Providers (IdPs) can either be explicitly configured to +release a `NameID` with a specific format, or configured to attempt to conform +with the requirements of a Service Provider (SP). The SP declares its +requirements in the `NameIDPolicy` element of a SAML Authentication Request. +In {es}, the `nameid_format` SAML realm setting controls the `NameIDPolicy` +value. + +Previously, the default value for `nameid_format` was +`urn:oasis:names:tc:SAML:2.0:nameid-format:transient`. This setting created +authentication requests that required the IdP to release `NameID` with a +`transient` format. + +The default value has been removed, which means that {es} will create SAML Authentication Requests by default that don't put this requirement on the +IdP. If you want to retain the previous behavior, set `nameid_format` to +`urn:oasis:names:tc:SAML:2.0:nameid-format:transient`. + +*Impact* + +If you currently don't configure `nameid_format` explicitly, it's possible +that your IdP will reject authentication requests from {es} because the requests +do not specify a `NameID` format (and your IdP is configured to expect one). +This mismatch can result in a broken SAML configuration. If you're unsure whether +your IdP is explicitly configured to use a certain `NameID` format and you want to retain current behavior +, try setting `nameid_format` to `urn:oasis:names:tc:SAML:2.0:nameid-format:transient` explicitly. +==== + [discrete] [[ssl-validation-changes]] ===== SSL/TLS configuration validation @@ -287,7 +318,7 @@ on startup. [discrete] [[ssl-misc-changes]] -===== Other SSL/TLS changes +===== Other SSL/TLS changes .PKCS#11 keystores and trustores cannot be configured in `elasticsearch.yml` [%collapsible] @@ -307,7 +338,7 @@ Use of a PKCS#11 keystore or truststore as the JRE's default store is not affect *Impact* + If you have a PKCS#11 keystore configured within your `elasticsearch.yml` file, you must remove that -configuration and switch to a supported keystore type, or configure your PKCS#11 keystore as the +configuration and switch to a supported keystore type, or configure your PKCS#11 keystore as the JRE default store. ==== @@ -360,6 +391,7 @@ renamed to better reflect its intended use. Assign users with the `kibana_user` role to the `kibana_admin` role. Discontinue use of the `kibana_user` role. ==== + // end::notable-breaking-changes[] // These are non-notable changes @@ -373,7 +405,7 @@ Discontinue use of the `kibana_user` role. [%collapsible] ==== *Details* + -If `xpack.security.fips_mode.enabled` is true (see <>), +If `xpack.security.fips_mode.enabled` is true (see <>), the value of `xpack.security.authc.password_hashing.algorithm` now defaults to `pbkdf2_stretch`. diff --git a/docs/reference/transform/apis/index.asciidoc b/docs/reference/transform/apis/index.asciidoc index b0948a7adb3dc..34a0b92c2d344 100644 --- a/docs/reference/transform/apis/index.asciidoc +++ b/docs/reference/transform/apis/index.asciidoc @@ -13,5 +13,6 @@ include::preview-transform.asciidoc[leveloffset=+2] include::start-transform.asciidoc[leveloffset=+2] //STOP include::stop-transform.asciidoc[leveloffset=+2] -//UPDATE -include::update-transform.asciidoc[leveloffset=+2] \ No newline at end of file +//UPDATE-UPGRADE +include::update-transform.asciidoc[leveloffset=+2] +include::upgrade-transforms.asciidoc[leveloffset=+2] \ No newline at end of file diff --git a/docs/reference/transform/apis/upgrade-transforms.asciidoc b/docs/reference/transform/apis/upgrade-transforms.asciidoc index 7c95a31e63243..505f070a344b5 100644 --- a/docs/reference/transform/apis/upgrade-transforms.asciidoc +++ b/docs/reference/transform/apis/upgrade-transforms.asciidoc @@ -1,14 +1,14 @@ [role="xpack"] [testenv="basic"] [[upgrade-transforms]] -= Upgrade {transform} API += Upgrade {transforms} API [subs="attributes"] ++++ -Upgrade {transform} +Upgrade {transforms} ++++ -Upgrades all {transform}s. +Upgrades all {transforms}. [[upgrade-transforms-request]] == {api-request-title} @@ -22,36 +22,68 @@ Requires the following privileges: * cluster: `manage_transform` (the `transform_admin` built-in role grants this privilege) -* source indices: `read`, `view_index_metadata` -* destination index: `read`, `index`. [[upgrade-transforms-desc]] == {api-description-title} -This API upgrades all existing {transform}s. +{transforms-cap} are compatible across minor versions and between supported +major versions. However, over time, the format of {transform} configuration +information may change. This API identifies {transforms} which have a legacy +configuration format and upgrades them to the latest version; including clean up +of the internal data structures that store {transform} state and checkpoints. +{transform-cap} upgrade does not effect the source and destination indices. + +If a {transform} upgrade step fails, the upgrade stops, and an error is returned +about the underlying issue. Resolve the issue then re-run the process again. A +summary is returned when the upgrade is finished. + +For a major version update – for example, from 7.16 to 8.0 –, it is recommended +to have a recent cluster backup prior to performing a {transform} upgrade which +can be run either before or after an {es} upgrade. However, it is recommended to +perform it before upgrading {es} to the next major version to ensure +{ctransforms} remain running. + + +[IMPORTANT] +==== + +* When {es} {security-features} are enabled, your {transform} remembers the +roles of the user who created or updated it last. In contrast to +<>, a {transform} upgrade does not change the +stored roles, therefore the role used to read source data and write to the +destination index remains unchanged. + +==== + [[upgrade-transforms-query-parms]] == {api-query-parms-title} `dry_run`:: - (Optional, Boolean) When `true`, only checks for updates but does not execute them. + (Optional, Boolean) When `true`, only checks for updates but does not execute + them. Defaults to `false`. + [[upgrade-transforms-example]] == {api-examples-title} +To upgrade the legacy {transforms} to the latest configuration format, perform +the following API call: + [source,console] -------------------------------------------------- POST _transform/_upgrade -------------------------------------------------- // TEST[setup:simple_kibana_continuous_pivot] -When all {transform}s are upgraded, you receive a summary: +When all {transforms} are upgraded, you receive a summary: [source,console-result] ---- { + "updated": 2, "no_action": 1 } ---- -// TESTRESPONSE[s/"no_action" : 1/"no_action" : $body.no_action/] +// TESTRESPONSE[skip:TBD] diff --git a/modules/lang-expression/licenses/lucene-expressions-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/modules/lang-expression/licenses/lucene-expressions-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..d92d8f3fc6b2f --- /dev/null +++ b/modules/lang-expression/licenses/lucene-expressions-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +93676b57287ef17b5eda8f0ab5aa91ac27781b30 \ No newline at end of file diff --git a/modules/lang-expression/licenses/lucene-expressions-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/modules/lang-expression/licenses/lucene-expressions-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index fe9352ca233c8..0000000000000 --- a/modules/lang-expression/licenses/lucene-expressions-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -3bc34dea0b46e0f6429b054f848e2611d6e1d3e7 \ No newline at end of file diff --git a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/org.elasticsearch.script.fields.txt b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/org.elasticsearch.script.fields.txt index 61986fab9423c..af330de477216 100644 --- a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/org.elasticsearch.script.fields.txt +++ b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/org.elasticsearch.script.fields.txt @@ -13,9 +13,6 @@ class org.elasticsearch.script.field.Field @dynamic_type { String getName() boolean isEmpty() int size() - List getValues() - def getValue(def) - def getValue(int, def) } class org.elasticsearch.script.DocBasedScript { diff --git a/modules/legacy-geo/licenses/lucene-spatial-extras-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/modules/legacy-geo/licenses/lucene-spatial-extras-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..a3ea1b0fef522 --- /dev/null +++ b/modules/legacy-geo/licenses/lucene-spatial-extras-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +fabf62d18d45d4eb4e6199005f92624233b3f2e4 \ No newline at end of file diff --git a/modules/legacy-geo/licenses/lucene-spatial-extras-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/modules/legacy-geo/licenses/lucene-spatial-extras-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index 1c96b8e73ff65..0000000000000 --- a/modules/legacy-geo/licenses/lucene-spatial-extras-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -d9f8584667012bf09c446512ee25191b5d00ceed \ No newline at end of file diff --git a/modules/reindex/src/internalClusterTest/java/org/elasticsearch/migration/FeatureMigrationIT.java b/modules/reindex/src/internalClusterTest/java/org/elasticsearch/migration/FeatureMigrationIT.java new file mode 100644 index 0000000000000..09765b472c770 --- /dev/null +++ b/modules/reindex/src/internalClusterTest/java/org/elasticsearch/migration/FeatureMigrationIT.java @@ -0,0 +1,388 @@ +/* + * 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 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 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch.migration; + +import org.apache.lucene.util.SetOnce; +import org.elasticsearch.Version; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusAction; +import org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusRequest; +import org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse; +import org.elasticsearch.action.admin.cluster.migration.PostFeatureUpgradeAction; +import org.elasticsearch.action.admin.cluster.migration.PostFeatureUpgradeRequest; +import org.elasticsearch.action.admin.cluster.migration.PostFeatureUpgradeResponse; +import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; +import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; +import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse; +import org.elasticsearch.action.index.IndexRequestBuilder; +import org.elasticsearch.action.support.ActiveShardCount; +import org.elasticsearch.client.Client; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.IndexMetadata; +import org.elasticsearch.cluster.metadata.Metadata; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.indices.SystemIndexDescriptor; +import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.plugins.SystemIndexPlugin; +import org.elasticsearch.reindex.ReindexPlugin; +import org.elasticsearch.test.ESIntegTestCase; +import org.elasticsearch.upgrades.FeatureMigrationResults; +import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.xcontent.json.JsonXContent; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.hamcrest.Matchers.aMapWithSize; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasKey; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +public class FeatureMigrationIT extends ESIntegTestCase { + @Override + protected Settings nodeSettings(int nodeOrdinal, Settings otherSettings) { + return Settings.builder().put(super.nodeSettings(nodeOrdinal, otherSettings)).build(); + } + + @Override + protected boolean forbidPrivateIndexSettings() { + // We need to be able to set the index creation version manually. + return false; + } + + @Override + protected Collection> nodePlugins() { + List> plugins = new ArrayList<>(super.nodePlugins()); + plugins.add(TestPlugin.class); + plugins.add(ReindexPlugin.class); + return plugins; + } + + public void testMigrateInternalManagedSystemIndex() throws Exception { + createSystemIndexForDescriptor(INTERNAL_MANAGED); + createSystemIndexForDescriptor(INTERNAL_UNMANAGED); + createSystemIndexForDescriptor(EXTERNAL_MANAGED); + createSystemIndexForDescriptor(EXTERNAL_UNMANAGED); + + ensureGreen(); + + SetOnce preUpgradeHookCalled = new SetOnce<>(); + SetOnce postUpgradeHookCalled = new SetOnce<>(); + TestPlugin.preMigrationHook.set(clusterState -> { + // Check that the ordering of these calls is correct. + assertThat(postUpgradeHookCalled.get(), nullValue()); + Map metadata = new HashMap<>(); + metadata.put("stringKey", "stringValue"); + metadata.put("intKey", 42); + { + Map innerMetadata = new HashMap<>(); + innerMetadata.put("innerKey", "innerValue"); + + metadata.put("mapKey", innerMetadata); + } + metadata.put("listKey", Arrays.asList(1, 2, 3, 4)); + preUpgradeHookCalled.set(true); + return metadata; + }); + + TestPlugin.postMigrationHook.set((clusterState, metadata) -> { + assertThat(preUpgradeHookCalled.get(), is(true)); + + assertThat( + metadata, + hasEntry("stringKey", "stringValue") + ); + assertThat(metadata, hasEntry("intKey", 42)); + assertThat(metadata, hasEntry("listKey", Arrays.asList(1,2,3,4))); + assertThat(metadata, hasKey("mapKey")); + @SuppressWarnings("unchecked") + Map innerMap = (Map) metadata.get("mapKey"); + assertThat(innerMap, hasEntry("innerKey", "innerValue")); + + // We shouldn't have any results in the cluster state as no features have fully finished yet. + FeatureMigrationResults currentResults = clusterState.metadata().custom(FeatureMigrationResults.TYPE); + assertThat(currentResults, nullValue()); + postUpgradeHookCalled.set(true); + }); + + PostFeatureUpgradeRequest migrationRequest = new PostFeatureUpgradeRequest(); + PostFeatureUpgradeResponse migrationResponse = client().execute(PostFeatureUpgradeAction.INSTANCE, migrationRequest).get(); + assertThat(migrationResponse.getReason(), nullValue()); + assertThat(migrationResponse.getElasticsearchException(), nullValue()); + final Set migratingFeatures = migrationResponse.getFeatures() + .stream() + .map(PostFeatureUpgradeResponse.Feature::getFeatureName) + .collect(Collectors.toSet()); + assertThat(migratingFeatures, hasItem(FEATURE_NAME)); + + GetFeatureUpgradeStatusRequest getStatusRequest = new GetFeatureUpgradeStatusRequest(); + assertBusy(() -> { + GetFeatureUpgradeStatusResponse statusResponse = client().execute(GetFeatureUpgradeStatusAction.INSTANCE, getStatusRequest) + .get(); + logger.info(Strings.toString(statusResponse)); + assertThat(statusResponse.getUpgradeStatus(), equalTo(GetFeatureUpgradeStatusResponse.UpgradeStatus.NO_MIGRATION_NEEDED)); + }); + + assertTrue("the pre-migration hook wasn't actually called", preUpgradeHookCalled.get()); + assertTrue("the post-migration hook wasn't actually called", postUpgradeHookCalled.get()); + + Metadata finalMetadata = client().admin().cluster().prepareState().get().getState().metadata(); + // Check that the results metadata is what we expect. + FeatureMigrationResults currentResults = finalMetadata.custom(FeatureMigrationResults.TYPE); + assertThat(currentResults, notNullValue()); + assertThat(currentResults.getFeatureStatuses(), allOf(aMapWithSize(1), hasKey(FEATURE_NAME))); + assertThat(currentResults.getFeatureStatuses().get(FEATURE_NAME).succeeded(), is(true)); + assertThat(currentResults.getFeatureStatuses().get(FEATURE_NAME).getFailedIndexName(), nullValue()); + assertThat(currentResults.getFeatureStatuses().get(FEATURE_NAME).getException(), nullValue()); + + assertIndexHasCorrectProperties( + finalMetadata, + ".int-man-old-reindexed-for-8", + INTERNAL_MANAGED_FLAG_VALUE, + true, + true, + Arrays.asList(".int-man-old", ".internal-managed-alias") + ); + assertIndexHasCorrectProperties( + finalMetadata, + ".int-unman-old-reindexed-for-8", + INTERNAL_UNMANAGED_FLAG_VALUE, + false, + true, + Collections.singletonList(".int-unman-old") + ); + assertIndexHasCorrectProperties( + finalMetadata, + ".ext-man-old-reindexed-for-8", + EXTERNAL_MANAGED_FLAG_VALUE, + true, + false, + Arrays.asList(".ext-man-old", ".external-managed-alias") + ); + assertIndexHasCorrectProperties( + finalMetadata, + ".ext-unman-old-reindexed-for-8", + EXTERNAL_UNMANAGED_FLAG_VALUE, + false, + false, + Collections.singletonList(".ext-unman-old") + ); + } + + public void assertIndexHasCorrectProperties( + Metadata metadata, + String indexName, + int settingsFlagValue, + boolean isManaged, + boolean isInternal, + Collection aliasNames) { + IndexMetadata imd = metadata.index(indexName); + assertThat(imd.getSettings().get(FlAG_SETTING_KEY), equalTo(Integer.toString(settingsFlagValue))); + final Map mapping = imd.mapping().getSourceAsMap(); + @SuppressWarnings("unchecked") + final Map meta = (Map) mapping.get("_meta"); + assertThat(meta.get(DESCRIPTOR_MANAGED_META_KEY), is(isManaged)); + assertThat(meta.get(DESCRIPTOR_INTERNAL_META_KEY), is(isInternal)); + + assertThat(imd.isSystem(), is(true)); + + Set actualAliasNames = imd.getAliases().keySet(); + assertThat(actualAliasNames, containsInAnyOrder(aliasNames.toArray())); + + IndicesStatsResponse indexStats = client().admin().indices().prepareStats(imd.getIndex().getName()).setDocs(true).get(); + assertThat(indexStats.getIndex(imd.getIndex().getName()).getTotal().getDocs().getCount(), is((long) INDEX_DOC_COUNT)); + } + + public void createSystemIndexForDescriptor(SystemIndexDescriptor descriptor) throws InterruptedException { + assertTrue( + "the strategy used below to create index names for descriptors without a primary index name only works for simple patterns", + descriptor.getIndexPattern().endsWith("*") + ); + String indexName = Optional.ofNullable(descriptor.getPrimaryIndex()).orElse(descriptor.getIndexPattern().replace("*", "old")); + CreateIndexRequestBuilder createRequest = prepareCreate(indexName); + createRequest.setWaitForActiveShards(ActiveShardCount.ALL); + if (descriptor.getSettings() != null) { + createRequest.setSettings(Settings.builder().put("index.version.created", Version.CURRENT).build()); + } else { + createRequest.setSettings( + createSimpleSettings( + Version.V_7_0_0, + descriptor.isInternal() ? INTERNAL_UNMANAGED_FLAG_VALUE : EXTERNAL_UNMANAGED_FLAG_VALUE + ) + ); + } + if (descriptor.getMappings() == null) { + createRequest.setMapping(createSimpleMapping(false, descriptor.isInternal())); + } + CreateIndexResponse response = createRequest.get(); + assertTrue(response.isShardsAcknowledged()); + + List docs = new ArrayList<>(INDEX_DOC_COUNT); + for (int i = 0; i < INDEX_DOC_COUNT; i++) { + docs.add(client().prepareIndex(indexName).setId(Integer.toString(i)).setSource("some_field", "words words")); + } + indexRandom(true, docs); + IndicesStatsResponse indexStats = client().admin().indices().prepareStats(indexName).setDocs(true).get(); + assertThat(indexStats.getIndex(indexName).getTotal().getDocs().getCount(), is((long) INDEX_DOC_COUNT)); + } + + static final String VERSION_META_KEY = "version"; + static final Version META_VERSION = Version.CURRENT; + static final String DESCRIPTOR_MANAGED_META_KEY = "desciptor_managed"; + static final String DESCRIPTOR_INTERNAL_META_KEY = "descriptor_internal"; + static final String FEATURE_NAME = "A-test-feature"; // Sorts alphabetically before the feature from MultiFeatureMigrationIT + static final String ORIGIN = FeatureMigrationIT.class.getSimpleName(); + static final String FlAG_SETTING_KEY = IndexMetadata.INDEX_PRIORITY_SETTING.getKey(); + static final int INDEX_DOC_COUNT = 100; // arbitrarily chosen + + static final int INTERNAL_MANAGED_FLAG_VALUE = 1; + static final int INTERNAL_UNMANAGED_FLAG_VALUE = 2; + static final int EXTERNAL_MANAGED_FLAG_VALUE = 3; + static final int EXTERNAL_UNMANAGED_FLAG_VALUE = 4; + static final SystemIndexDescriptor INTERNAL_MANAGED = SystemIndexDescriptor.builder() + .setIndexPattern(".int-man-*") + .setAliasName(".internal-managed-alias") + .setPrimaryIndex(".int-man-old") + .setType(SystemIndexDescriptor.Type.INTERNAL_MANAGED) + .setSettings(createSimpleSettings(Version.V_7_0_0, INTERNAL_MANAGED_FLAG_VALUE)) + .setMappings(createSimpleMapping(true, true)) + .setOrigin(ORIGIN) + .setVersionMetaKey(VERSION_META_KEY) + .setAllowedElasticProductOrigins(Collections.emptyList()) + .setMinimumNodeVersion(Version.V_7_0_0) + .setPriorSystemIndexDescriptors(Collections.emptyList()) + .build(); + static final SystemIndexDescriptor INTERNAL_UNMANAGED = SystemIndexDescriptor.builder() + .setIndexPattern(".int-unman-*") + .setType(SystemIndexDescriptor.Type.INTERNAL_UNMANAGED) + .setOrigin(ORIGIN) + .setVersionMetaKey(VERSION_META_KEY) + .setAllowedElasticProductOrigins(Collections.emptyList()) + .setMinimumNodeVersion(Version.V_7_0_0) + .setPriorSystemIndexDescriptors(Collections.emptyList()) + .build(); + static final SystemIndexDescriptor EXTERNAL_MANAGED = SystemIndexDescriptor.builder() + .setIndexPattern(".ext-man-*") + .setAliasName(".external-managed-alias") + .setPrimaryIndex(".ext-man-old") + .setType(SystemIndexDescriptor.Type.EXTERNAL_MANAGED) + .setSettings(createSimpleSettings(Version.V_7_0_0, EXTERNAL_MANAGED_FLAG_VALUE)) + .setMappings(createSimpleMapping(true, false)) + .setOrigin(ORIGIN) + .setVersionMetaKey(VERSION_META_KEY) + .setAllowedElasticProductOrigins(Collections.singletonList(ORIGIN)) + .setMinimumNodeVersion(Version.V_7_0_0) + .setPriorSystemIndexDescriptors(Collections.emptyList()) + .build(); + static final SystemIndexDescriptor EXTERNAL_UNMANAGED = SystemIndexDescriptor.builder() + .setIndexPattern(".ext-unman-*") + .setType(SystemIndexDescriptor.Type.EXTERNAL_UNMANAGED) + .setOrigin(ORIGIN) + .setVersionMetaKey(VERSION_META_KEY) + .setAllowedElasticProductOrigins(Collections.singletonList(ORIGIN)) + .setMinimumNodeVersion(Version.V_7_0_0) + .setPriorSystemIndexDescriptors(Collections.emptyList()) + .build(); + + static Settings createSimpleSettings(Version creationVersion, int flagSettingValue) { + return Settings.builder() + .put(IndexMetadata.INDEX_NUMBER_OF_SHARDS_SETTING.getKey(), 1) + .put(IndexMetadata.INDEX_NUMBER_OF_REPLICAS_SETTING.getKey(), 0) + .put(FlAG_SETTING_KEY, flagSettingValue) + .put("index.version.created", creationVersion) + .build(); + } + + static String createSimpleMapping(boolean descriptorManaged, boolean descriptorInternal) { + try (XContentBuilder builder = JsonXContent.contentBuilder()) { + builder.startObject(); + { + builder.startObject("_meta"); + builder.field(VERSION_META_KEY, META_VERSION); + builder.field(DESCRIPTOR_MANAGED_META_KEY, descriptorManaged); + builder.field(DESCRIPTOR_INTERNAL_META_KEY, descriptorInternal); + builder.endObject(); + + builder.field("dynamic", "strict"); + builder.startObject("properties"); + { + builder.startObject("some_field"); + builder.field("type", "keyword"); + builder.endObject(); + } + builder.endObject(); + } + builder.endObject(); + return Strings.toString(builder); + } catch (IOException e) { + // Just rethrow, it should be impossible for this to throw here + throw new AssertionError(e); + } + } + + public static class TestPlugin extends Plugin implements SystemIndexPlugin { + public static final AtomicReference>> preMigrationHook = new AtomicReference<>(); + public static final AtomicReference>> postMigrationHook = new AtomicReference<>(); + + public TestPlugin() { + + } + + @Override + public String getFeatureName() { + return FEATURE_NAME; + } + + @Override + public String getFeatureDescription() { + return "a plugin for testing system index migration"; + } + + @Override + public Collection getSystemIndexDescriptors(Settings settings) { + return Arrays.asList(INTERNAL_MANAGED, INTERNAL_UNMANAGED, EXTERNAL_MANAGED, EXTERNAL_UNMANAGED); + } + + @Override + public void prepareForIndicesMigration(ClusterService clusterService, Client client, ActionListener> listener) { + listener.onResponse(preMigrationHook.get().apply(clusterService.state())); + } + + @Override + public void indicesMigrationComplete( + Map preUpgradeMetadata, + ClusterService clusterService, + Client client, + ActionListener listener + ) { + postMigrationHook.get().accept(clusterService.state(), preUpgradeMetadata); + listener.onResponse(true); + } + } +} diff --git a/modules/reindex/src/internalClusterTest/java/org/elasticsearch/migration/MultiFeatureMigrationIT.java b/modules/reindex/src/internalClusterTest/java/org/elasticsearch/migration/MultiFeatureMigrationIT.java new file mode 100644 index 0000000000000..832990a973e53 --- /dev/null +++ b/modules/reindex/src/internalClusterTest/java/org/elasticsearch/migration/MultiFeatureMigrationIT.java @@ -0,0 +1,302 @@ +/* + * 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 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 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch.migration; + +import org.apache.lucene.util.SetOnce; +import org.elasticsearch.Version; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusAction; +import org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusRequest; +import org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse; +import org.elasticsearch.action.admin.cluster.migration.PostFeatureUpgradeAction; +import org.elasticsearch.action.admin.cluster.migration.PostFeatureUpgradeRequest; +import org.elasticsearch.action.admin.cluster.migration.PostFeatureUpgradeResponse; +import org.elasticsearch.client.Client; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.Metadata; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.indices.SystemIndexDescriptor; +import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.plugins.SystemIndexPlugin; +import org.elasticsearch.reindex.ReindexPlugin; +import org.elasticsearch.upgrades.FeatureMigrationResults; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.hamcrest.Matchers.aMapWithSize; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.hasKey; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +public class MultiFeatureMigrationIT extends FeatureMigrationIT { + + @Override + protected Settings nodeSettings(int nodeOrdinal, Settings otherSettings) { + return Settings.builder().put(super.nodeSettings(nodeOrdinal, otherSettings)).build(); + } + + @Override + protected boolean forbidPrivateIndexSettings() { + // We need to be able to set the index creation version manually. + return false; + } + + @Override + protected Collection> nodePlugins() { + List> plugins = new ArrayList<>(super.nodePlugins()); + plugins.add(FeatureMigrationIT.TestPlugin.class); + plugins.add(SecondPlugin.class); + plugins.add(ReindexPlugin.class); + return plugins; + } + + // Sorts alphabetically after the feature from MultiFeatureMigrationIT + private static final String SECOND_FEATURE_NAME = "B-test-feature"; + private static final String ORIGIN = MultiFeatureMigrationIT.class.getSimpleName(); + private static final String VERSION_META_KEY = "version"; + static final int SECOND_FEATURE_IDX_FLAG_VALUE = 0; + + public void testMultipleFeatureMigration() throws Exception { + // All the indices from FeatureMigrationIT + createSystemIndexForDescriptor(INTERNAL_MANAGED); + createSystemIndexForDescriptor(INTERNAL_UNMANAGED); + createSystemIndexForDescriptor(EXTERNAL_MANAGED); + createSystemIndexForDescriptor(EXTERNAL_UNMANAGED); + // And our new one + createSystemIndexForDescriptor(SECOND_FEATURE_IDX_DESCIPTOR); + + ensureGreen(); + + SetOnce preMigrationHookCalled = new SetOnce<>(); + SetOnce postMigrationHookCalled = new SetOnce<>(); + SetOnce secondPluginPreMigrationHookCalled = new SetOnce<>(); + SetOnce secondPluginPostMigrationHookCalled = new SetOnce<>(); + + TestPlugin.preMigrationHook.set(clusterState -> { + // None of the other hooks should have been called yet. + assertThat(postMigrationHookCalled.get(), nullValue()); + assertThat(secondPluginPreMigrationHookCalled.get(), nullValue()); + assertThat(secondPluginPostMigrationHookCalled.get(), nullValue()); + Map metadata = new HashMap<>(); + metadata.put("stringKey", "first plugin value"); + + // We shouldn't have any results in the cluster state given no features have finished yet. + FeatureMigrationResults currentResults = clusterState.metadata().custom(FeatureMigrationResults.TYPE); + assertThat(currentResults, nullValue()); + + preMigrationHookCalled.set(true); + return metadata; + }); + + TestPlugin.postMigrationHook.set((clusterState, metadata) -> { + // Check that the hooks have been called or not as expected. + assertThat(preMigrationHookCalled.get(), is(true)); + assertThat(secondPluginPreMigrationHookCalled.get(), nullValue()); + assertThat(secondPluginPostMigrationHookCalled.get(), nullValue()); + + assertThat( + metadata, + hasEntry("stringKey", "first plugin value") + ); + + // We shouldn't have any results in the cluster state given no features have finished yet. + FeatureMigrationResults currentResults = clusterState.metadata().custom(FeatureMigrationResults.TYPE); + assertThat(currentResults, nullValue()); + + postMigrationHookCalled.set(true); + }); + + SecondPlugin.preMigrationHook.set(clusterState -> { + // Check that the hooks have been called or not as expected. + assertThat(preMigrationHookCalled.get(), is(true)); + assertThat(postMigrationHookCalled.get(), is(true)); + assertThat(secondPluginPostMigrationHookCalled.get(), nullValue()); + + Map metadata = new HashMap<>(); + metadata.put("stringKey", "second plugin value"); + + // But now, we should have results, as we're in a new feature! + FeatureMigrationResults currentResults = clusterState.metadata().custom(FeatureMigrationResults.TYPE); + assertThat(currentResults, notNullValue()); + assertThat(currentResults.getFeatureStatuses(), allOf(aMapWithSize(1), hasKey(FEATURE_NAME))); + assertThat(currentResults.getFeatureStatuses().get(FEATURE_NAME).succeeded(), is(true)); + assertThat(currentResults.getFeatureStatuses().get(FEATURE_NAME).getFailedIndexName(), nullValue()); + assertThat(currentResults.getFeatureStatuses().get(FEATURE_NAME).getException(), nullValue()); + + secondPluginPreMigrationHookCalled.set(true); + return metadata; + }); + + SecondPlugin.postMigrationHook.set((clusterState, metadata) -> { + // Check that the hooks have been called or not as expected. + assertThat(preMigrationHookCalled.get(), is(true)); + assertThat(postMigrationHookCalled.get(), is(true)); + assertThat(secondPluginPreMigrationHookCalled.get(), is(true)); + + assertThat( + metadata, + hasEntry("stringKey", "second plugin value") + ); + + // And here, the results should be the same, as we haven't updated the state with this feature's status yet. + FeatureMigrationResults currentResults = clusterState.metadata().custom(FeatureMigrationResults.TYPE); + assertThat(currentResults, notNullValue()); + assertThat(currentResults.getFeatureStatuses(), allOf(aMapWithSize(1), hasKey(FEATURE_NAME))); + assertThat(currentResults.getFeatureStatuses().get(FEATURE_NAME).succeeded(), is(true)); + assertThat(currentResults.getFeatureStatuses().get(FEATURE_NAME).getFailedIndexName(), nullValue()); + assertThat(currentResults.getFeatureStatuses().get(FEATURE_NAME).getException(), nullValue()); + + secondPluginPostMigrationHookCalled.set(true); + }); + + PostFeatureUpgradeRequest migrationRequest = new PostFeatureUpgradeRequest(); + PostFeatureUpgradeResponse migrationResponse = client().execute(PostFeatureUpgradeAction.INSTANCE, migrationRequest).get(); + assertThat(migrationResponse.getReason(), nullValue()); + assertThat(migrationResponse.getElasticsearchException(), nullValue()); + final Set migratingFeatures = migrationResponse.getFeatures() + .stream() + .map(PostFeatureUpgradeResponse.Feature::getFeatureName) + .collect(Collectors.toSet()); + assertThat(migratingFeatures, hasItems(FEATURE_NAME, SECOND_FEATURE_NAME)); + + GetFeatureUpgradeStatusRequest getStatusRequest = new GetFeatureUpgradeStatusRequest(); + assertBusy(() -> { + GetFeatureUpgradeStatusResponse statusResponse = client().execute(GetFeatureUpgradeStatusAction.INSTANCE, getStatusRequest) + .get(); + logger.info(Strings.toString(statusResponse)); + assertThat(statusResponse.getUpgradeStatus(), equalTo(GetFeatureUpgradeStatusResponse.UpgradeStatus.NO_MIGRATION_NEEDED)); + }); + + assertTrue("the first plugin's pre-migration hook wasn't actually called", preMigrationHookCalled.get()); + assertTrue("the first plugin's post-migration hook wasn't actually called", postMigrationHookCalled.get()); + + assertTrue("the second plugin's pre-migration hook wasn't actually called", secondPluginPreMigrationHookCalled.get()); + assertTrue("the second plugin's post-migration hook wasn't actually called", secondPluginPostMigrationHookCalled.get()); + + Metadata finalMetadata = client().admin().cluster().prepareState().get().getState().metadata(); + // Check that the results metadata is what we expect + FeatureMigrationResults currentResults = finalMetadata.custom(FeatureMigrationResults.TYPE); + assertThat(currentResults, notNullValue()); + assertThat(currentResults.getFeatureStatuses(), allOf(aMapWithSize(2), hasKey(FEATURE_NAME), hasKey(SECOND_FEATURE_NAME))); + assertThat(currentResults.getFeatureStatuses().get(FEATURE_NAME).succeeded(), is(true)); + assertThat(currentResults.getFeatureStatuses().get(FEATURE_NAME).getFailedIndexName(), nullValue()); + assertThat(currentResults.getFeatureStatuses().get(FEATURE_NAME).getException(), nullValue()); + assertThat(currentResults.getFeatureStatuses().get(SECOND_FEATURE_NAME).succeeded(), is(true)); + assertThat(currentResults.getFeatureStatuses().get(SECOND_FEATURE_NAME).getFailedIndexName(), nullValue()); + assertThat(currentResults.getFeatureStatuses().get(SECOND_FEATURE_NAME).getException(), nullValue()); + + // Finally, verify that all the indices exist and have the properties we expect. + assertIndexHasCorrectProperties( + finalMetadata, + ".int-man-old-reindexed-for-8", + INTERNAL_MANAGED_FLAG_VALUE, + true, + true, + Arrays.asList(".int-man-old", ".internal-managed-alias") + ); + assertIndexHasCorrectProperties( + finalMetadata, + ".int-unman-old-reindexed-for-8", + INTERNAL_UNMANAGED_FLAG_VALUE, + false, + true, + Collections.singletonList(".int-unman-old") + ); + assertIndexHasCorrectProperties( + finalMetadata, + ".ext-man-old-reindexed-for-8", + EXTERNAL_MANAGED_FLAG_VALUE, + true, + false, + Arrays.asList(".ext-man-old", ".external-managed-alias") + ); + assertIndexHasCorrectProperties( + finalMetadata, + ".ext-unman-old-reindexed-for-8", + EXTERNAL_UNMANAGED_FLAG_VALUE, + false, + false, + Collections.singletonList(".ext-unman-old") + ); + + assertIndexHasCorrectProperties( + finalMetadata, + ".second-int-man-old-reindexed-for-8", + SECOND_FEATURE_IDX_FLAG_VALUE, + true, + true, + Arrays.asList(".second-int-man-old", ".second-internal-managed-alias") + ); + } + + private static final SystemIndexDescriptor SECOND_FEATURE_IDX_DESCIPTOR = SystemIndexDescriptor.builder() + .setIndexPattern(".second-int-man-*") + .setAliasName(".second-internal-managed-alias") + .setPrimaryIndex(".second-int-man-old") + .setType(SystemIndexDescriptor.Type.INTERNAL_MANAGED) + .setSettings(createSimpleSettings(Version.V_7_0_0, 0)) + .setMappings(createSimpleMapping(true, true)) + .setOrigin(ORIGIN) + .setVersionMetaKey(VERSION_META_KEY) + .setAllowedElasticProductOrigins(Collections.emptyList()) + .setMinimumNodeVersion(Version.V_7_0_0) + .setPriorSystemIndexDescriptors(Collections.emptyList()) + .build(); + + public static class SecondPlugin extends Plugin implements SystemIndexPlugin { + + private static final AtomicReference>> preMigrationHook = new AtomicReference<>(); + private static final AtomicReference>> postMigrationHook = new AtomicReference<>(); + + public SecondPlugin() { + + } + + @Override public String getFeatureName() { + return SECOND_FEATURE_NAME; + } + + @Override public String getFeatureDescription() { + return "a plugin for test system index migration with multiple features"; + } + + @Override public Collection getSystemIndexDescriptors(Settings settings) { + return Collections.singletonList(SECOND_FEATURE_IDX_DESCIPTOR); + } + + @Override public void prepareForIndicesMigration( + ClusterService clusterService, Client client, ActionListener> listener) { + listener.onResponse(preMigrationHook.get().apply(clusterService.state())); + } + + @Override public void indicesMigrationComplete( + Map preUpgradeMetadata, ClusterService clusterService, Client client, ActionListener listener) { + postMigrationHook.get().accept(clusterService.state(), preUpgradeMetadata); + listener.onResponse(true); + } + } +} diff --git a/plugins/analysis-icu/licenses/lucene-analysis-icu-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/plugins/analysis-icu/licenses/lucene-analysis-icu-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..19406d09ecf18 --- /dev/null +++ b/plugins/analysis-icu/licenses/lucene-analysis-icu-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +c5b251c26358225271e6901ae8e62f2b7b9a6e98 \ No newline at end of file diff --git a/plugins/analysis-icu/licenses/lucene-analysis-icu-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/plugins/analysis-icu/licenses/lucene-analysis-icu-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index 8c6f53bfae64d..0000000000000 --- a/plugins/analysis-icu/licenses/lucene-analysis-icu-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -91d7bb3e0f54577efbd08f8527ab705f76b405be \ No newline at end of file diff --git a/plugins/analysis-kuromoji/licenses/lucene-analysis-kuromoji-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/plugins/analysis-kuromoji/licenses/lucene-analysis-kuromoji-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..f40fc403c5530 --- /dev/null +++ b/plugins/analysis-kuromoji/licenses/lucene-analysis-kuromoji-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +07e69528347205991aa8b9724170c6bb4a61b0b0 \ No newline at end of file diff --git a/plugins/analysis-kuromoji/licenses/lucene-analysis-kuromoji-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/plugins/analysis-kuromoji/licenses/lucene-analysis-kuromoji-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index dc92541178560..0000000000000 --- a/plugins/analysis-kuromoji/licenses/lucene-analysis-kuromoji-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -2e37f30126a2ddc0231b929b82b2bc2e120af1c2 \ No newline at end of file diff --git a/plugins/analysis-nori/licenses/lucene-analysis-nori-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/plugins/analysis-nori/licenses/lucene-analysis-nori-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..3540eb801f1ae --- /dev/null +++ b/plugins/analysis-nori/licenses/lucene-analysis-nori-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +f170e5a8a8105c7eb747ab77ee3a91247f1704b1 \ No newline at end of file diff --git a/plugins/analysis-nori/licenses/lucene-analysis-nori-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/plugins/analysis-nori/licenses/lucene-analysis-nori-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index 0a00260a3592c..0000000000000 --- a/plugins/analysis-nori/licenses/lucene-analysis-nori-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -efae6bf6515c2d767491b85a50946279f66e9836 \ No newline at end of file diff --git a/plugins/analysis-phonetic/licenses/lucene-analysis-phonetic-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/plugins/analysis-phonetic/licenses/lucene-analysis-phonetic-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..308d0978017df --- /dev/null +++ b/plugins/analysis-phonetic/licenses/lucene-analysis-phonetic-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +e1c03aa49d6dc9c5f194446ba1ac39504628456e \ No newline at end of file diff --git a/plugins/analysis-phonetic/licenses/lucene-analysis-phonetic-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/plugins/analysis-phonetic/licenses/lucene-analysis-phonetic-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index cf21023f7195d..0000000000000 --- a/plugins/analysis-phonetic/licenses/lucene-analysis-phonetic-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -e50a65b19d22bc98ca57a9426c45138c71787154 \ No newline at end of file diff --git a/plugins/analysis-smartcn/licenses/lucene-analysis-smartcn-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/plugins/analysis-smartcn/licenses/lucene-analysis-smartcn-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..0e0de95bafd14 --- /dev/null +++ b/plugins/analysis-smartcn/licenses/lucene-analysis-smartcn-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +62b1dcdb25704edf95e634a810f8aa36aaac99ab \ No newline at end of file diff --git a/plugins/analysis-smartcn/licenses/lucene-analysis-smartcn-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/plugins/analysis-smartcn/licenses/lucene-analysis-smartcn-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index 4bfee0a4dabe1..0000000000000 --- a/plugins/analysis-smartcn/licenses/lucene-analysis-smartcn-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -6de256a78d4c8838d70f4b3720ba9fb6242a20bf \ No newline at end of file diff --git a/plugins/analysis-stempel/licenses/lucene-analysis-stempel-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/plugins/analysis-stempel/licenses/lucene-analysis-stempel-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..0fb07bd6f7352 --- /dev/null +++ b/plugins/analysis-stempel/licenses/lucene-analysis-stempel-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +10cf350a47eb30b615a7fd9bf740ad5e45017a2d \ No newline at end of file diff --git a/plugins/analysis-stempel/licenses/lucene-analysis-stempel-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/plugins/analysis-stempel/licenses/lucene-analysis-stempel-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index 2c7e1a52098af..0000000000000 --- a/plugins/analysis-stempel/licenses/lucene-analysis-stempel-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -48030e67171008e5d76fb211091a2bd4d256f097 \ No newline at end of file diff --git a/plugins/analysis-ukrainian/licenses/lucene-analysis-morfologik-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/plugins/analysis-ukrainian/licenses/lucene-analysis-morfologik-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..04a4d5df07ded --- /dev/null +++ b/plugins/analysis-ukrainian/licenses/lucene-analysis-morfologik-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +839cd3dcb679d53239860f88a70c970a4b30c93a \ No newline at end of file diff --git a/plugins/analysis-ukrainian/licenses/lucene-analysis-morfologik-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/plugins/analysis-ukrainian/licenses/lucene-analysis-morfologik-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index 2d8b0dc4dd2a5..0000000000000 --- a/plugins/analysis-ukrainian/licenses/lucene-analysis-morfologik-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -21a775f1b3a2912c02ac64ceb23746b259694938 \ No newline at end of file diff --git a/qa/multi-cluster-search/src/test/java/org/elasticsearch/search/CCSDuelIT.java b/qa/multi-cluster-search/src/test/java/org/elasticsearch/search/CCSDuelIT.java index aaaafd5c15c8c..49fa8e8dd46c9 100644 --- a/qa/multi-cluster-search/src/test/java/org/elasticsearch/search/CCSDuelIT.java +++ b/qa/multi-cluster-search/src/test/java/org/elasticsearch/search/CCSDuelIT.java @@ -103,6 +103,7 @@ import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.lessThanOrEqualTo; import static org.hamcrest.Matchers.not; /** @@ -438,7 +439,6 @@ public void testSortByFieldOneClusterHasNoResults() throws Exception { assumeMultiClusterSetup(); SearchRequest searchRequest = initSearchRequest(); // set to a value greater than the number of shards to avoid differences due to the skipping of shards - searchRequest.setPreFilterShardSize(128); SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); boolean onlyRemote = randomBoolean(); sourceBuilder.query(new TermQueryBuilder("_index", onlyRemote ? REMOTE_INDEX_NAME : INDEX_NAME)); @@ -461,7 +461,6 @@ public void testSortByFieldOneClusterHasNoResults() throws Exception { }); } - @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/79365") public void testFieldCollapsingOneClusterHasNoResults() throws Exception { assumeMultiClusterSetup(); SearchRequest searchRequest = initSearchRequest(); @@ -771,6 +770,7 @@ private static void duelSearch(SearchRequest searchRequest, Consumer responseToMap(SearchResponse response) throws shard.remove("fetch"); } } + Map shards = (Map)responseMap.get("_shards"); + if (shards != null) { + shards.remove("skipped"); + } return responseMap; } diff --git a/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/FeatureUpgradeIT.java b/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/FeatureUpgradeIT.java index 8bba5325cec8d..0591e0521ff78 100644 --- a/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/FeatureUpgradeIT.java +++ b/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/FeatureUpgradeIT.java @@ -91,10 +91,10 @@ public void testGetFeatureUpgradeStatus() throws Exception { assertThat(feature.size(), equalTo(4)); assertThat(feature.get("minimum_index_version"), equalTo(UPGRADE_FROM_VERSION.toString())); - if (UPGRADE_FROM_VERSION.before(Version.CURRENT.minimumIndexCompatibilityVersion())) { - assertThat(feature.get("upgrade_status"), equalTo("UPGRADE_NEEDED")); + if (UPGRADE_FROM_VERSION.before(Version.V_8_0_0)) { + assertThat(feature.get("migration_status"), equalTo("MIGRATION_NEEDED")); } else { - assertThat(feature.get("upgrade_status"), equalTo("NO_UPGRADE_NEEDED")); + assertThat(feature.get("migration_status"), equalTo("NO_MIGRATION_NEEDED")); } }); } diff --git a/qa/system-indices/src/javaRestTest/java/org/elasticsearch/system/indices/FeatureUpgradeApiIT.java b/qa/system-indices/src/javaRestTest/java/org/elasticsearch/system/indices/FeatureUpgradeApiIT.java index af9839a772a10..32e5abfb9a3e0 100644 --- a/qa/system-indices/src/javaRestTest/java/org/elasticsearch/system/indices/FeatureUpgradeApiIT.java +++ b/qa/system-indices/src/javaRestTest/java/org/elasticsearch/system/indices/FeatureUpgradeApiIT.java @@ -52,8 +52,8 @@ public void testGetFeatureUpgradedStatuses() throws Exception { Response response = client().performRequest(new Request("GET", "/_migration/system_features")); assertThat(response.getStatusLine().getStatusCode(), is(200)); XContentTestUtils.JsonMapView view = XContentTestUtils.createJsonMapView(response.getEntity().getContent()); - String upgradeStatus = view.get("upgrade_status"); - assertThat(upgradeStatus, equalTo("NO_UPGRADE_NEEDED")); + String upgradeStatus = view.get("migration_status"); + assertThat(upgradeStatus, equalTo("NO_MIGRATION_NEEDED")); List> features = view.get("features"); Map testFeature = features.stream() .filter(feature -> "system indices qa".equals(feature.get("feature_name"))) @@ -62,7 +62,7 @@ public void testGetFeatureUpgradedStatuses() throws Exception { assertThat(testFeature.size(), equalTo(4)); assertThat(testFeature.get("minimum_index_version"), equalTo(Version.CURRENT.toString())); - assertThat(testFeature.get("upgrade_status"), equalTo("NO_UPGRADE_NEEDED")); + assertThat(testFeature.get("migration_status"), equalTo("NO_MIGRATION_NEEDED")); assertThat(testFeature.get("indices"), instanceOf(List.class)); assertThat((List) testFeature.get("indices"), hasSize(1)); diff --git a/rest-api-spec/build.gradle b/rest-api-spec/build.gradle index 0cef59a464047..0f26777f04ec7 100644 --- a/rest-api-spec/build.gradle +++ b/rest-api-spec/build.gradle @@ -81,6 +81,7 @@ tasks.named("yamlRestTestV7CompatTransform").configure { task -> task.skipTest("search.aggregation/20_terms/string profiler via global ordinals native implementation", "The profiler results aren't backwards compatible.") task.skipTest("search.aggregation/20_terms/string profiler via map", "The profiler results aren't backwards compatible.") task.skipTest("search.aggregation/20_terms/numeric profiler", "The profiler results aren't backwards compatible.") + task.skipTest("migration/10_get_feature_upgrade_status/Get feature upgrade status", "Awaits backport") task.replaceValueInMatch("_type", "_doc") task.addAllowedWarningRegex("\\[types removal\\].*") diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/migration/10_get_feature_upgrade_status.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/migration/10_get_feature_upgrade_status.yml index 1fd5bc9c85a24..fefa4bb48230b 100644 --- a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/migration/10_get_feature_upgrade_status.yml +++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/migration/10_get_feature_upgrade_status.yml @@ -7,5 +7,5 @@ - do: migration.get_feature_upgrade_status: {} - - is_true: upgrade_status + - is_true: migration_status - is_true: features diff --git a/server/licenses/lucene-analysis-common-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/server/licenses/lucene-analysis-common-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..1d5734eb988f7 --- /dev/null +++ b/server/licenses/lucene-analysis-common-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +0f73e4a59da39da41511bb960212398d82e64a97 \ No newline at end of file diff --git a/server/licenses/lucene-analysis-common-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/server/licenses/lucene-analysis-common-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index 1475363327951..0000000000000 --- a/server/licenses/lucene-analysis-common-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -5a90d530649b981da658ddda7889f1a3db2eec84 \ No newline at end of file diff --git a/server/licenses/lucene-backward-codecs-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/server/licenses/lucene-backward-codecs-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..773ae4902d257 --- /dev/null +++ b/server/licenses/lucene-backward-codecs-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +ec67313245fcdb584b98790b6798a59f2f171f39 \ No newline at end of file diff --git a/server/licenses/lucene-backward-codecs-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/server/licenses/lucene-backward-codecs-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index f7ceb099c3bcd..0000000000000 --- a/server/licenses/lucene-backward-codecs-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -077984d39a5ffcdf1d3b6a41f0bc91352ad1a9a6 \ No newline at end of file diff --git a/server/licenses/lucene-core-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/server/licenses/lucene-core-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..6815a521b7287 --- /dev/null +++ b/server/licenses/lucene-core-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +6f5d5f4968f6e2f066a532d0c7a8ed0fbb9aec7d \ No newline at end of file diff --git a/server/licenses/lucene-core-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/server/licenses/lucene-core-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index d4cc15a3c336f..0000000000000 --- a/server/licenses/lucene-core-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -9c2860726c0ce9a32b6c90976e2338e70c9ebfd2 \ No newline at end of file diff --git a/server/licenses/lucene-grouping-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/server/licenses/lucene-grouping-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..08e04201d60ea --- /dev/null +++ b/server/licenses/lucene-grouping-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +2992847af15ee3b61b543bddd0e501f3fe178c6f \ No newline at end of file diff --git a/server/licenses/lucene-grouping-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/server/licenses/lucene-grouping-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index 133859fb80755..0000000000000 --- a/server/licenses/lucene-grouping-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -d97143f3691c72d62ca591df230399addccc93e7 \ No newline at end of file diff --git a/server/licenses/lucene-highlighter-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/server/licenses/lucene-highlighter-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..dffe5d7260c5a --- /dev/null +++ b/server/licenses/lucene-highlighter-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +530f39370fc0c7b6bc837d3232204670ac62c8e1 \ No newline at end of file diff --git a/server/licenses/lucene-highlighter-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/server/licenses/lucene-highlighter-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index aa29f011018c0..0000000000000 --- a/server/licenses/lucene-highlighter-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -22b9996fab3f8cc167c3aa0015f859efc5dd5de3 \ No newline at end of file diff --git a/server/licenses/lucene-join-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/server/licenses/lucene-join-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..9f21794438d0b --- /dev/null +++ b/server/licenses/lucene-join-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +7368570d058183ccc3d1c5e1d62750ade07162da \ No newline at end of file diff --git a/server/licenses/lucene-join-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/server/licenses/lucene-join-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index 1d1bed7d380bf..0000000000000 --- a/server/licenses/lucene-join-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -b1b1b6efd48c353ea930cc159ed526821ae80551 \ No newline at end of file diff --git a/server/licenses/lucene-memory-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/server/licenses/lucene-memory-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..6b660dbcc30bb --- /dev/null +++ b/server/licenses/lucene-memory-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +148d1bb8a7ff899d082a03e3fab3004e270603c1 \ No newline at end of file diff --git a/server/licenses/lucene-memory-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/server/licenses/lucene-memory-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index 0382d46d7faf4..0000000000000 --- a/server/licenses/lucene-memory-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -ab2cb78c651898e51060d0858ce96cc390cbc951 \ No newline at end of file diff --git a/server/licenses/lucene-misc-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/server/licenses/lucene-misc-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..f76923a9ce965 --- /dev/null +++ b/server/licenses/lucene-misc-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +920bc15625ec49f1656cde591a071f4798974158 \ No newline at end of file diff --git a/server/licenses/lucene-misc-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/server/licenses/lucene-misc-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index 26ae55e13363d..0000000000000 --- a/server/licenses/lucene-misc-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -f94f74e9f491fb2d3bed9f71ac39d9f7047731d5 \ No newline at end of file diff --git a/server/licenses/lucene-queries-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/server/licenses/lucene-queries-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..9fb827c8b5c01 --- /dev/null +++ b/server/licenses/lucene-queries-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +61561472420037e0cead34ac14cc93ec948ddca5 \ No newline at end of file diff --git a/server/licenses/lucene-queries-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/server/licenses/lucene-queries-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index 839fdc438bfb7..0000000000000 --- a/server/licenses/lucene-queries-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -a7fe8b44115414a6514020174b7d75c274492100 \ No newline at end of file diff --git a/server/licenses/lucene-queryparser-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/server/licenses/lucene-queryparser-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..ae5c8276a7e67 --- /dev/null +++ b/server/licenses/lucene-queryparser-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +e90bbf2465f7f7fc1c606076d17a69bf7b455439 \ No newline at end of file diff --git a/server/licenses/lucene-queryparser-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/server/licenses/lucene-queryparser-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index b95ccbc6c9523..0000000000000 --- a/server/licenses/lucene-queryparser-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -198eed372135943e6971ba78682208944a9386ae \ No newline at end of file diff --git a/server/licenses/lucene-sandbox-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/server/licenses/lucene-sandbox-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..c6ba51b1055c3 --- /dev/null +++ b/server/licenses/lucene-sandbox-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +e67b37e3d5e6fa59eef529f5a24598958006de7e \ No newline at end of file diff --git a/server/licenses/lucene-sandbox-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/server/licenses/lucene-sandbox-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index e33b961389be8..0000000000000 --- a/server/licenses/lucene-sandbox-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -95798905cae9f4f60b4a6f8d8c3e18e59b9e89a8 \ No newline at end of file diff --git a/server/licenses/lucene-spatial3d-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/server/licenses/lucene-spatial3d-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..d4009aa5f5e24 --- /dev/null +++ b/server/licenses/lucene-spatial3d-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +062e6ecea21b4281d720910e486ed04012ae8b18 \ No newline at end of file diff --git a/server/licenses/lucene-spatial3d-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/server/licenses/lucene-spatial3d-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index 37ad81feecd1f..0000000000000 --- a/server/licenses/lucene-spatial3d-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -7e3c6993f306f94618a54ae1afa7cfe75ee7c4ee \ No newline at end of file diff --git a/server/licenses/lucene-suggest-9.0.0-snapshot-8b68bf60c98.jar.sha1 b/server/licenses/lucene-suggest-9.0.0-snapshot-8b68bf60c98.jar.sha1 new file mode 100644 index 0000000000000..eb5311d0b1856 --- /dev/null +++ b/server/licenses/lucene-suggest-9.0.0-snapshot-8b68bf60c98.jar.sha1 @@ -0,0 +1 @@ +ade0398fa44d77e59842e40f76ec2910be1f5492 \ No newline at end of file diff --git a/server/licenses/lucene-suggest-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 b/server/licenses/lucene-suggest-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 deleted file mode 100644 index 08e578d7f1186..0000000000000 --- a/server/licenses/lucene-suggest-9.0.0-snapshot-cfd9f9f98f7.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -1a0f9ecd3b487f93fad3d9b6817e9865b49e01eb \ No newline at end of file diff --git a/server/src/main/java/org/elasticsearch/Version.java b/server/src/main/java/org/elasticsearch/Version.java index 3c371e59d2a90..e35e1f2ee9afe 100644 --- a/server/src/main/java/org/elasticsearch/Version.java +++ b/server/src/main/java/org/elasticsearch/Version.java @@ -91,7 +91,7 @@ public class Version implements Comparable, ToXContentFragment { public static final Version V_7_15_0 = new Version(7150099, org.apache.lucene.util.Version.LUCENE_8_9_0); public static final Version V_7_15_1 = new Version(7150199, org.apache.lucene.util.Version.LUCENE_8_9_0); public static final Version V_7_15_2 = new Version(7150299, org.apache.lucene.util.Version.LUCENE_8_9_0); - public static final Version V_7_16_0 = new Version(7160099, org.apache.lucene.util.Version.LUCENE_8_10_0); + public static final Version V_7_16_0 = new Version(7160099, org.apache.lucene.util.Version.LUCENE_8_10_1); public static final Version V_8_0_0 = new Version(8000099, org.apache.lucene.util.Version.LUCENE_9_0_0); public static final Version CURRENT = V_8_0_0; diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/migration/GetFeatureUpgradeStatusResponse.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/migration/GetFeatureUpgradeStatusResponse.java index 0d281ba4b6944..56b068fa2101d 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/migration/GetFeatureUpgradeStatusResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/migration/GetFeatureUpgradeStatusResponse.java @@ -8,17 +8,20 @@ package org.elasticsearch.action.admin.cluster.migration; +import org.elasticsearch.ElasticsearchException; import org.elasticsearch.Version; import org.elasticsearch.action.ActionResponse; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.core.Nullable; import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; import java.io.IOException; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Objects; /** @@ -57,7 +60,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.value(featureUpgradeStatus); } builder.endArray(); - builder.field("upgrade_status", upgradeStatus); + builder.field("migration_status", upgradeStatus); builder.endObject(); return builder; } @@ -98,9 +101,18 @@ public String toString() { } public enum UpgradeStatus { - UPGRADE_NEEDED, - NO_UPGRADE_NEEDED, - IN_PROGRESS + NO_MIGRATION_NEEDED, + MIGRATION_NEEDED, + IN_PROGRESS, + ERROR; + + public static UpgradeStatus combine(UpgradeStatus... statuses) { + int statusOrd = 0; + for (UpgradeStatus status : statuses) { + statusOrd = Math.max(status.ordinal(), statusOrd); + } + return UpgradeStatus.values()[statusOrd]; + } } /** @@ -111,20 +123,20 @@ public static class FeatureUpgradeStatus implements Writeable, ToXContentObject private final String featureName; private final Version minimumIndexVersion; private final UpgradeStatus upgradeStatus; - private final List indexVersions; + private final List indexInfos; /** * @param featureName Name of the feature * @param minimumIndexVersion Earliest Elasticsearch version used to create a system index for this feature * @param upgradeStatus Whether the feature needs to be upgraded - * @param indexVersions A list of this feature's concrete indices and the Elasticsearch version that created them + * @param indexInfos A list of this feature's concrete indices and the Elasticsearch version that created them */ public FeatureUpgradeStatus(String featureName, Version minimumIndexVersion, - UpgradeStatus upgradeStatus, List indexVersions) { + UpgradeStatus upgradeStatus, List indexInfos) { this.featureName = featureName; this.minimumIndexVersion = minimumIndexVersion; this.upgradeStatus = upgradeStatus; - this.indexVersions = indexVersions; + this.indexInfos = indexInfos; } /** @@ -135,7 +147,7 @@ public FeatureUpgradeStatus(StreamInput in) throws IOException { this.featureName = in.readString(); this.minimumIndexVersion = Version.readVersion(in); this.upgradeStatus = in.readEnum(UpgradeStatus.class); - this.indexVersions = in.readList(IndexVersion::new); + this.indexInfos = in.readList(IndexInfo::new); } public String getFeatureName() { @@ -150,8 +162,8 @@ public UpgradeStatus getUpgradeStatus() { return this.upgradeStatus; } - public List getIndexVersions() { - return this.indexVersions; + public List getIndexVersions() { + return this.indexInfos; } @Override @@ -159,7 +171,7 @@ public void writeTo(StreamOutput out) throws IOException { out.writeString(this.featureName); Version.writeVersion(this.minimumIndexVersion, out); out.writeEnum(this.upgradeStatus); - out.writeList(this.indexVersions); + out.writeList(this.indexInfos); } @Override @@ -167,9 +179,9 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.startObject(); builder.field("feature_name", this.featureName); builder.field("minimum_index_version", this.minimumIndexVersion.toString()); - builder.field("upgrade_status", this.upgradeStatus); + builder.field("migration_status", this.upgradeStatus); builder.startArray("indices"); - for (IndexVersion version : this.indexVersions) { + for (IndexInfo version : this.indexInfos) { builder.value(version); } builder.endArray(); @@ -185,12 +197,12 @@ public boolean equals(Object o) { return Objects.equals(featureName, that.featureName) && Objects.equals(minimumIndexVersion, that.minimumIndexVersion) && Objects.equals(upgradeStatus, that.upgradeStatus) - && Objects.equals(indexVersions, that.indexVersions); + && Objects.equals(indexInfos, that.indexInfos); } @Override public int hashCode() { - return Objects.hash(featureName, minimumIndexVersion, upgradeStatus, indexVersions); + return Objects.hash(featureName, minimumIndexVersion, upgradeStatus, indexInfos); } @Override @@ -199,7 +211,7 @@ public String toString() { "featureName='" + featureName + '\'' + ", minimumIndexVersion='" + minimumIndexVersion + '\'' + ", upgradeStatus='" + upgradeStatus + '\'' + - ", indexVersions=" + indexVersions + + ", indexInfos=" + indexInfos + '}'; } } @@ -207,26 +219,38 @@ public String toString() { /** * A data class that holds an index name and the version of Elasticsearch with which that index was created */ - public static class IndexVersion implements Writeable, ToXContentObject { + public static class IndexInfo implements Writeable, ToXContentObject { + private static final Map STACK_TRACE_ENABLED_PARAMS = + Map.of(ElasticsearchException.REST_EXCEPTION_SKIP_STACK_TRACE, "false"); + private final String indexName; private final Version version; + @Nullable private final Exception exception; // Present if this index failed /** * @param indexName Name of the index * @param version Version of Elasticsearch that created the index + * @param exception The exception that this index's migration failed with, if applicable */ - public IndexVersion(String indexName, Version version) { + public IndexInfo(String indexName, Version version, Exception exception) { this.indexName = indexName; this.version = version; + this.exception = exception; } /** * @param in A stream input for a serialized index version object * @throws IOException if we can't deserialize the object */ - public IndexVersion(StreamInput in) throws IOException { + public IndexInfo(StreamInput in) throws IOException { this.indexName = in.readString(); this.version = Version.readVersion(in); + boolean hasException = in.readBoolean(); + if (hasException) { + this.exception = in.readException(); + } else { + this.exception = null; + } } public String getIndexName() { @@ -237,17 +261,36 @@ public Version getVersion() { return this.version; } + public Exception getException() { + return this.exception; + } + @Override public void writeTo(StreamOutput out) throws IOException { out.writeString(this.indexName); Version.writeVersion(this.version, out); + if (exception != null) { + out.writeBoolean(true); + out.writeException(this.exception); + } else { + out.writeBoolean(false); + } } @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + Params exceptionParams = new DelegatingMapParams(STACK_TRACE_ENABLED_PARAMS, params); + builder.startObject(); builder.field("index", this.indexName); builder.field("version", this.version.toString()); + if (exception != null) { + builder.startObject("failure_cause"); + { + ElasticsearchException.generateFailureXContent(builder, exceptionParams, exception, true); + } + builder.endObject(); + } builder.endObject(); return builder; } @@ -256,7 +299,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - IndexVersion that = (IndexVersion) o; + IndexInfo that = (IndexInfo) o; return indexName.equals(that.indexName) && version.equals(that.version); } @@ -267,9 +310,10 @@ public int hashCode() { @Override public String toString() { - return "IndexVersion{" + + return "IndexInfo{" + "indexName='" + indexName + '\'' + ", version='" + version + '\'' + + ", exception='" + exception.getMessage() + "'" + '}'; } } diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/migration/TransportGetFeatureUpgradeStatusAction.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/migration/TransportGetFeatureUpgradeStatusAction.java index b8777d91437e1..04b1031cd6dc7 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/migration/TransportGetFeatureUpgradeStatusAction.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/migration/TransportGetFeatureUpgradeStatusAction.java @@ -19,25 +19,38 @@ import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.indices.SystemIndices; +import org.elasticsearch.persistent.PersistentTasksCustomMetadata; import org.elasticsearch.tasks.Task; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; +import org.elasticsearch.upgrades.FeatureMigrationResults; +import org.elasticsearch.upgrades.SingleFeatureMigrationResult; +import org.elasticsearch.upgrades.SystemIndexMigrationTaskState; import java.util.Collection; +import java.util.Comparator; import java.util.List; -import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.NO_UPGRADE_NEEDED; -import static org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.UPGRADE_NEEDED; +import static org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.ERROR; +import static org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.IN_PROGRESS; +import static org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.NO_MIGRATION_NEEDED; +import static org.elasticsearch.action.admin.cluster.migration.GetFeatureUpgradeStatusResponse.UpgradeStatus.MIGRATION_NEEDED; +import static org.elasticsearch.upgrades.SystemIndexMigrationTaskParams.SYSTEM_INDEX_UPGRADE_TASK_NAME; /** * Transport class for the get feature upgrade status action */ public class TransportGetFeatureUpgradeStatusAction extends TransportMasterNodeAction< - GetFeatureUpgradeStatusRequest, - GetFeatureUpgradeStatusResponse> { + GetFeatureUpgradeStatusRequest, + GetFeatureUpgradeStatusResponse> { + + /** + * This version is only valid for >=8.0.0 and should be changed on backport. + */ + public static final Version NO_UPGRADE_REQUIRED_VERSION = Version.V_8_0_0; private final SystemIndices systemIndices; @@ -65,55 +78,91 @@ public TransportGetFeatureUpgradeStatusAction( } @Override - protected void masterOperation(Task task, GetFeatureUpgradeStatusRequest request, ClusterState state, - ActionListener listener) throws Exception { - - List features = systemIndices.getFeatures().entrySet().stream() - .sorted(Map.Entry.comparingByKey()) - .map(entry -> getFeatureUpgradeStatus(state, entry)) + protected void masterOperation( + Task task, + GetFeatureUpgradeStatusRequest request, + ClusterState state, + ActionListener listener + ) throws Exception { + + List features = systemIndices.getFeatures() + .values() + .stream() + .sorted(Comparator.comparing(SystemIndices.Feature::getName)) + .map(feature -> getFeatureUpgradeStatus(state, feature)) .collect(Collectors.toList()); - boolean isUpgradeNeeded = features.stream() - .map(GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus::getMinimumIndexVersion) - .min(Version::compareTo) - .orElse(Version.CURRENT) - .before(Version.V_7_0_0); + GetFeatureUpgradeStatusResponse.UpgradeStatus status = features.stream() + .map(GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus::getUpgradeStatus) + .reduce(GetFeatureUpgradeStatusResponse.UpgradeStatus::combine) + .orElseGet(() -> { + assert false : "get feature statuses API doesn't have any features"; + return NO_MIGRATION_NEEDED; + }); - listener.onResponse(new GetFeatureUpgradeStatusResponse(features, isUpgradeNeeded ? UPGRADE_NEEDED : NO_UPGRADE_NEEDED)); + listener.onResponse(new GetFeatureUpgradeStatusResponse(features, status)); } - // visible for testing static GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus getFeatureUpgradeStatus( - ClusterState state, Map.Entry entry) { + ClusterState state, + SystemIndices.Feature feature + ) { + String featureName = feature.getName(); - String featureName = entry.getKey(); - SystemIndices.Feature feature = entry.getValue(); + final String currentFeature = Optional.ofNullable( + state.metadata().custom(PersistentTasksCustomMetadata.TYPE) + ) + .map(tasksMetdata -> tasksMetdata.getTask(SYSTEM_INDEX_UPGRADE_TASK_NAME)) + .map(task -> task.getState()) + .map(taskState -> ((SystemIndexMigrationTaskState) taskState).getCurrentFeature()) + .orElse(null); - List indexVersions = getIndexVersions(state, feature); + List indexInfos = getIndexInfos(state, feature); - Version minimumVersion = indexVersions.stream() - .map(GetFeatureUpgradeStatusResponse.IndexVersion::getVersion) + Version minimumVersion = indexInfos.stream() + .map(GetFeatureUpgradeStatusResponse.IndexInfo::getVersion) .min(Version::compareTo) .orElse(Version.CURRENT); - - return new GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus( - featureName, - minimumVersion, - minimumVersion.before(Version.V_7_0_0) ? UPGRADE_NEEDED : NO_UPGRADE_NEEDED, - indexVersions - ); + GetFeatureUpgradeStatusResponse.UpgradeStatus initialStatus; + if (featureName.equals(currentFeature)) { + initialStatus = IN_PROGRESS; + } else if (minimumVersion.before(NO_UPGRADE_REQUIRED_VERSION)) { + initialStatus = MIGRATION_NEEDED; + } else { + initialStatus = NO_MIGRATION_NEEDED; + } + + GetFeatureUpgradeStatusResponse.UpgradeStatus status = indexInfos.stream() + .filter(idxInfo -> idxInfo.getException() != null) + .findFirst() + .map(idxInfo -> ERROR) + .map(idxStatus -> GetFeatureUpgradeStatusResponse.UpgradeStatus.combine(idxStatus, initialStatus)) + .orElse(initialStatus); + + return new GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus(featureName, minimumVersion, status, indexInfos); } // visible for testing - static List getIndexVersions(ClusterState state, SystemIndices.Feature feature) { + static List getIndexInfos(ClusterState state, SystemIndices.Feature feature) { + final SingleFeatureMigrationResult featureStatus = Optional.ofNullable( + (FeatureMigrationResults) state.metadata().custom(FeatureMigrationResults.TYPE) + ).map(FeatureMigrationResults::getFeatureStatuses).map(results -> results.get(feature.getName())).orElse(null); + + final String failedFeatureName = featureStatus == null ? null : featureStatus.getFailedIndexName(); + final Exception exception = featureStatus == null ? null : featureStatus.getException(); + return Stream.of(feature.getIndexDescriptors(), feature.getAssociatedIndexDescriptors()) .flatMap(Collection::stream) .flatMap(descriptor -> descriptor.getMatchingIndices(state.metadata()).stream()) .sorted(String::compareTo) .map(index -> state.metadata().index(index)) - .map(indexMetadata -> new GetFeatureUpgradeStatusResponse.IndexVersion( - indexMetadata.getIndex().getName(), - indexMetadata.getCreationVersion())) + .map( + indexMetadata -> new GetFeatureUpgradeStatusResponse.IndexInfo( + indexMetadata.getIndex().getName(), + indexMetadata.getCreationVersion(), + indexMetadata.getIndex().getName().equals(failedFeatureName) ? exception : null + ) + ) .collect(Collectors.toList()); } diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/migration/TransportPostFeatureUpgradeAction.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/migration/TransportPostFeatureUpgradeAction.java index 3ede3d4c4b463..b7ea3d4c7f817 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/migration/TransportPostFeatureUpgradeAction.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/migration/TransportPostFeatureUpgradeAction.java @@ -8,6 +8,9 @@ package org.elasticsearch.action.admin.cluster.migration; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.ActionFilters; import org.elasticsearch.action.support.master.TransportMasterNodeAction; @@ -18,12 +21,18 @@ import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.indices.SystemIndices; +import org.elasticsearch.persistent.PersistentTasksService; import org.elasticsearch.tasks.Task; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; +import org.elasticsearch.upgrades.SystemIndexMigrationTaskParams; -import java.util.ArrayList; +import java.util.Comparator; import java.util.List; +import java.util.stream.Collectors; + +import static org.elasticsearch.action.admin.cluster.migration.TransportGetFeatureUpgradeStatusAction.getFeatureUpgradeStatus; +import static org.elasticsearch.upgrades.SystemIndexMigrationTaskParams.SYSTEM_INDEX_UPGRADE_TASK_NAME; /** * Transport action for post feature upgrade action @@ -31,8 +40,10 @@ public class TransportPostFeatureUpgradeAction extends TransportMasterNodeAction< PostFeatureUpgradeRequest, PostFeatureUpgradeResponse> { + private static final Logger logger = LogManager.getLogger(TransportPostFeatureUpgradeAction.class); private final SystemIndices systemIndices; + private final PersistentTasksService persistentTasksService; @Inject public TransportPostFeatureUpgradeAction( @@ -41,7 +52,8 @@ public TransportPostFeatureUpgradeAction( ActionFilters actionFilters, ClusterService clusterService, IndexNameExpressionResolver indexNameExpressionResolver, - SystemIndices systemIndices + SystemIndices systemIndices, + PersistentTasksService persistentTasksService ) { super( PostFeatureUpgradeAction.NAME, @@ -55,20 +67,46 @@ public TransportPostFeatureUpgradeAction( ThreadPool.Names.SAME ); this.systemIndices = systemIndices; + this.persistentTasksService = persistentTasksService; } @Override - protected void masterOperation(Task task, PostFeatureUpgradeRequest request, ClusterState state, - ActionListener listener) throws Exception { - List features = new ArrayList<>(); - features.add(new PostFeatureUpgradeResponse.Feature("security")); - listener.onResponse(new PostFeatureUpgradeResponse( - // TODO: implement operation for this action - true, features, null, null)); + protected void masterOperation( + Task task, + PostFeatureUpgradeRequest request, + ClusterState state, + ActionListener listener + ) throws Exception { + List featuresToMigrate = systemIndices.getFeatures() + .values() + .stream() + .map(feature -> getFeatureUpgradeStatus(state, feature)) + .filter(status -> status.getUpgradeStatus().equals(GetFeatureUpgradeStatusResponse.UpgradeStatus.MIGRATION_NEEDED)) + .map(GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus::getFeatureName) + .map(PostFeatureUpgradeResponse.Feature::new) + .sorted(Comparator.comparing(PostFeatureUpgradeResponse.Feature::getFeatureName)) // consistent ordering to simplify testing + .collect(Collectors.toList()); + + if (featuresToMigrate.isEmpty() == false) { + persistentTasksService.sendStartRequest( + SYSTEM_INDEX_UPGRADE_TASK_NAME, + SYSTEM_INDEX_UPGRADE_TASK_NAME, + new SystemIndexMigrationTaskParams(), + ActionListener.wrap(startedTask -> { + listener.onResponse(new PostFeatureUpgradeResponse(true, featuresToMigrate, null, null)); + }, ex -> { + logger.error("failed to start system index upgrade task", ex); + + listener.onResponse(new PostFeatureUpgradeResponse(false, null, null, new ElasticsearchException(ex))); + }) + ); + } else { + listener.onResponse(new PostFeatureUpgradeResponse(false, null, "No system indices require migration", null)); + } } @Override protected ClusterBlockException checkBlock(PostFeatureUpgradeRequest request, ClusterState state) { - return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ); + return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE); } } diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/node/hotthreads/NodesHotThreadsRequest.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/node/hotthreads/NodesHotThreadsRequest.java index 2be13918c797e..0e013dbe93d14 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/node/hotthreads/NodesHotThreadsRequest.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/node/hotthreads/NodesHotThreadsRequest.java @@ -8,6 +8,7 @@ package org.elasticsearch.action.admin.cluster.node.hotthreads; +import org.elasticsearch.Version; import org.elasticsearch.action.support.nodes.BaseNodesRequest; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.common.io.stream.StreamInput; @@ -22,6 +23,7 @@ public class NodesHotThreadsRequest extends BaseNodesRequest getNamedWriteables() { ComposableIndexTemplateMetadata::readDiffFrom); registerMetadataCustom(entries, DataStreamMetadata.TYPE, DataStreamMetadata::new, DataStreamMetadata::readDiffFrom); registerMetadataCustom(entries, NodesShutdownMetadata.TYPE, NodesShutdownMetadata::new, NodesShutdownMetadata::readDiffFrom); + registerMetadataCustom( + entries, + FeatureMigrationResults.TYPE, + FeatureMigrationResults::new, + FeatureMigrationResults::readDiffFrom + ); // Task Status (not Diffable) entries.add(new Entry(Task.Status.class, PersistentTasksNodeService.Status.NAME, PersistentTasksNodeService.Status::new)); @@ -266,7 +270,6 @@ protected void configure() { bind(MetadataIndexStateService.class).asEagerSingleton(); bind(MetadataMappingService.class).asEagerSingleton(); bind(MetadataIndexAliasesService.class).asEagerSingleton(); - bind(MetadataUpdateSettingsService.class).asEagerSingleton(); bind(MetadataIndexTemplateService.class).asEagerSingleton(); bind(IndexNameExpressionResolver.class).toInstance(indexNameExpressionResolver); bind(DelayedAllocationService.class).asEagerSingleton(); diff --git a/server/src/main/java/org/elasticsearch/cluster/coordination/ElasticsearchNodeCommand.java b/server/src/main/java/org/elasticsearch/cluster/coordination/ElasticsearchNodeCommand.java index f4041e76218ca..21a965f3fc60f 100644 --- a/server/src/main/java/org/elasticsearch/cluster/coordination/ElasticsearchNodeCommand.java +++ b/server/src/main/java/org/elasticsearch/cluster/coordination/ElasticsearchNodeCommand.java @@ -9,6 +9,7 @@ import joptsimple.OptionParser; import joptsimple.OptionSet; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.lucene.store.LockObtainFailedException; @@ -22,20 +23,22 @@ import org.elasticsearch.cluster.ClusterName; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.Diff; +import org.elasticsearch.cluster.metadata.ComponentTemplateMetadata; +import org.elasticsearch.cluster.metadata.ComposableIndexTemplateMetadata; import org.elasticsearch.cluster.metadata.DataStreamMetadata; import org.elasticsearch.cluster.metadata.Metadata; -import org.elasticsearch.core.Tuple; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.BigArrays; -import org.elasticsearch.xcontent.NamedXContentRegistry; -import org.elasticsearch.xcontent.XContentBuilder; -import org.elasticsearch.xcontent.XContentParser; +import org.elasticsearch.core.Tuple; import org.elasticsearch.env.Environment; import org.elasticsearch.env.NodeEnvironment; import org.elasticsearch.env.NodeMetadata; import org.elasticsearch.gateway.PersistedClusterStateService; +import org.elasticsearch.xcontent.NamedXContentRegistry; +import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.xcontent.XContentParser; import java.io.IOException; import java.nio.file.Files; @@ -68,7 +71,8 @@ public abstract class ElasticsearchNodeCommand extends EnvironmentAwareCommand { public T parseNamedObject(Class categoryClass, String name, XContentParser parser, C context) throws IOException { // Currently, two unknown top-level objects are present if (Metadata.Custom.class.isAssignableFrom(categoryClass)) { - if (DataStreamMetadata.TYPE.equals(name)) { + if (DataStreamMetadata.TYPE.equals(name) || ComposableIndexTemplateMetadata.TYPE.equals(name) + || ComponentTemplateMetadata.TYPE.equals(name)) { // DataStreamMetadata is used inside Metadata class for validation purposes and building the indicesLookup, // therefor even es node commands need to be able to parse it. return super.parseNamedObject(categoryClass, name, parser, context); diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/ComponentTemplate.java b/server/src/main/java/org/elasticsearch/cluster/metadata/ComponentTemplate.java index 2548431276020..ecfece366f7ad 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/ComponentTemplate.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/ComponentTemplate.java @@ -129,7 +129,7 @@ public String toString() { @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); - builder.field(TEMPLATE.getPreferredName(), this.template); + builder.field(TEMPLATE.getPreferredName(), this.template, params); if (this.version != null) { builder.field(VERSION.getPreferredName(), this.version); } diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/ComponentTemplateMetadata.java b/server/src/main/java/org/elasticsearch/cluster/metadata/ComponentTemplateMetadata.java index c655145bd7ff0..883372b9a4638 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/ComponentTemplateMetadata.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/ComponentTemplateMetadata.java @@ -98,7 +98,7 @@ public static ComponentTemplateMetadata fromXContent(XContentParser parser) thro public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(COMPONENT_TEMPLATE.getPreferredName()); for (Map.Entry template : componentTemplates.entrySet()) { - builder.field(template.getKey(), template.getValue()); + builder.field(template.getKey(), template.getValue(), params); } builder.endObject(); return builder; diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/ComposableIndexTemplate.java b/server/src/main/java/org/elasticsearch/cluster/metadata/ComposableIndexTemplate.java index 80ab79c2b24ad..79581380d296b 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/ComposableIndexTemplate.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/ComposableIndexTemplate.java @@ -202,7 +202,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.startObject(); builder.stringListField(INDEX_PATTERNS.getPreferredName(), this.indexPatterns); if (this.template != null) { - builder.field(TEMPLATE.getPreferredName(), this.template); + builder.field(TEMPLATE.getPreferredName(), this.template, params); } if (this.componentTemplates != null) { builder.stringListField(COMPOSED_OF.getPreferredName(), this.componentTemplates); @@ -217,7 +217,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.field(METADATA.getPreferredName(), metadata); } if (this.dataStreamTemplate != null) { - builder.field(DATA_STREAM.getPreferredName(), dataStreamTemplate); + builder.field(DATA_STREAM.getPreferredName(), dataStreamTemplate, params); } if (this.allowAutoCreate != null) { builder.field(ALLOW_AUTO_CREATE.getPreferredName(), allowAutoCreate); diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/ComposableIndexTemplateMetadata.java b/server/src/main/java/org/elasticsearch/cluster/metadata/ComposableIndexTemplateMetadata.java index 67fd84779f6b7..1fe3f3ab8d8c2 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/ComposableIndexTemplateMetadata.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/ComposableIndexTemplateMetadata.java @@ -99,7 +99,7 @@ public void writeTo(StreamOutput out) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(INDEX_TEMPLATE.getPreferredName()); for (Map.Entry template : indexTemplates.entrySet()) { - builder.field(template.getKey(), template.getValue()); + builder.field(template.getKey(), template.getValue(), params); } builder.endObject(); return builder; diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolver.java b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolver.java index add6ff97597fc..b7781680aca92 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolver.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolver.java @@ -103,7 +103,7 @@ public List resolveIndexAbstractions(Iterable indices, IndicesOp } else if (dateMathName.equals(indexAbstraction)) { if (minus) { finalIndices.remove(indexAbstraction); - } else { + } else if (indicesOptions.ignoreUnavailable() == false || availableIndexAbstractions.contains(indexAbstraction)) { finalIndices.add(indexAbstraction); } } diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataUpdateSettingsService.java b/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataUpdateSettingsService.java index e25808bc1d24f..9800f732e6d3a 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataUpdateSettingsService.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/MetadataUpdateSettingsService.java @@ -22,7 +22,6 @@ import org.elasticsearch.cluster.routing.allocation.AllocationService; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.Priority; -import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.regex.Regex; import org.elasticsearch.common.settings.IndexScopedSettings; import org.elasticsearch.common.settings.Setting; @@ -57,7 +56,6 @@ public class MetadataUpdateSettingsService { private final ShardLimitValidator shardLimitValidator; private final ThreadPool threadPool; - @Inject public MetadataUpdateSettingsService(ClusterService clusterService, AllocationService allocationService, IndexScopedSettings indexScopedSettings, IndicesService indicesService, ShardLimitValidator shardLimitValidator, ThreadPool threadPool) { diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/Template.java b/server/src/main/java/org/elasticsearch/cluster/metadata/Template.java index ffb23b6835b7b..8e7833aae6ee1 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/Template.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/Template.java @@ -11,6 +11,7 @@ import org.elasticsearch.cluster.AbstractDiffable; import org.elasticsearch.common.util.Maps; import org.elasticsearch.core.Nullable; +import org.elasticsearch.xcontent.ObjectParser; import org.elasticsearch.xcontent.ParseField; import org.elasticsearch.common.Strings; import org.elasticsearch.common.compress.CompressedXContent; @@ -27,6 +28,7 @@ import org.elasticsearch.index.mapper.MapperService; import java.io.IOException; +import java.util.Base64; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -47,8 +49,18 @@ public class Template extends AbstractDiffable