Display enterprise license as platinum in /_xpack (#58217)
The GET /_license endpoint displays "enterprise" licenses as "platinum" by default so that old clients (including beats, kibana and logstash) know to interpret this new license type as if it were a platinum license. However, this compatibility layer was not applied to the GET /_xpack/ endpoint which also displays a license type & mode. This commit causes the _xpack API to mimic the _license API and treat enterprise as platinum by default, with a new accept_enterprise parameter that will cause the API to return the correct "enterprise" value. This BWC layer exists only for the 7.x branch. This is a breaking change because, since 7.6, the _xpack API has returned "enterprise" for enterprise licenses, but this has been found to break old versions of beats and logstash so needs to be corrected.
This commit is contained in:
parent
8341ebc061
commit
dcc5a06dec
|
@ -5,10 +5,12 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.protocol.xpack;
|
package org.elasticsearch.protocol.xpack;
|
||||||
|
|
||||||
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.ActionRequest;
|
import org.elasticsearch.action.ActionRequest;
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.license.License;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
@ -40,8 +42,10 @@ public class XPackInfoRequest extends ActionRequest {
|
||||||
|
|
||||||
private boolean verbose;
|
private boolean verbose;
|
||||||
private EnumSet<Category> categories = EnumSet.noneOf(Category.class);
|
private EnumSet<Category> categories = EnumSet.noneOf(Category.class);
|
||||||
|
private int licenseVersion = License.VERSION_CURRENT;
|
||||||
|
|
||||||
public XPackInfoRequest() {}
|
public XPackInfoRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
public XPackInfoRequest(StreamInput in) throws IOException {
|
public XPackInfoRequest(StreamInput in) throws IOException {
|
||||||
// NOTE: this does *not* call super, THIS IS A BUG
|
// NOTE: this does *not* call super, THIS IS A BUG
|
||||||
|
@ -52,6 +56,9 @@ public class XPackInfoRequest extends ActionRequest {
|
||||||
categories.add(Category.valueOf(in.readString()));
|
categories.add(Category.valueOf(in.readString()));
|
||||||
}
|
}
|
||||||
this.categories = categories;
|
this.categories = categories;
|
||||||
|
if (in.getVersion().onOrAfter(Version.V_7_8_1)) {
|
||||||
|
this.licenseVersion = in.readVInt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVerbose(boolean verbose) {
|
public void setVerbose(boolean verbose) {
|
||||||
|
@ -70,6 +77,14 @@ public class XPackInfoRequest extends ActionRequest {
|
||||||
return categories;
|
return categories;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getLicenseVersion() {
|
||||||
|
return licenseVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLicenseVersion(int licenseVersion) {
|
||||||
|
this.licenseVersion = licenseVersion;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionRequestValidationException validate() {
|
public ActionRequestValidationException validate() {
|
||||||
return null;
|
return null;
|
||||||
|
@ -82,5 +97,8 @@ public class XPackInfoRequest extends ActionRequest {
|
||||||
for (Category category : categories) {
|
for (Category category : categories) {
|
||||||
out.writeString(category.name());
|
out.writeString(category.name());
|
||||||
}
|
}
|
||||||
|
if (out.getVersion().onOrAfter(Version.V_7_8_1)) {
|
||||||
|
out.writeVInt(this.licenseVersion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,8 +49,18 @@ public class TransportXPackInfoAction extends HandledTransportAction<XPackInfoRe
|
||||||
if (request.getCategories().contains(XPackInfoRequest.Category.LICENSE)) {
|
if (request.getCategories().contains(XPackInfoRequest.Category.LICENSE)) {
|
||||||
License license = licenseService.getLicense();
|
License license = licenseService.getLicense();
|
||||||
if (license != null) {
|
if (license != null) {
|
||||||
licenseInfo = new LicenseInfo(license.uid(), license.type(), license.operationMode().description(),
|
String type = license.type();
|
||||||
license.status(), license.expiryDate());
|
License.OperationMode mode = license.operationMode();
|
||||||
|
if (request.getLicenseVersion() < License.VERSION_ENTERPRISE) {
|
||||||
|
if (License.LicenseType.ENTERPRISE.getTypeName().equals(type)) {
|
||||||
|
type = License.LicenseType.PLATINUM.getTypeName();
|
||||||
|
}
|
||||||
|
if (mode == License.OperationMode.ENTERPRISE) {
|
||||||
|
mode = License.OperationMode.PLATINUM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
licenseInfo = new LicenseInfo(license.uid(), type, mode.description(), license.status(),
|
||||||
|
license.expiryDate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,4 +33,8 @@ public class XPackInfoRequestBuilder extends ActionRequestBuilder<XPackInfoReque
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public XPackInfoRequestBuilder setLicenseVersion(int licenseVersion) {
|
||||||
|
request.setLicenseVersion(licenseVersion);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.core.rest.action;
|
package org.elasticsearch.xpack.core.rest.action;
|
||||||
|
|
||||||
|
import org.elasticsearch.license.License;
|
||||||
import org.elasticsearch.protocol.xpack.XPackInfoRequest;
|
import org.elasticsearch.protocol.xpack.XPackInfoRequest;
|
||||||
import org.elasticsearch.rest.RestRequest;
|
import org.elasticsearch.rest.RestRequest;
|
||||||
import org.elasticsearch.rest.action.RestToXContentListener;
|
import org.elasticsearch.rest.action.RestToXContentListener;
|
||||||
|
@ -36,16 +37,20 @@ public class RestXPackInfoAction extends XPackRestHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RestChannelConsumer doPrepareRequest(RestRequest request, XPackClient client) throws IOException {
|
public RestChannelConsumer doPrepareRequest(RestRequest request, XPackClient client) throws IOException {
|
||||||
|
|
||||||
// we piggyback verbosity on "human" output
|
// we piggyback verbosity on "human" output
|
||||||
boolean verbose = request.paramAsBoolean("human", true);
|
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<XPackInfoRequest.Category> categories = XPackInfoRequest.Category
|
EnumSet<XPackInfoRequest.Category> categories = XPackInfoRequest.Category
|
||||||
.toSet(request.paramAsStringArray("categories", new String[] { "_all" }));
|
.toSet(request.paramAsStringArray("categories", new String[] { "_all" }));
|
||||||
return channel ->
|
return channel ->
|
||||||
client.prepareInfo()
|
client.prepareInfo()
|
||||||
.setVerbose(verbose)
|
.setVerbose(verbose)
|
||||||
.setCategories(categories)
|
.setCategories(categories)
|
||||||
|
.setLicenseVersion(licenseVersion)
|
||||||
.execute(new RestToXContentListener<>(channel));
|
.execute(new RestToXContentListener<>(channel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import java.util.Set;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.hasKey;
|
import static org.hamcrest.Matchers.hasKey;
|
||||||
|
@ -41,7 +42,69 @@ import static org.mockito.Mockito.when;
|
||||||
public class TransportXPackInfoActionTests extends ESTestCase {
|
public class TransportXPackInfoActionTests extends ESTestCase {
|
||||||
|
|
||||||
public void testDoExecute() throws Exception {
|
public void testDoExecute() throws Exception {
|
||||||
|
EnumSet<XPackInfoRequest.Category> 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<XPackInfoRequest.Category> 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<XPackInfoRequest.Category> 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<XPackInfoRequest.Category> categories, int licenseVersion, License license,
|
||||||
|
Consumer<XPackInfoResponse.LicenseInfo> licenseVerifier) throws InterruptedException {
|
||||||
LicenseService licenseService = mock(LicenseService.class);
|
LicenseService licenseService = mock(LicenseService.class);
|
||||||
|
|
||||||
final Set<XPackFeatureSet> featureSets = new HashSet<>();
|
final Set<XPackFeatureSet> featureSets = new HashSet<>();
|
||||||
|
@ -59,28 +122,14 @@ public class TransportXPackInfoActionTests extends ESTestCase {
|
||||||
TransportXPackInfoAction action = new TransportXPackInfoAction(transportService, mock(ActionFilters.class),
|
TransportXPackInfoAction action = new TransportXPackInfoAction(transportService, mock(ActionFilters.class),
|
||||||
licenseService, featureSets);
|
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);
|
when(licenseService.getLicense()).thenReturn(license);
|
||||||
|
|
||||||
XPackInfoRequest request = new XPackInfoRequest();
|
XPackInfoRequest request = new XPackInfoRequest();
|
||||||
request.setVerbose(randomBoolean());
|
request.setVerbose(randomBoolean());
|
||||||
|
|
||||||
EnumSet<XPackInfoRequest.Category> 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);
|
request.setCategories(categories);
|
||||||
|
if (licenseVersion != -1) {
|
||||||
|
request.setLicenseVersion(licenseVersion);
|
||||||
|
}
|
||||||
|
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
final AtomicReference<XPackInfoResponse> response = new AtomicReference<>();
|
final AtomicReference<XPackInfoResponse> response = new AtomicReference<>();
|
||||||
|
@ -114,11 +163,7 @@ public class TransportXPackInfoActionTests extends ESTestCase {
|
||||||
|
|
||||||
if (request.getCategories().contains(XPackInfoRequest.Category.LICENSE)) {
|
if (request.getCategories().contains(XPackInfoRequest.Category.LICENSE)) {
|
||||||
assertThat(response.get().getLicenseInfo(), notNullValue());
|
assertThat(response.get().getLicenseInfo(), notNullValue());
|
||||||
assertThat(response.get().getLicenseInfo().getExpiryDate(), is(expiryDate));
|
licenseVerifier.accept(response.get().getLicenseInfo());
|
||||||
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));
|
|
||||||
} else {
|
} else {
|
||||||
assertThat(response.get().getLicenseInfo(), nullValue());
|
assertThat(response.get().getLicenseInfo(), nullValue());
|
||||||
}
|
}
|
||||||
|
@ -136,7 +181,6 @@ public class TransportXPackInfoActionTests extends ESTestCase {
|
||||||
} else {
|
} else {
|
||||||
assertThat(response.get().getFeatureSetsInfo(), nullValue());
|
assertThat(response.get().getFeatureSetsInfo(), nullValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,10 @@
|
||||||
"categories":{
|
"categories":{
|
||||||
"type":"list",
|
"type":"list",
|
||||||
"description":"Comma-separated list of info categories. Can be any of: build, license, features"
|
"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)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,13 @@ teardown:
|
||||||
- match: { license.type: "platinum" }
|
- match: { license.type: "platinum" }
|
||||||
- match: { license.max_nodes: 50 }
|
- 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:
|
- do:
|
||||||
license.get:
|
license.get:
|
||||||
accept_enterprise: true
|
accept_enterprise: true
|
||||||
|
@ -39,6 +46,13 @@ teardown:
|
||||||
- match: { license.max_resource_units: 50 }
|
- match: { license.max_resource_units: 50 }
|
||||||
- match: { license.max_nodes: null }
|
- 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:
|
- do:
|
||||||
license.get:
|
license.get:
|
||||||
accept_enterprise: false
|
accept_enterprise: false
|
||||||
|
@ -49,3 +63,11 @@ teardown:
|
||||||
## opt-out of real enterprise type
|
## opt-out of real enterprise type
|
||||||
- match: { license.type: "platinum" }
|
- match: { license.type: "platinum" }
|
||||||
- match: { license.max_nodes: 50 }
|
- 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" }
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
"XPack Info API":
|
||||||
|
- do:
|
||||||
|
xpack.info: {}
|
||||||
|
|
||||||
|
- match: { license.type: "trial" }
|
||||||
|
- match: { license.mode: "trial" }
|
||||||
|
- match: { license.status: "active" }
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.xcontent.ObjectPath;
|
import org.elasticsearch.common.xcontent.ObjectPath;
|
||||||
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
||||||
|
import org.junit.Before;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -23,6 +24,11 @@ import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
public class CcrRollingUpgradeIT extends AbstractMultiClusterUpgradeTestCase {
|
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 {
|
public void testUniDirectionalIndexFollowing() throws Exception {
|
||||||
logger.info("clusterName={}, upgradeState={}", clusterName, upgradeState);
|
logger.info("clusterName={}, upgradeState={}", clusterName, upgradeState);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue