diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/protocol/xpack/XPackInfoRequest.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/protocol/xpack/XPackInfoRequest.java index 4deb63c060d14..e45f00d4d010a 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/protocol/xpack/XPackInfoRequest.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/protocol/xpack/XPackInfoRequest.java @@ -5,10 +5,12 @@ */ package org.elasticsearch.protocol.xpack; +import org.elasticsearch.Version; import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionRequestValidationException; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.license.License; import java.io.IOException; import java.util.EnumSet; @@ -40,8 +42,10 @@ public static EnumSet toSet(String... categories) { private boolean verbose; private EnumSet categories = EnumSet.noneOf(Category.class); + private int licenseVersion = License.VERSION_CURRENT; - public XPackInfoRequest() {} + public XPackInfoRequest() { + } public XPackInfoRequest(StreamInput in) throws IOException { // NOTE: this does *not* call super, THIS IS A BUG @@ -52,6 +56,9 @@ public XPackInfoRequest(StreamInput in) throws IOException { categories.add(Category.valueOf(in.readString())); } this.categories = categories; + if (in.getVersion().onOrAfter(Version.V_7_8_1)) { + this.licenseVersion = in.readVInt(); + } } public void setVerbose(boolean verbose) { @@ -70,6 +77,14 @@ public EnumSet getCategories() { return categories; } + public int getLicenseVersion() { + return licenseVersion; + } + + public void setLicenseVersion(int licenseVersion) { + this.licenseVersion = licenseVersion; + } + @Override public ActionRequestValidationException validate() { return null; @@ -82,5 +97,8 @@ public void writeTo(StreamOutput out) throws IOException { for (Category category : categories) { out.writeString(category.name()); } + if (out.getVersion().onOrAfter(Version.V_7_8_1)) { + out.writeVInt(this.licenseVersion); + } } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackInfoAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackInfoAction.java index e0938ad7d97f1..5a54fbf34f0b9 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackInfoAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackInfoAction.java @@ -49,8 +49,18 @@ protected void doExecute(Task task, XPackInfoRequest request, ActionListener return this; } + public XPackInfoRequestBuilder setLicenseVersion(int licenseVersion) { + request.setLicenseVersion(licenseVersion); + return this; + } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rest/action/RestXPackInfoAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rest/action/RestXPackInfoAction.java index 48bec03531781..b26a726ae00f7 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rest/action/RestXPackInfoAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rest/action/RestXPackInfoAction.java @@ -5,6 +5,7 @@ */ package org.elasticsearch.xpack.core.rest.action; +import org.elasticsearch.license.License; import org.elasticsearch.protocol.xpack.XPackInfoRequest; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.action.RestToXContentListener; @@ -36,16 +37,20 @@ public String getName() { @Override public RestChannelConsumer doPrepareRequest(RestRequest request, XPackClient client) throws IOException { - // we piggyback verbosity on "human" output boolean verbose = request.paramAsBoolean("human", true); + // Hide enterprise licenses by default, there is an opt-in flag to show them + final boolean acceptEnterprise = request.paramAsBoolean("accept_enterprise", false); + final int licenseVersion = acceptEnterprise ? License.VERSION_CURRENT : License.VERSION_CRYPTO_ALGORITHMS; + EnumSet categories = XPackInfoRequest.Category .toSet(request.paramAsStringArray("categories", new String[] { "_all" })); return channel -> client.prepareInfo() .setVerbose(verbose) .setCategories(categories) + .setLicenseVersion(licenseVersion) .execute(new RestToXContentListener<>(channel)); } } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/action/TransportXPackInfoActionTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/action/TransportXPackInfoActionTests.java index 33500271de936..f6fd0cecfd076 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/action/TransportXPackInfoActionTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/action/TransportXPackInfoActionTests.java @@ -29,6 +29,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasKey; @@ -41,7 +42,69 @@ public class TransportXPackInfoActionTests extends ESTestCase { public void testDoExecute() throws Exception { + EnumSet categories = EnumSet.noneOf(XPackInfoRequest.Category.class); + int maxCategoryCount = randomIntBetween(0, XPackInfoRequest.Category.values().length); + for (int i = 0; i < maxCategoryCount; i++) { + categories.add(randomFrom(XPackInfoRequest.Category.values())); + } + + License license = mock(License.class); + long expiryDate = randomLong(); + when(license.expiryDate()).thenReturn(expiryDate); + LicenseStatus status = randomFrom(LicenseStatus.values()); + when(license.status()).thenReturn(status); + String licenseType = randomAlphaOfLength(10); + when(license.type()).thenReturn(licenseType); + License.OperationMode licenseMode = randomFrom(License.OperationMode.values()); + when(license.operationMode()).thenReturn(licenseMode); + String uid = randomAlphaOfLength(30); + when(license.uid()).thenReturn(uid); + + checkAction(categories, -1, license, (XPackInfoResponse.LicenseInfo licenseInfo) -> { + assertThat(licenseInfo.getExpiryDate(), is(expiryDate)); + assertThat(licenseInfo.getStatus(), is(status)); + assertThat(licenseInfo.getType(), is(licenseType)); + assertThat(licenseInfo.getMode(), is(licenseMode.name().toLowerCase(Locale.ROOT))); + assertThat(licenseInfo.getUid(), is(uid)); + }); + } + + public void testDoExecuteWithEnterpriseLicenseWithoutBackwardsCompat() throws Exception { + EnumSet categories = EnumSet.allOf(XPackInfoRequest.Category.class); + + License license = mock(License.class); + when(license.expiryDate()).thenReturn(randomLong()); + when(license.status()).thenReturn(LicenseStatus.ACTIVE); + when(license.type()).thenReturn("enterprise"); + when(license.operationMode()).thenReturn(License.OperationMode.ENTERPRISE); + when(license.uid()).thenReturn(randomAlphaOfLength(30)); + + checkAction(categories, randomFrom(License.VERSION_ENTERPRISE, License.VERSION_CURRENT, -1), license, + licenseInfo -> { + assertThat(licenseInfo.getType(), is("enterprise")); + assertThat(licenseInfo.getMode(), is("enterprise")); + }); + } + public void testDoExecuteWithEnterpriseLicenseWithBackwardsCompat() throws Exception { + EnumSet categories = EnumSet.allOf(XPackInfoRequest.Category.class); + + License license = mock(License.class); + when(license.expiryDate()).thenReturn(randomLong()); + when(license.status()).thenReturn(LicenseStatus.ACTIVE); + when(license.type()).thenReturn("enterprise"); + when(license.operationMode()).thenReturn(License.OperationMode.ENTERPRISE); + when(license.uid()).thenReturn(randomAlphaOfLength(30)); + + checkAction(categories, randomFrom(License.VERSION_START_DATE, License.VERSION_CRYPTO_ALGORITHMS), license, + licenseInfo -> { + assertThat(licenseInfo.getType(), is("platinum")); + assertThat(licenseInfo.getMode(), is("platinum")); + }); + } + + private void checkAction(EnumSet categories, int licenseVersion, License license, + Consumer licenseVerifier) throws InterruptedException { LicenseService licenseService = mock(LicenseService.class); final Set featureSets = new HashSet<>(); @@ -59,28 +122,14 @@ public void testDoExecute() throws Exception { TransportXPackInfoAction action = new TransportXPackInfoAction(transportService, mock(ActionFilters.class), licenseService, featureSets); - License license = mock(License.class); - long expiryDate = randomLong(); - when(license.expiryDate()).thenReturn(expiryDate); - LicenseStatus status = randomFrom(LicenseStatus.values()); - when(license.status()).thenReturn(status); - String type = randomAlphaOfLength(10); - when(license.type()).thenReturn(type); - License.OperationMode mode = randomFrom(License.OperationMode.values()); - when(license.operationMode()).thenReturn(mode); - String uid = randomAlphaOfLength(30); - when(license.uid()).thenReturn(uid); when(licenseService.getLicense()).thenReturn(license); XPackInfoRequest request = new XPackInfoRequest(); request.setVerbose(randomBoolean()); - - EnumSet categories = EnumSet.noneOf(XPackInfoRequest.Category.class); - int maxCategoryCount = randomIntBetween(0, XPackInfoRequest.Category.values().length); - for (int i = 0; i < maxCategoryCount; i++) { - categories.add(randomFrom(XPackInfoRequest.Category.values())); - } request.setCategories(categories); + if (licenseVersion != -1) { + request.setLicenseVersion(licenseVersion); + } final CountDownLatch latch = new CountDownLatch(1); final AtomicReference response = new AtomicReference<>(); @@ -114,11 +163,7 @@ public void onFailure(Exception e) { if (request.getCategories().contains(XPackInfoRequest.Category.LICENSE)) { assertThat(response.get().getLicenseInfo(), notNullValue()); - assertThat(response.get().getLicenseInfo().getExpiryDate(), is(expiryDate)); - assertThat(response.get().getLicenseInfo().getStatus(), is(status)); - assertThat(response.get().getLicenseInfo().getType(), is(type)); - assertThat(response.get().getLicenseInfo().getMode(), is(mode.name().toLowerCase(Locale.ROOT))); - assertThat(response.get().getLicenseInfo().getUid(), is(uid)); + licenseVerifier.accept(response.get().getLicenseInfo()); } else { assertThat(response.get().getLicenseInfo(), nullValue()); } @@ -136,7 +181,6 @@ public void onFailure(Exception e) { } else { assertThat(response.get().getFeatureSetsInfo(), nullValue()); } - } } diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.info.json b/x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.info.json index 2ccb1beda7d96..b9fcd27aa26cf 100644 --- a/x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.info.json +++ b/x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.info.json @@ -19,6 +19,10 @@ "categories":{ "type":"list", "description":"Comma-separated list of info categories. Can be any of: build, license, features" + }, + "accept_enterprise":{ + "type":"boolean", + "description":"If an enterprise license is installed, return the type and mode as 'enterprise' (default: false)" } } } diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/test/license/30_enterprise_license.yml b/x-pack/plugin/src/test/resources/rest-api-spec/test/license/30_enterprise_license.yml index 1d2470b5c4bd6..d275c2d1bf832 100644 --- a/x-pack/plugin/src/test/resources/rest-api-spec/test/license/30_enterprise_license.yml +++ b/x-pack/plugin/src/test/resources/rest-api-spec/test/license/30_enterprise_license.yml @@ -27,6 +27,13 @@ teardown: - match: { license.type: "platinum" } - match: { license.max_nodes: 50 } + ## Check the xpack info API as well + - do: + xpack.info: {} + - match: { license.type: "platinum" } + - match: { license.mode: "platinum" } + + ## Check the opt-in v5 license type - do: license.get: accept_enterprise: true @@ -39,6 +46,13 @@ teardown: - match: { license.max_resource_units: 50 } - match: { license.max_nodes: null } + ## Check the xpack info API as well + - do: + xpack.info: + accept_enterprise: true + - match: { license.type: "enterprise" } + - match: { license.mode: "enterprise" } + - do: license.get: accept_enterprise: false @@ -49,3 +63,11 @@ teardown: ## opt-out of real enterprise type - match: { license.type: "platinum" } - match: { license.max_nodes: 50 } + + ## Check the xpack info API as well + - do: + xpack.info: + accept_enterprise: false + - match: { license.type: "platinum" } + - match: { license.mode: "platinum" } + diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/test/xpack/20_info.yml b/x-pack/plugin/src/test/resources/rest-api-spec/test/xpack/20_info.yml new file mode 100644 index 0000000000000..1af19aed9a27f --- /dev/null +++ b/x-pack/plugin/src/test/resources/rest-api-spec/test/xpack/20_info.yml @@ -0,0 +1,9 @@ +"XPack Info API": + - do: + xpack.info: {} + + - match: { license.type: "trial" } + - match: { license.mode: "trial" } + - match: { license.status: "active" } + + diff --git a/x-pack/qa/rolling-upgrade-multi-cluster/src/test/java/org/elasticsearch/upgrades/CcrRollingUpgradeIT.java b/x-pack/qa/rolling-upgrade-multi-cluster/src/test/java/org/elasticsearch/upgrades/CcrRollingUpgradeIT.java index 3c8fff8a9b3c4..172f0474ed74f 100644 --- a/x-pack/qa/rolling-upgrade-multi-cluster/src/test/java/org/elasticsearch/upgrades/CcrRollingUpgradeIT.java +++ b/x-pack/qa/rolling-upgrade-multi-cluster/src/test/java/org/elasticsearch/upgrades/CcrRollingUpgradeIT.java @@ -13,6 +13,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.ObjectPath; import org.elasticsearch.common.xcontent.support.XContentMapValues; +import org.junit.Before; import java.io.IOException; import java.util.Map; @@ -23,6 +24,11 @@ public class CcrRollingUpgradeIT extends AbstractMultiClusterUpgradeTestCase { + @Before + public void skipForBackportOf58217() { + assumeFalse("Skip while back-porting #58217", UPGRADE_FROM_VERSION.equals(Version.V_7_8_1)); + } + public void testUniDirectionalIndexFollowing() throws Exception { logger.info("clusterName={}, upgradeState={}", clusterName, upgradeState);