HLREST: Add x-pack-info API (#31870)
This is the first x-pack API we're adding to the high level REST client so there is a lot to talk about here! = Open source The *client* for these APIs is open source. We're taking the previously Elastic licensed files used for the `Request` and `Response` objects and relicensing them under the Apache 2 license. The implementation of these features is staying under the Elastic license. This lines up with how the rest of the Elasticsearch language clients work. = Location of the new files We're moving all of the `Request` and `Response` objects that we're relicensing to the `x-pack/protocol` directory. We're adding a copy of the Apache 2 license to the root fo the `x-pack/protocol` directory to line up with the language in the root `LICENSE.txt` file. All files in this directory will have the Apache 2 license header as well. We don't want there to be any confusion. Even though the files are under the `x-pack` directory, they are Apache 2 licensed. We chose this particular directory layout because it keeps the X-Pack stuff together and easier to think about. = Location of the API in the REST client We've been following the layout of the rest-api-spec files for other APIs and we plan to do this for the X-Pack APIs with one exception: we're dropping the `xpack` from the name of most of the APIs. So `xpack.graph.explore` will become `graph().explore()` and `xpack.license.get` will become `license().get()`. `xpack.info` and `xpack.usage` are special here though because they don't belong to any proper category. For now I'm just calling `xpack.info` `xPackInfo()` and intend to call usage `xPackUsage` though I'm not convinced that this is the final name for them. But it does get us started. = Jars, jars everywhere! This change makes the `xpack:protocol` project a `compile` scoped dependency of the `x-pack:plugin:core` and `client:rest-high-level` projects. I intend to keep it a compile scoped dependency of `x-pack:plugin:core` but I intend to bundle the contents of the protocol jar into the `client:rest-high-level` jar in a follow up. This change has grown large enough at this point. In that followup I'll address javadoc issues as well. = Breaking-Java This breaks that transport client by a few classes around. We've traditionally been ok with doing this to the transport client.
This commit is contained in:
parent
49ba271bd8
commit
fb27f3e7f0
|
@ -41,6 +41,7 @@ dependencies {
|
|||
compile "org.elasticsearch.plugin:aggs-matrix-stats-client:${version}"
|
||||
compile "org.elasticsearch.plugin:rank-eval-client:${version}"
|
||||
compile "org.elasticsearch.plugin:lang-mustache-client:${version}"
|
||||
compile project(':x-pack:protocol') // TODO bundle into the jar
|
||||
|
||||
testCompile "org.elasticsearch.client:test:${version}"
|
||||
testCompile "org.elasticsearch.test:framework:${version}"
|
||||
|
|
|
@ -104,6 +104,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
|||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.index.VersionType;
|
||||
import org.elasticsearch.index.rankeval.RankEvalRequest;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoRequest;
|
||||
import org.elasticsearch.rest.action.search.RestSearchAction;
|
||||
import org.elasticsearch.script.mustache.MultiSearchTemplateRequest;
|
||||
import org.elasticsearch.script.mustache.SearchTemplateRequest;
|
||||
|
@ -115,8 +116,10 @@ import java.io.IOException;
|
|||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Locale;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
final class RequestConverters {
|
||||
static final XContentType REQUEST_BODY_CONTENT_TYPE = XContentType.JSON;
|
||||
|
@ -1065,6 +1068,19 @@ final class RequestConverters {
|
|||
return request;
|
||||
}
|
||||
|
||||
static Request xPackInfo(XPackInfoRequest infoRequest) {
|
||||
Request request = new Request(HttpGet.METHOD_NAME, "/_xpack");
|
||||
if (false == infoRequest.isVerbose()) {
|
||||
request.addParameter("human", "false");
|
||||
}
|
||||
if (false == infoRequest.getCategories().equals(EnumSet.allOf(XPackInfoRequest.Category.class))) {
|
||||
request.addParameter("categories", infoRequest.getCategories().stream()
|
||||
.map(c -> c.toString().toLowerCase(Locale.ROOT))
|
||||
.collect(Collectors.joining(",")));
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
private static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) throws IOException {
|
||||
BytesRef source = XContentHelper.toXContent(toXContent, xContentType, false).toBytesRef();
|
||||
return new ByteArrayEntity(source.bytes, source.offset, source.length, createContentType(xContentType));
|
||||
|
|
|
@ -66,6 +66,8 @@ import org.elasticsearch.common.xcontent.XContentType;
|
|||
import org.elasticsearch.index.rankeval.RankEvalRequest;
|
||||
import org.elasticsearch.index.rankeval.RankEvalResponse;
|
||||
import org.elasticsearch.plugins.spi.NamedXContentProvider;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoRequest;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse;
|
||||
import org.elasticsearch.rest.BytesRestResponse;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
import org.elasticsearch.script.mustache.MultiSearchTemplateRequest;
|
||||
|
@ -668,7 +670,7 @@ public class RestHighLevelClient implements Closeable {
|
|||
emptySet());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Executes a request using the Multi Search Template API.
|
||||
*
|
||||
|
@ -678,9 +680,9 @@ public class RestHighLevelClient implements Closeable {
|
|||
public final MultiSearchTemplateResponse multiSearchTemplate(MultiSearchTemplateRequest multiSearchTemplateRequest,
|
||||
RequestOptions options) throws IOException {
|
||||
return performRequestAndParseEntity(multiSearchTemplateRequest, RequestConverters::multiSearchTemplate,
|
||||
options, MultiSearchTemplateResponse::fromXContext, emptySet());
|
||||
}
|
||||
|
||||
options, MultiSearchTemplateResponse::fromXContext, emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously executes a request using the Multi Search Template API
|
||||
*
|
||||
|
@ -692,7 +694,7 @@ public class RestHighLevelClient implements Closeable {
|
|||
ActionListener<MultiSearchTemplateResponse> listener) {
|
||||
performRequestAsyncAndParseEntity(multiSearchTemplateRequest, RequestConverters::multiSearchTemplate,
|
||||
options, MultiSearchTemplateResponse::fromXContext, listener, emptySet());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously executes a request using the Ranking Evaluation API.
|
||||
|
@ -792,6 +794,34 @@ public class RestHighLevelClient implements Closeable {
|
|||
FieldCapabilitiesResponse::fromXContent, listener, emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch information about X-Pack from the cluster if it is installed.
|
||||
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/info-api.html">
|
||||
* the docs</a> for more.
|
||||
* @param request the request
|
||||
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
|
||||
* @return the response
|
||||
* @throws IOException in case there is a problem sending the request or parsing back the response
|
||||
*/
|
||||
public XPackInfoResponse xPackInfo(XPackInfoRequest request, RequestOptions options) throws IOException {
|
||||
return performRequestAndParseEntity(request, RequestConverters::xPackInfo, options,
|
||||
XPackInfoResponse::fromXContent, emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch information about X-Pack from the cluster if it is installed.
|
||||
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/info-api.html">
|
||||
* the docs</a> for more.
|
||||
* @param request the request
|
||||
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
|
||||
* @param listener the listener to be notified upon request completion
|
||||
*/
|
||||
public void xPackInfoAsync(XPackInfoRequest request, RequestOptions options,
|
||||
ActionListener<XPackInfoResponse> listener) {
|
||||
performRequestAsyncAndParseEntity(request, RequestConverters::xPackInfo, options,
|
||||
XPackInfoResponse::fromXContent, listener, emptySet());
|
||||
}
|
||||
|
||||
protected final <Req extends ActionRequest, Resp> Resp performRequestAndParseEntity(Req request,
|
||||
CheckedFunction<Req, Request, IOException> requestConverter,
|
||||
RequestOptions options,
|
||||
|
|
|
@ -21,8 +21,13 @@ package org.elasticsearch.client;
|
|||
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.elasticsearch.action.main.MainResponse;
|
||||
import org.elasticsearch.protocol.license.LicenseStatus;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoRequest;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse.FeatureSetsInfo.FeatureSet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
|
||||
public class PingAndInfoIT extends ESRestHighLevelClientTestCase {
|
||||
|
@ -31,7 +36,6 @@ public class PingAndInfoIT extends ESRestHighLevelClientTestCase {
|
|||
assertTrue(highLevelClient().ping(RequestOptions.DEFAULT));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testInfo() throws IOException {
|
||||
MainResponse info = highLevelClient().info(RequestOptions.DEFAULT);
|
||||
// compare with what the low level client outputs
|
||||
|
@ -41,6 +45,7 @@ public class PingAndInfoIT extends ESRestHighLevelClientTestCase {
|
|||
|
||||
// only check node name existence, might be a different one from what was hit by low level client in multi-node cluster
|
||||
assertNotNull(info.getNodeName());
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> versionMap = (Map<String, Object>) infoAsMap.get("version");
|
||||
assertEquals(versionMap.get("build_flavor"), info.getBuild().flavor().displayName());
|
||||
assertEquals(versionMap.get("build_type"), info.getBuild().type().displayName());
|
||||
|
@ -51,4 +56,49 @@ public class PingAndInfoIT extends ESRestHighLevelClientTestCase {
|
|||
assertEquals(versionMap.get("lucene_version"), info.getVersion().luceneVersion.toString());
|
||||
}
|
||||
|
||||
public void testXPackInfo() throws IOException {
|
||||
XPackInfoRequest request = new XPackInfoRequest();
|
||||
request.setCategories(EnumSet.allOf(XPackInfoRequest.Category.class));
|
||||
request.setVerbose(true);
|
||||
XPackInfoResponse info = highLevelClient().xPackInfo(request, RequestOptions.DEFAULT);
|
||||
|
||||
MainResponse mainResponse = highLevelClient().info(RequestOptions.DEFAULT);
|
||||
|
||||
assertEquals(mainResponse.getBuild().shortHash(), info.getBuildInfo().getHash());
|
||||
|
||||
assertEquals("basic", info.getLicenseInfo().getType());
|
||||
assertEquals("basic", info.getLicenseInfo().getMode());
|
||||
assertEquals(LicenseStatus.ACTIVE, info.getLicenseInfo().getStatus());
|
||||
|
||||
FeatureSet graph = info.getFeatureSetsInfo().getFeatureSets().get("graph");
|
||||
assertNotNull(graph.description());
|
||||
assertFalse(graph.available());
|
||||
assertTrue(graph.enabled());
|
||||
assertNull(graph.nativeCodeInfo());
|
||||
FeatureSet monitoring = info.getFeatureSetsInfo().getFeatureSets().get("monitoring");
|
||||
assertNotNull(monitoring.description());
|
||||
assertTrue(monitoring.available());
|
||||
assertTrue(monitoring.enabled());
|
||||
assertNull(monitoring.nativeCodeInfo());
|
||||
FeatureSet ml = info.getFeatureSetsInfo().getFeatureSets().get("ml");
|
||||
assertNotNull(ml.description());
|
||||
assertFalse(ml.available());
|
||||
assertTrue(ml.enabled());
|
||||
assertEquals(mainResponse.getVersion().toString(),
|
||||
ml.nativeCodeInfo().get("version").toString().replace("-SNAPSHOT", ""));
|
||||
}
|
||||
|
||||
public void testXPackInfoEmptyRequest() throws IOException {
|
||||
XPackInfoResponse info = highLevelClient().xPackInfo(new XPackInfoRequest(), RequestOptions.DEFAULT);
|
||||
|
||||
/*
|
||||
* The default in the transport client is non-verbose and returning
|
||||
* no categories which is the opposite of the default when you use
|
||||
* the API over REST. We don't want to break the transport client
|
||||
* even though it doesn't feel like a good default.
|
||||
*/
|
||||
assertNull(info.getBuildInfo());
|
||||
assertNull(info.getLicenseInfo());
|
||||
assertNull(info.getFeatureSetsInfo());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,6 +123,7 @@ import org.elasticsearch.index.rankeval.RankEvalRequest;
|
|||
import org.elasticsearch.index.rankeval.RankEvalSpec;
|
||||
import org.elasticsearch.index.rankeval.RatedRequest;
|
||||
import org.elasticsearch.index.rankeval.RestRankEvalAction;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoRequest;
|
||||
import org.elasticsearch.repositories.fs.FsRepository;
|
||||
import org.elasticsearch.rest.action.search.RestSearchAction;
|
||||
import org.elasticsearch.script.ScriptType;
|
||||
|
@ -150,6 +151,7 @@ import java.nio.file.Path;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -2465,6 +2467,37 @@ public class RequestConvertersTests extends ESTestCase {
|
|||
+ "previous requests have content-type [" + xContentType + "]", exception.getMessage());
|
||||
}
|
||||
|
||||
public void testXPackInfo() {
|
||||
XPackInfoRequest infoRequest = new XPackInfoRequest();
|
||||
Map<String, String> expectedParams = new HashMap<>();
|
||||
infoRequest.setVerbose(randomBoolean());
|
||||
if (false == infoRequest.isVerbose()) {
|
||||
expectedParams.put("human", "false");
|
||||
}
|
||||
int option = between(0, 2);
|
||||
switch (option) {
|
||||
case 0:
|
||||
infoRequest.setCategories(EnumSet.allOf(XPackInfoRequest.Category.class));
|
||||
break;
|
||||
case 1:
|
||||
infoRequest.setCategories(EnumSet.of(XPackInfoRequest.Category.FEATURES));
|
||||
expectedParams.put("categories", "features");
|
||||
break;
|
||||
case 2:
|
||||
infoRequest.setCategories(EnumSet.of(XPackInfoRequest.Category.FEATURES, XPackInfoRequest.Category.BUILD));
|
||||
expectedParams.put("categories", "build,features");
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("invalid option [" + option + "]");
|
||||
}
|
||||
|
||||
Request request = RequestConverters.xPackInfo(infoRequest);
|
||||
assertEquals(HttpGet.METHOD_NAME, request.getMethod());
|
||||
assertEquals("/_xpack", request.getEndpoint());
|
||||
assertNull(request.getEntity());
|
||||
assertEquals(expectedParams, request.getParameters());
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomize the {@link FetchSourceContext} request parameters.
|
||||
*/
|
||||
|
|
|
@ -22,14 +22,24 @@ package org.elasticsearch.client.documentation;
|
|||
import org.apache.http.HttpHost;
|
||||
import org.elasticsearch.Build;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.LatchedActionListener;
|
||||
import org.elasticsearch.action.main.MainResponse;
|
||||
import org.elasticsearch.client.ESRestHighLevelClientTestCase;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.elasticsearch.client.RestHighLevelClient;
|
||||
import org.elasticsearch.cluster.ClusterName;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoRequest;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse.BuildInfo;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse.FeatureSetsInfo;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse.LicenseInfo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Documentation for miscellaneous APIs in the high level java client.
|
||||
|
@ -66,6 +76,59 @@ public class MiscellaneousDocumentationIT extends ESRestHighLevelClientTestCase
|
|||
assertTrue(response);
|
||||
}
|
||||
|
||||
public void testXPackInfo() throws Exception {
|
||||
RestHighLevelClient client = highLevelClient();
|
||||
{
|
||||
//tag::x-pack-info-execute
|
||||
XPackInfoRequest request = new XPackInfoRequest();
|
||||
request.setVerbose(true); // <1>
|
||||
request.setCategories(EnumSet.of( // <2>
|
||||
XPackInfoRequest.Category.BUILD,
|
||||
XPackInfoRequest.Category.LICENSE,
|
||||
XPackInfoRequest.Category.FEATURES));
|
||||
XPackInfoResponse response = client.xPackInfo(request, RequestOptions.DEFAULT);
|
||||
//end::x-pack-info-execute
|
||||
|
||||
//tag::x-pack-info-response
|
||||
BuildInfo build = response.getBuildInfo(); // <1>
|
||||
LicenseInfo license = response.getLicenseInfo(); // <2>
|
||||
assertEquals(XPackInfoResponse.BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS,
|
||||
license.getExpiryDate()); // <3>
|
||||
FeatureSetsInfo features = response.getFeatureSetsInfo(); // <4>
|
||||
//end::x-pack-info-response
|
||||
|
||||
assertNotNull(response.getBuildInfo());
|
||||
assertNotNull(response.getLicenseInfo());
|
||||
assertNotNull(response.getFeatureSetsInfo());
|
||||
}
|
||||
{
|
||||
XPackInfoRequest request = new XPackInfoRequest();
|
||||
// tag::x-pack-info-execute-listener
|
||||
ActionListener<XPackInfoResponse> listener = new ActionListener<XPackInfoResponse>() {
|
||||
@Override
|
||||
public void onResponse(XPackInfoResponse indexResponse) {
|
||||
// <1>
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
// <2>
|
||||
}
|
||||
};
|
||||
// end::x-pack-info-execute-listener
|
||||
|
||||
// Replace the empty listener by a blocking listener in test
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
listener = new LatchedActionListener<>(listener, latch);
|
||||
|
||||
// tag::x-pack-info-execute-async
|
||||
client.xPackInfoAsync(request, RequestOptions.DEFAULT, listener); // <1>
|
||||
// end::x-pack-info-execute-async
|
||||
|
||||
assertTrue(latch.await(30L, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
|
||||
public void testInitializationFromClientBuilder() throws IOException {
|
||||
//tag::rest-high-level-client-init
|
||||
RestHighLevelClient client = new RestHighLevelClient(
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
[[java-rest-high-x-pack-info]]
|
||||
=== X-Pack Info API
|
||||
|
||||
[[java-rest-high-x-pack-info-execution]]
|
||||
==== Execution
|
||||
|
||||
General information about the installed {xpack} features can be retrieved
|
||||
using the `xPackInfo()` method:
|
||||
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests}/MiscellaneousDocumentationIT.java[x-pack-info-execute]
|
||||
--------------------------------------------------
|
||||
<1> Enable verbose mode. The default is `false` but `true` will return
|
||||
more information.
|
||||
<2> Set the categories of information to retrieve. The the default is to
|
||||
return no information which is useful for checking if {xpack} is installed
|
||||
but not much else.
|
||||
|
||||
[[java-rest-high-x-pack-info-response]]
|
||||
==== Response
|
||||
|
||||
The returned `XPackInfoResponse` can contain `BuildInfo`, `LicenseInfo`,
|
||||
and `FeatureSetsInfo` depending on the categories requested.
|
||||
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests}/MiscellaneousDocumentationIT.java[x-pack-info-response]
|
||||
--------------------------------------------------
|
||||
<1> `BuildInfo` contains the commit hash from which Elasticsearch was
|
||||
built and the timestamp that the x-pack module was created.
|
||||
<2> `LicenseInfo` contains the type of license that the cluster is using
|
||||
and its expiration date.
|
||||
<3> Basic licenses do not expire and will return this constant.
|
||||
<4> `FeatureSetsInfo` contains a `Map` from the name of a feature to
|
||||
information about a feature like whether or not it is available under
|
||||
the current license.
|
||||
|
||||
[[java-rest-high-x-pack-info-async]]
|
||||
==== Asynchronous Execution
|
||||
|
||||
This request can be executed asynchronously:
|
||||
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests}/MiscellaneousDocumentationIT.java[x-pack-info-execute-async]
|
||||
--------------------------------------------------
|
||||
<1> The `XPackInfoRequest` to execute and the `ActionListener` to use when
|
||||
the execution completes
|
||||
|
||||
The asynchronous method does not block and returns immediately. Once it is
|
||||
completed the `ActionListener` is called back using the `onResponse` method
|
||||
if the execution successfully completed or using the `onFailure` method if
|
||||
it failed.
|
||||
|
||||
A typical listener for `XPackInfoResponse` looks like:
|
||||
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests}/MiscellaneousDocumentationIT.java[x-pack-info-execute-listener]
|
||||
--------------------------------------------------
|
||||
<1> Called when the execution is successfully completed. The response is
|
||||
provided as an argument
|
||||
<2> Called in case of failure. The raised exception is provided as an argument
|
|
@ -53,9 +53,11 @@ The Java High Level REST Client supports the following Miscellaneous APIs:
|
|||
|
||||
* <<java-rest-high-main>>
|
||||
* <<java-rest-high-ping>>
|
||||
* <<java-rest-high-x-pack-info>>
|
||||
|
||||
include::miscellaneous/main.asciidoc[]
|
||||
include::miscellaneous/ping.asciidoc[]
|
||||
include::miscellaneous/x-pack-info.asciidoc[]
|
||||
|
||||
== Indices APIs
|
||||
|
||||
|
@ -181,4 +183,3 @@ The Java High Level REST Client supports the following Scripts APIs:
|
|||
|
||||
include::script/get_script.asciidoc[]
|
||||
include::script/delete_script.asciidoc[]
|
||||
|
||||
|
|
|
@ -411,6 +411,7 @@ public final class ObjectParser<Value, Context> extends AbstractObjectParser<Val
|
|||
INT_ARRAY(START_ARRAY, VALUE_NUMBER, VALUE_STRING),
|
||||
BOOLEAN_ARRAY(START_ARRAY, VALUE_BOOLEAN),
|
||||
OBJECT(START_OBJECT),
|
||||
OBJECT_OR_NULL(START_OBJECT, VALUE_NULL),
|
||||
OBJECT_ARRAY(START_OBJECT, START_ARRAY),
|
||||
OBJECT_OR_BOOLEAN(START_OBJECT, VALUE_BOOLEAN),
|
||||
OBJECT_OR_STRING(START_OBJECT, VALUE_STRING),
|
||||
|
|
|
@ -12,16 +12,23 @@ subprojects {
|
|||
// helper method to find the path to a module
|
||||
ext.xpackModule = { String moduleName -> xpackProject("plugin:${moduleName}").path }
|
||||
|
||||
ext.licenseName = 'Elastic License'
|
||||
ext.licenseUrl = ext.elasticLicenseUrl
|
||||
|
||||
project.ext.licenseFile = rootProject.file('licenses/ELASTIC-LICENSE.txt')
|
||||
project.ext.noticeFile = xpackRootProject.file('NOTICE.txt')
|
||||
|
||||
plugins.withType(PluginBuildPlugin).whenPluginAdded {
|
||||
project.esplugin.licenseFile = rootProject.file('licenses/ELASTIC-LICENSE.txt')
|
||||
project.esplugin.noticeFile = xpackRootProject.file('NOTICE.txt')
|
||||
}
|
||||
|
||||
if (project.name != 'protocol') {
|
||||
tasks.withType(LicenseHeadersTask.class) {
|
||||
approvedLicenses = ['Elastic License', 'Generated']
|
||||
additionalLicense 'ELAST', 'Elastic License', 'Licensed under the Elastic License'
|
||||
}
|
||||
|
||||
ext.licenseName = 'Elastic License'
|
||||
ext.licenseUrl = ext.elasticLicenseUrl
|
||||
|
||||
project.ext.licenseFile = rootProject.file('licenses/ELASTIC-LICENSE.txt')
|
||||
project.ext.noticeFile = xpackRootProject.file('NOTICE.txt')
|
||||
}
|
||||
}
|
||||
|
||||
File checkstyleSuppressions = file('dev-tools/checkstyle_suppressions.xml')
|
||||
|
@ -34,10 +41,6 @@ subprojects {
|
|||
]
|
||||
}
|
||||
|
||||
tasks.withType(LicenseHeadersTask.class) {
|
||||
approvedLicenses = ['Elastic License', 'Generated']
|
||||
additionalLicense 'ELAST', 'Elastic License', 'Licensed under the Elastic License'
|
||||
}
|
||||
ext.projectSubstitutions += [ "org.elasticsearch.plugin:x-pack-core:${version}": xpackModule('core')]
|
||||
ext.projectSubstitutions += [ "org.elasticsearch.plugin:x-pack-deprecation:${version}": xpackModule('deprecation')]
|
||||
ext.projectSubstitutions += [ "org.elasticsearch.plugin:x-pack-graph:${version}": xpackModule('graph')]
|
||||
|
|
|
@ -25,6 +25,7 @@ dependencyLicenses {
|
|||
|
||||
dependencies {
|
||||
compileOnly "org.elasticsearch:elasticsearch:${version}"
|
||||
compile project(':x-pack:protocol')
|
||||
compile "org.apache.httpcomponents:httpclient:${versions.httpclient}"
|
||||
compile "org.apache.httpcomponents:httpcore:${versions.httpcore}"
|
||||
compile "org.apache.httpcomponents:httpcore-nio:${versions.httpcore}"
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
|
|||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.protocol.license.LicenseStatus;
|
||||
|
||||
/**
|
||||
* Data structure for license. Use {@link Builder} to build a license.
|
||||
|
@ -267,14 +268,14 @@ public class License implements ToXContentObject {
|
|||
/**
|
||||
* @return the current license's status
|
||||
*/
|
||||
public Status status() {
|
||||
public LicenseStatus status() {
|
||||
long now = System.currentTimeMillis();
|
||||
if (issueDate > now) {
|
||||
return Status.INVALID;
|
||||
return LicenseStatus.INVALID;
|
||||
} else if (expiryDate < now) {
|
||||
return Status.EXPIRED;
|
||||
return LicenseStatus.EXPIRED;
|
||||
}
|
||||
return Status.ACTIVE;
|
||||
return LicenseStatus.ACTIVE;
|
||||
}
|
||||
|
||||
private void validate() {
|
||||
|
@ -767,41 +768,6 @@ public class License implements ToXContentObject {
|
|||
}
|
||||
}
|
||||
|
||||
public enum Status {
|
||||
|
||||
ACTIVE("active"),
|
||||
INVALID("invalid"),
|
||||
EXPIRED("expired");
|
||||
|
||||
private final String label;
|
||||
|
||||
Status(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String label() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeString(label);
|
||||
}
|
||||
|
||||
public static Status readFrom(StreamInput in) throws IOException {
|
||||
String value = in.readString();
|
||||
switch (value) {
|
||||
case "active":
|
||||
return ACTIVE;
|
||||
case "invalid":
|
||||
return INVALID;
|
||||
case "expired":
|
||||
return EXPIRED;
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown license status [" + value + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> iff the license is a production licnese
|
||||
*/
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.elasticsearch.common.unit.TimeValue;
|
|||
import org.elasticsearch.discovery.DiscoveryModule;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.gateway.GatewayService;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.elasticsearch.xpack.core.XPackPlugin;
|
||||
import org.elasticsearch.xpack.core.XPackSettings;
|
||||
|
@ -72,7 +73,8 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
|
|||
*/
|
||||
static final TimeValue GRACE_PERIOD_DURATION = days(7);
|
||||
|
||||
public static final long BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS = Long.MAX_VALUE - days(365).millis();
|
||||
public static final long BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS =
|
||||
XPackInfoResponse.BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS;
|
||||
|
||||
private final ClusterService clusterService;
|
||||
|
||||
|
|
|
@ -1,298 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.license;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.ActionResponse;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.io.stream.Writeable;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.xpack.core.XPackBuild;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class XPackInfoResponse extends ActionResponse {
|
||||
|
||||
@Nullable private BuildInfo buildInfo;
|
||||
@Nullable private LicenseInfo licenseInfo;
|
||||
@Nullable private FeatureSetsInfo featureSetsInfo;
|
||||
|
||||
public XPackInfoResponse() {}
|
||||
|
||||
public XPackInfoResponse(@Nullable BuildInfo buildInfo, @Nullable LicenseInfo licenseInfo, @Nullable FeatureSetsInfo featureSetsInfo) {
|
||||
this.buildInfo = buildInfo;
|
||||
this.licenseInfo = licenseInfo;
|
||||
this.featureSetsInfo = featureSetsInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The build info (incl. build hash and timestamp)
|
||||
*/
|
||||
public BuildInfo getBuildInfo() {
|
||||
return buildInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The current license info (incl. UID, type/mode. status and expiry date). May return {@code null} when no
|
||||
* license is currently installed.
|
||||
*/
|
||||
public LicenseInfo getLicenseInfo() {
|
||||
return licenseInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The current status of the feature sets in X-Pack. Feature sets describe the features available/enabled in X-Pack.
|
||||
*/
|
||||
public FeatureSetsInfo getFeatureSetsInfo() {
|
||||
return featureSetsInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
super.writeTo(out);
|
||||
out.writeOptionalWriteable(buildInfo);
|
||||
out.writeOptionalWriteable(licenseInfo);
|
||||
out.writeOptionalWriteable(featureSetsInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
this.buildInfo = in.readOptionalWriteable(BuildInfo::new);
|
||||
this.licenseInfo = in.readOptionalWriteable(LicenseInfo::new);
|
||||
this.featureSetsInfo = in.readOptionalWriteable(FeatureSetsInfo::new);
|
||||
}
|
||||
|
||||
public static class LicenseInfo implements ToXContentObject, Writeable {
|
||||
|
||||
private final String uid;
|
||||
private final String type;
|
||||
private final String mode;
|
||||
private final long expiryDate;
|
||||
private final License.Status status;
|
||||
|
||||
public LicenseInfo(License license) {
|
||||
this(license.uid(), license.type(), license.operationMode().name().toLowerCase(Locale.ROOT),
|
||||
license.status(), license.expiryDate());
|
||||
}
|
||||
|
||||
public LicenseInfo(StreamInput in) throws IOException {
|
||||
this(in.readString(), in.readString(), in.readString(), License.Status.readFrom(in), in.readLong());
|
||||
}
|
||||
|
||||
public LicenseInfo(String uid, String type, String mode, License.Status status, long expiryDate) {
|
||||
this.uid = uid;
|
||||
this.type = type;
|
||||
this.mode = mode;
|
||||
this.status = status;
|
||||
this.expiryDate = expiryDate;
|
||||
}
|
||||
|
||||
public String getUid() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public long getExpiryDate() {
|
||||
return expiryDate;
|
||||
}
|
||||
|
||||
public License.Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject()
|
||||
.field("uid", uid)
|
||||
.field("type", type)
|
||||
.field("mode", mode)
|
||||
.field("status", status.label());
|
||||
if (expiryDate != LicenseService.BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS) {
|
||||
builder.timeField("expiry_date_in_millis", "expiry_date", expiryDate);
|
||||
}
|
||||
return builder.endObject();
|
||||
}
|
||||
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeString(uid);
|
||||
out.writeString(type);
|
||||
out.writeString(mode);
|
||||
status.writeTo(out);
|
||||
out.writeLong(expiryDate);
|
||||
}
|
||||
}
|
||||
|
||||
public static class BuildInfo implements ToXContentObject, Writeable {
|
||||
|
||||
private final String hash;
|
||||
private final String timestamp;
|
||||
|
||||
public BuildInfo(XPackBuild build) {
|
||||
this(build.shortHash(), build.date());
|
||||
}
|
||||
|
||||
public BuildInfo(StreamInput input) throws IOException {
|
||||
this(input.readString(), input.readString());
|
||||
}
|
||||
|
||||
public BuildInfo(String hash, String timestamp) {
|
||||
this.hash = hash;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public String getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
public String getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
return builder.startObject()
|
||||
.field("hash", hash)
|
||||
.field("date", timestamp)
|
||||
.endObject();
|
||||
}
|
||||
|
||||
public void writeTo(StreamOutput output) throws IOException {
|
||||
output.writeString(hash);
|
||||
output.writeString(timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FeatureSetsInfo implements ToXContentObject, Writeable {
|
||||
|
||||
private final Map<String, FeatureSet> featureSets;
|
||||
|
||||
public FeatureSetsInfo(StreamInput in) throws IOException {
|
||||
int size = in.readVInt();
|
||||
Map<String, FeatureSet> featureSets = new HashMap<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
FeatureSet featureSet = new FeatureSet(in);
|
||||
featureSets.put(featureSet.name, featureSet);
|
||||
}
|
||||
this.featureSets = Collections.unmodifiableMap(featureSets);
|
||||
}
|
||||
|
||||
public FeatureSetsInfo(Set<FeatureSet> featureSets) {
|
||||
Map<String, FeatureSet> map = new HashMap<>(featureSets.size());
|
||||
for (FeatureSet featureSet : featureSets) {
|
||||
map.put(featureSet.name, featureSet);
|
||||
}
|
||||
this.featureSets = Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
public Map<String, FeatureSet> getFeatureSets() {
|
||||
return featureSets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
List<String> names = new ArrayList<>(this.featureSets.keySet()).stream().sorted().collect(Collectors.toList());
|
||||
for (String name : names) {
|
||||
builder.field(name, featureSets.get(name), params);
|
||||
}
|
||||
return builder.endObject();
|
||||
}
|
||||
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeVInt(featureSets.size());
|
||||
for (FeatureSet featureSet : featureSets.values()) {
|
||||
featureSet.writeTo(out);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FeatureSet implements ToXContentObject, Writeable {
|
||||
|
||||
private final String name;
|
||||
@Nullable private final String description;
|
||||
private final boolean available;
|
||||
private final boolean enabled;
|
||||
@Nullable private final Map<String, Object> nativeCodeInfo;
|
||||
|
||||
public FeatureSet(StreamInput in) throws IOException {
|
||||
this(in.readString(), in.readOptionalString(), in.readBoolean(), in.readBoolean(),
|
||||
in.getVersion().onOrAfter(Version.V_5_4_0) ? in.readMap() : null);
|
||||
}
|
||||
|
||||
public FeatureSet(String name, @Nullable String description, boolean available, boolean enabled,
|
||||
@Nullable Map<String, Object> nativeCodeInfo) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.available = available;
|
||||
this.enabled = enabled;
|
||||
this.nativeCodeInfo = nativeCodeInfo;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public boolean available() {
|
||||
return available;
|
||||
}
|
||||
|
||||
public boolean enabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Map<String, Object> nativeCodeInfo() {
|
||||
return nativeCodeInfo;
|
||||
}
|
||||
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
if (description != null) {
|
||||
builder.field("description", description);
|
||||
}
|
||||
builder.field("available", available);
|
||||
builder.field("enabled", enabled);
|
||||
if (nativeCodeInfo != null) {
|
||||
builder.field("native_code_info", nativeCodeInfo);
|
||||
}
|
||||
return builder.endObject();
|
||||
}
|
||||
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeString(name);
|
||||
out.writeOptionalString(description);
|
||||
out.writeBoolean(available);
|
||||
out.writeBoolean(enabled);
|
||||
if (out.getVersion().onOrAfter(Version.V_5_4_0)) {
|
||||
out.writeMap(nativeCodeInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -9,9 +9,9 @@ import org.elasticsearch.action.ActionListener;
|
|||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.license.LicensingClient;
|
||||
import org.elasticsearch.license.XPackInfoResponse;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoRequest;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse;
|
||||
import org.elasticsearch.xpack.core.action.XPackInfoAction;
|
||||
import org.elasticsearch.xpack.core.action.XPackInfoRequest;
|
||||
import org.elasticsearch.xpack.core.action.XPackInfoRequestBuilder;
|
||||
import org.elasticsearch.xpack.core.ml.client.MachineLearningClient;
|
||||
import org.elasticsearch.xpack.core.monitoring.client.MonitoringClient;
|
||||
|
|
|
@ -12,14 +12,16 @@ import org.elasticsearch.common.inject.Inject;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.license.License;
|
||||
import org.elasticsearch.license.LicenseService;
|
||||
import org.elasticsearch.license.XPackInfoResponse;
|
||||
import org.elasticsearch.license.XPackInfoResponse.FeatureSetsInfo.FeatureSet;
|
||||
import org.elasticsearch.license.XPackInfoResponse.LicenseInfo;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoRequest;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse.FeatureSetsInfo.FeatureSet;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse.LicenseInfo;
|
||||
import org.elasticsearch.tasks.Task;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.xpack.core.XPackBuild;
|
||||
import org.elasticsearch.xpack.core.XPackFeatureSet;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -43,14 +45,15 @@ public class TransportXPackInfoAction extends HandledTransportAction<XPackInfoRe
|
|||
|
||||
XPackInfoResponse.BuildInfo buildInfo = null;
|
||||
if (request.getCategories().contains(XPackInfoRequest.Category.BUILD)) {
|
||||
buildInfo = new XPackInfoResponse.BuildInfo(XPackBuild.CURRENT);
|
||||
buildInfo = new XPackInfoResponse.BuildInfo(XPackBuild.CURRENT.shortHash(), XPackBuild.CURRENT.date());
|
||||
}
|
||||
|
||||
LicenseInfo licenseInfo = null;
|
||||
if (request.getCategories().contains(XPackInfoRequest.Category.LICENSE)) {
|
||||
License license = licenseService.getLicense();
|
||||
if (license != null) {
|
||||
licenseInfo = new LicenseInfo(license);
|
||||
licenseInfo = new LicenseInfo(license.uid(), license.type(), license.operationMode().name().toLowerCase(Locale.ROOT),
|
||||
license.status(), license.expiryDate());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
package org.elasticsearch.xpack.core.action;
|
||||
|
||||
import org.elasticsearch.action.Action;
|
||||
import org.elasticsearch.license.XPackInfoResponse;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse;
|
||||
|
||||
public class XPackInfoAction extends Action<XPackInfoResponse> {
|
||||
|
||||
|
|
|
@ -7,7 +7,8 @@ package org.elasticsearch.xpack.core.action;
|
|||
|
||||
import org.elasticsearch.action.ActionRequestBuilder;
|
||||
import org.elasticsearch.client.ElasticsearchClient;
|
||||
import org.elasticsearch.license.XPackInfoResponse;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoRequest;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
|
|
|
@ -6,15 +6,11 @@
|
|||
package org.elasticsearch.xpack.core.rest.action;
|
||||
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.license.XPackInfoResponse;
|
||||
import org.elasticsearch.rest.BytesRestResponse;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoRequest;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.RestResponse;
|
||||
import org.elasticsearch.rest.action.RestBuilderListener;
|
||||
import org.elasticsearch.rest.action.RestToXContentListener;
|
||||
import org.elasticsearch.xpack.core.XPackClient;
|
||||
import org.elasticsearch.xpack.core.action.XPackInfoRequest;
|
||||
import org.elasticsearch.xpack.core.rest.XPackRestHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -22,7 +18,6 @@ import java.util.EnumSet;
|
|||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||
import static org.elasticsearch.rest.RestRequest.Method.HEAD;
|
||||
import static org.elasticsearch.rest.RestStatus.OK;
|
||||
|
||||
public class RestXPackInfoAction extends XPackRestHandler {
|
||||
public RestXPackInfoAction(Settings settings, RestController controller) {
|
||||
|
@ -48,36 +43,6 @@ public class RestXPackInfoAction extends XPackRestHandler {
|
|||
client.prepareInfo()
|
||||
.setVerbose(verbose)
|
||||
.setCategories(categories)
|
||||
.execute(new RestBuilderListener<XPackInfoResponse>(channel) {
|
||||
@Override
|
||||
public RestResponse buildResponse(XPackInfoResponse infoResponse, XContentBuilder builder) throws Exception {
|
||||
|
||||
builder.startObject();
|
||||
|
||||
if (infoResponse.getBuildInfo() != null) {
|
||||
builder.field("build", infoResponse.getBuildInfo(), request);
|
||||
}
|
||||
|
||||
if (infoResponse.getLicenseInfo() != null) {
|
||||
builder.field("license", infoResponse.getLicenseInfo(), request);
|
||||
} else if (categories.contains(XPackInfoRequest.Category.LICENSE)) {
|
||||
// if the user requested the license info, and there is no license, we should send
|
||||
// back an explicit null value (indicating there is no license). This is different
|
||||
// than not adding the license info at all
|
||||
builder.nullField("license");
|
||||
}
|
||||
|
||||
if (infoResponse.getFeatureSetsInfo() != null) {
|
||||
builder.field("features", infoResponse.getFeatureSetsInfo(), request);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
builder.field("tagline", "You know, for X");
|
||||
}
|
||||
|
||||
builder.endObject();
|
||||
return new BytesRestResponse(OK, builder);
|
||||
}
|
||||
});
|
||||
.execute(new RestToXContentListener<>(channel));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,10 @@ import org.elasticsearch.action.support.ActionFilters;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.license.License;
|
||||
import org.elasticsearch.license.LicenseService;
|
||||
import org.elasticsearch.license.XPackInfoResponse;
|
||||
import org.elasticsearch.license.XPackInfoResponse.FeatureSetsInfo.FeatureSet;
|
||||
import org.elasticsearch.protocol.license.LicenseStatus;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoRequest;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse.FeatureSetsInfo.FeatureSet;
|
||||
import org.elasticsearch.tasks.Task;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.transport.Transport;
|
||||
|
@ -61,7 +63,7 @@ public class TransportXPackInfoActionTests extends ESTestCase {
|
|||
License license = mock(License.class);
|
||||
long expiryDate = randomLong();
|
||||
when(license.expiryDate()).thenReturn(expiryDate);
|
||||
License.Status status = randomFrom(License.Status.values());
|
||||
LicenseStatus status = randomFrom(LicenseStatus.values());
|
||||
when(license.status()).thenReturn(status);
|
||||
String type = randomAlphaOfLength(10);
|
||||
when(license.type()).thenReturn(type);
|
||||
|
|
|
@ -13,11 +13,12 @@ import org.elasticsearch.common.Nullable;
|
|||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.license.License;
|
||||
import org.elasticsearch.license.XPackInfoResponse;
|
||||
import org.elasticsearch.protocol.license.LicenseStatus;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoRequest;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse;
|
||||
import org.elasticsearch.transport.ActionNotFoundTransportException;
|
||||
import org.elasticsearch.transport.RemoteClusterAware;
|
||||
import org.elasticsearch.xpack.core.action.XPackInfoAction;
|
||||
import org.elasticsearch.xpack.core.action.XPackInfoRequest;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
|
@ -136,7 +137,7 @@ public class MlRemoteLicenseChecker {
|
|||
|
||||
static boolean licenseSupportsML(XPackInfoResponse.LicenseInfo licenseInfo) {
|
||||
License.OperationMode mode = License.OperationMode.resolve(licenseInfo.getMode());
|
||||
return licenseInfo.getStatus() == License.Status.ACTIVE &&
|
||||
return licenseInfo.getStatus() == LicenseStatus.ACTIVE &&
|
||||
(mode == License.OperationMode.PLATINUM || mode == License.OperationMode.TRIAL);
|
||||
}
|
||||
|
||||
|
@ -173,7 +174,7 @@ public class MlRemoteLicenseChecker {
|
|||
|
||||
public static String buildErrorMessage(RemoteClusterLicenseInfo clusterLicenseInfo) {
|
||||
StringBuilder error = new StringBuilder();
|
||||
if (clusterLicenseInfo.licenseInfo.getStatus() != License.Status.ACTIVE) {
|
||||
if (clusterLicenseInfo.licenseInfo.getStatus() != LicenseStatus.ACTIVE) {
|
||||
error.append("The license on cluster [").append(clusterLicenseInfo.clusterName)
|
||||
.append("] is not active. ");
|
||||
} else {
|
||||
|
|
|
@ -11,8 +11,8 @@ import org.elasticsearch.client.Client;
|
|||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.license.License;
|
||||
import org.elasticsearch.license.XPackInfoResponse;
|
||||
import org.elasticsearch.protocol.license.LicenseStatus;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.core.action.XPackInfoAction;
|
||||
|
@ -66,16 +66,16 @@ public class MlRemoteLicenseCheckerTests extends ESTestCase {
|
|||
|
||||
public void testLicenseSupportsML() {
|
||||
XPackInfoResponse.LicenseInfo licenseInfo = new XPackInfoResponse.LicenseInfo("uid", "trial", "trial",
|
||||
License.Status.ACTIVE, randomNonNegativeLong());
|
||||
LicenseStatus.ACTIVE, randomNonNegativeLong());
|
||||
assertTrue(MlRemoteLicenseChecker.licenseSupportsML(licenseInfo));
|
||||
|
||||
licenseInfo = new XPackInfoResponse.LicenseInfo("uid", "trial", "trial", License.Status.EXPIRED, randomNonNegativeLong());
|
||||
licenseInfo = new XPackInfoResponse.LicenseInfo("uid", "trial", "trial", LicenseStatus.EXPIRED, randomNonNegativeLong());
|
||||
assertFalse(MlRemoteLicenseChecker.licenseSupportsML(licenseInfo));
|
||||
|
||||
licenseInfo = new XPackInfoResponse.LicenseInfo("uid", "GOLD", "GOLD", License.Status.ACTIVE, randomNonNegativeLong());
|
||||
licenseInfo = new XPackInfoResponse.LicenseInfo("uid", "GOLD", "GOLD", LicenseStatus.ACTIVE, randomNonNegativeLong());
|
||||
assertFalse(MlRemoteLicenseChecker.licenseSupportsML(licenseInfo));
|
||||
|
||||
licenseInfo = new XPackInfoResponse.LicenseInfo("uid", "PLATINUM", "PLATINUM", License.Status.ACTIVE, randomNonNegativeLong());
|
||||
licenseInfo = new XPackInfoResponse.LicenseInfo("uid", "PLATINUM", "PLATINUM", LicenseStatus.ACTIVE, randomNonNegativeLong());
|
||||
assertTrue(MlRemoteLicenseChecker.licenseSupportsML(licenseInfo));
|
||||
}
|
||||
|
||||
|
@ -186,14 +186,14 @@ public class MlRemoteLicenseCheckerTests extends ESTestCase {
|
|||
}
|
||||
|
||||
private XPackInfoResponse.LicenseInfo createPlatinumLicenseResponse() {
|
||||
return new XPackInfoResponse.LicenseInfo("uid", "PLATINUM", "PLATINUM", License.Status.ACTIVE, randomNonNegativeLong());
|
||||
return new XPackInfoResponse.LicenseInfo("uid", "PLATINUM", "PLATINUM", LicenseStatus.ACTIVE, randomNonNegativeLong());
|
||||
}
|
||||
|
||||
private XPackInfoResponse.LicenseInfo createBasicLicenseResponse() {
|
||||
return new XPackInfoResponse.LicenseInfo("uid", "BASIC", "BASIC", License.Status.ACTIVE, randomNonNegativeLong());
|
||||
return new XPackInfoResponse.LicenseInfo("uid", "BASIC", "BASIC", LicenseStatus.ACTIVE, randomNonNegativeLong());
|
||||
}
|
||||
|
||||
private XPackInfoResponse.LicenseInfo createExpiredLicenseResponse() {
|
||||
return new XPackInfoResponse.LicenseInfo("uid", "PLATINUM", "PLATINUM", License.Status.EXPIRED, randomNonNegativeLong());
|
||||
return new XPackInfoResponse.LicenseInfo("uid", "PLATINUM", "PLATINUM", LicenseStatus.EXPIRED, randomNonNegativeLong());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@ import org.elasticsearch.common.xcontent.XContentType;
|
|||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.env.TestEnvironment;
|
||||
import org.elasticsearch.license.XPackInfoResponse;
|
||||
import org.elasticsearch.license.XPackInfoResponse.FeatureSetsInfo;
|
||||
import org.elasticsearch.license.XPackInfoResponse.FeatureSetsInfo.FeatureSet;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse.FeatureSetsInfo;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse.FeatureSetsInfo.FeatureSet;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
import org.elasticsearch.xpack.core.security.support.Validation;
|
||||
import org.elasticsearch.xpack.core.security.user.ElasticUser;
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
apply plugin: 'elasticsearch.build'
|
||||
|
||||
description = 'Request and Response objects for x-pack that are used by the' +
|
||||
' high level rest client and x-pack itself'
|
||||
|
||||
dependencies {
|
||||
compileOnly "org.elasticsearch:elasticsearch:${version}"
|
||||
|
||||
testCompile "org.elasticsearch.test:framework:${version}"
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.elasticsearch.protocol.license;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.io.stream.Writeable;
|
||||
|
||||
/**
|
||||
* Status of an X-Pack license.
|
||||
*/
|
||||
public enum LicenseStatus implements Writeable {
|
||||
|
||||
ACTIVE("active"),
|
||||
INVALID("invalid"),
|
||||
EXPIRED("expired");
|
||||
|
||||
private final String label;
|
||||
|
||||
LicenseStatus(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String label() {
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeString(label);
|
||||
}
|
||||
|
||||
public static LicenseStatus readFrom(StreamInput in) throws IOException {
|
||||
return fromString(in.readString());
|
||||
}
|
||||
|
||||
public static LicenseStatus fromString(String value) {
|
||||
switch (value) {
|
||||
case "active":
|
||||
return ACTIVE;
|
||||
case "invalid":
|
||||
return INVALID;
|
||||
case "expired":
|
||||
return EXPIRED;
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown license status [" + value + "]");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Request and Response objects for the default distribution's License
|
||||
* APIs.
|
||||
*/
|
||||
package org.elasticsearch.protocol.license;
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Request and Response objects for the default distribution's Security
|
||||
* APIs.
|
||||
*/
|
||||
package org.elasticsearch.protocol.security;
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Request and Response objects for the default distribution's Watcher
|
||||
* APIs.
|
||||
*/
|
||||
package org.elasticsearch.protocol.watcher;
|
|
@ -1,9 +1,22 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.core.action;
|
||||
package org.elasticsearch.protocol.xpack;
|
||||
|
||||
import org.elasticsearch.action.ActionRequest;
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
|
@ -14,6 +27,9 @@ import java.io.IOException;
|
|||
import java.util.EnumSet;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Fetch information about X-Pack from the cluster.
|
||||
*/
|
||||
public class XPackInfoRequest extends ActionRequest {
|
||||
|
||||
public enum Category {
|
|
@ -0,0 +1,500 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.elasticsearch.protocol.xpack;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.ActionResponse;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.io.stream.Writeable;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.protocol.license.LicenseStatus;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
|
||||
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
|
||||
|
||||
public class XPackInfoResponse extends ActionResponse implements ToXContentObject {
|
||||
/**
|
||||
* Value of the license's expiration time if it should never expire.
|
||||
*/
|
||||
public static final long BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS = Long.MAX_VALUE - TimeUnit.HOURS.toMillis(24 * 365);
|
||||
// TODO move this constant to License.java once we move License.java to the protocol jar
|
||||
|
||||
@Nullable private BuildInfo buildInfo;
|
||||
@Nullable private LicenseInfo licenseInfo;
|
||||
@Nullable private FeatureSetsInfo featureSetsInfo;
|
||||
|
||||
public XPackInfoResponse() {}
|
||||
|
||||
public XPackInfoResponse(@Nullable BuildInfo buildInfo, @Nullable LicenseInfo licenseInfo, @Nullable FeatureSetsInfo featureSetsInfo) {
|
||||
this.buildInfo = buildInfo;
|
||||
this.licenseInfo = licenseInfo;
|
||||
this.featureSetsInfo = featureSetsInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The build info (incl. build hash and timestamp)
|
||||
*/
|
||||
public BuildInfo getBuildInfo() {
|
||||
return buildInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The current license info (incl. UID, type/mode. status and expiry date). May return {@code null} when no
|
||||
* license is currently installed.
|
||||
*/
|
||||
public LicenseInfo getLicenseInfo() {
|
||||
return licenseInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The current status of the feature sets in X-Pack. Feature sets describe the features available/enabled in X-Pack.
|
||||
*/
|
||||
public FeatureSetsInfo getFeatureSetsInfo() {
|
||||
return featureSetsInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
super.writeTo(out);
|
||||
out.writeOptionalWriteable(buildInfo);
|
||||
out.writeOptionalWriteable(licenseInfo);
|
||||
out.writeOptionalWriteable(featureSetsInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
this.buildInfo = in.readOptionalWriteable(BuildInfo::new);
|
||||
this.licenseInfo = in.readOptionalWriteable(LicenseInfo::new);
|
||||
this.featureSetsInfo = in.readOptionalWriteable(FeatureSetsInfo::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == null || other.getClass() != getClass()) return false;
|
||||
if (this == other) return true;
|
||||
XPackInfoResponse rhs = (XPackInfoResponse) other;
|
||||
return Objects.equals(buildInfo, rhs.buildInfo)
|
||||
&& Objects.equals(licenseInfo, rhs.licenseInfo)
|
||||
&& Objects.equals(featureSetsInfo, rhs.featureSetsInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(buildInfo, licenseInfo, featureSetsInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Strings.toString(this, true, false);
|
||||
}
|
||||
|
||||
private static final ConstructingObjectParser<XPackInfoResponse, Void> PARSER = new ConstructingObjectParser<>(
|
||||
"xpack_info_response", true, (a, v) -> {
|
||||
BuildInfo buildInfo = (BuildInfo) a[0];
|
||||
LicenseInfo licenseInfo = (LicenseInfo) a[1];
|
||||
@SuppressWarnings("unchecked") // This is how constructing object parser works
|
||||
List<FeatureSetsInfo.FeatureSet> featureSets = (List<FeatureSetsInfo.FeatureSet>) a[2];
|
||||
FeatureSetsInfo featureSetsInfo = featureSets == null ? null : new FeatureSetsInfo(new HashSet<>(featureSets));
|
||||
return new XPackInfoResponse(buildInfo, licenseInfo, featureSetsInfo);
|
||||
});
|
||||
static {
|
||||
PARSER.declareObject(optionalConstructorArg(), BuildInfo.PARSER, new ParseField("build"));
|
||||
/*
|
||||
* licenseInfo is sort of "double optional" because it is
|
||||
* optional but it can also be send as `null`.
|
||||
*/
|
||||
PARSER.declareField(optionalConstructorArg(), (p, v) -> {
|
||||
if (p.currentToken() == XContentParser.Token.VALUE_NULL) {
|
||||
return null;
|
||||
}
|
||||
return LicenseInfo.PARSER.parse(p, v);
|
||||
},
|
||||
new ParseField("license"), ValueType.OBJECT_OR_NULL);
|
||||
PARSER.declareNamedObjects(optionalConstructorArg(),
|
||||
(p, c, name) -> FeatureSetsInfo.FeatureSet.PARSER.parse(p, name),
|
||||
new ParseField("features"));
|
||||
}
|
||||
public static XPackInfoResponse fromXContent(XContentParser parser) throws IOException {
|
||||
return PARSER.parse(parser, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
|
||||
if (buildInfo != null) {
|
||||
builder.field("build", buildInfo, params);
|
||||
}
|
||||
|
||||
EnumSet<XPackInfoRequest.Category> categories = XPackInfoRequest.Category
|
||||
.toSet(Strings.splitStringByCommaToArray(params.param("categories", "_all")));
|
||||
if (licenseInfo != null) {
|
||||
builder.field("license", licenseInfo, params);
|
||||
} else if (categories.contains(XPackInfoRequest.Category.LICENSE)) {
|
||||
// if the user requested the license info, and there is no license, we should send
|
||||
// back an explicit null value (indicating there is no license). This is different
|
||||
// than not adding the license info at all
|
||||
builder.nullField("license");
|
||||
}
|
||||
|
||||
if (featureSetsInfo != null) {
|
||||
builder.field("features", featureSetsInfo, params);
|
||||
}
|
||||
|
||||
if (params.paramAsBoolean("human", true)) {
|
||||
builder.field("tagline", "You know, for X");
|
||||
}
|
||||
|
||||
return builder.endObject();
|
||||
}
|
||||
|
||||
public static class LicenseInfo implements ToXContentObject, Writeable {
|
||||
private final String uid;
|
||||
private final String type;
|
||||
private final String mode;
|
||||
private final LicenseStatus status;
|
||||
private final long expiryDate;
|
||||
|
||||
public LicenseInfo(String uid, String type, String mode, LicenseStatus status, long expiryDate) {
|
||||
this.uid = uid;
|
||||
this.type = type;
|
||||
this.mode = mode;
|
||||
this.status = status;
|
||||
this.expiryDate = expiryDate;
|
||||
}
|
||||
|
||||
public LicenseInfo(StreamInput in) throws IOException {
|
||||
this(in.readString(), in.readString(), in.readString(), LicenseStatus.readFrom(in), in.readLong());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeString(uid);
|
||||
out.writeString(type);
|
||||
out.writeString(mode);
|
||||
status.writeTo(out);
|
||||
out.writeLong(expiryDate);
|
||||
}
|
||||
|
||||
public String getUid() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public long getExpiryDate() {
|
||||
return expiryDate;
|
||||
}
|
||||
|
||||
public LicenseStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == null || other.getClass() != getClass()) return false;
|
||||
if (this == other) return true;
|
||||
LicenseInfo rhs = (LicenseInfo) other;
|
||||
return Objects.equals(uid, rhs.uid)
|
||||
&& Objects.equals(type, rhs.type)
|
||||
&& Objects.equals(mode, rhs.mode)
|
||||
&& Objects.equals(status, rhs.status)
|
||||
&& expiryDate == rhs.expiryDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(uid, type, mode, status, expiryDate);
|
||||
}
|
||||
|
||||
private static final ConstructingObjectParser<LicenseInfo, Void> PARSER = new ConstructingObjectParser<>(
|
||||
"license_info", true, (a, v) -> {
|
||||
String uid = (String) a[0];
|
||||
String type = (String) a[1];
|
||||
String mode = (String) a[2];
|
||||
LicenseStatus status = LicenseStatus.fromString((String) a[3]);
|
||||
Long expiryDate = (Long) a[4];
|
||||
long primitiveExpiryDate = expiryDate == null ? BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS : expiryDate;
|
||||
return new LicenseInfo(uid, type, mode, status, primitiveExpiryDate);
|
||||
});
|
||||
static {
|
||||
PARSER.declareString(constructorArg(), new ParseField("uid"));
|
||||
PARSER.declareString(constructorArg(), new ParseField("type"));
|
||||
PARSER.declareString(constructorArg(), new ParseField("mode"));
|
||||
PARSER.declareString(constructorArg(), new ParseField("status"));
|
||||
PARSER.declareLong(optionalConstructorArg(), new ParseField("expiry_date_in_millis"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject()
|
||||
.field("uid", uid)
|
||||
.field("type", type)
|
||||
.field("mode", mode)
|
||||
.field("status", status.label());
|
||||
if (expiryDate != BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS) {
|
||||
builder.timeField("expiry_date_in_millis", "expiry_date", expiryDate);
|
||||
}
|
||||
return builder.endObject();
|
||||
}
|
||||
}
|
||||
|
||||
public static class BuildInfo implements ToXContentObject, Writeable {
|
||||
private final String hash;
|
||||
private final String timestamp;
|
||||
|
||||
public BuildInfo(String hash, String timestamp) {
|
||||
this.hash = hash;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public BuildInfo(StreamInput input) throws IOException {
|
||||
this(input.readString(), input.readString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput output) throws IOException {
|
||||
output.writeString(hash);
|
||||
output.writeString(timestamp);
|
||||
}
|
||||
|
||||
public String getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
public String getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == null || other.getClass() != getClass()) return false;
|
||||
if (this == other) return true;
|
||||
BuildInfo rhs = (BuildInfo) other;
|
||||
return Objects.equals(hash, rhs.hash)
|
||||
&& Objects.equals(timestamp, rhs.timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(hash, timestamp);
|
||||
}
|
||||
|
||||
private static final ConstructingObjectParser<BuildInfo, Void> PARSER = new ConstructingObjectParser<>(
|
||||
"build_info", true, (a, v) -> new BuildInfo((String) a[0], (String) a[1]));
|
||||
static {
|
||||
PARSER.declareString(constructorArg(), new ParseField("hash"));
|
||||
PARSER.declareString(constructorArg(), new ParseField("date"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
return builder.startObject()
|
||||
.field("hash", hash)
|
||||
.field("date", timestamp)
|
||||
.endObject();
|
||||
}
|
||||
}
|
||||
|
||||
public static class FeatureSetsInfo implements ToXContentObject, Writeable {
|
||||
private final Map<String, FeatureSet> featureSets;
|
||||
|
||||
public FeatureSetsInfo(Set<FeatureSet> featureSets) {
|
||||
Map<String, FeatureSet> map = new HashMap<>(featureSets.size());
|
||||
for (FeatureSet featureSet : featureSets) {
|
||||
map.put(featureSet.name, featureSet);
|
||||
}
|
||||
this.featureSets = Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
public FeatureSetsInfo(StreamInput in) throws IOException {
|
||||
int size = in.readVInt();
|
||||
Map<String, FeatureSet> featureSets = new HashMap<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
FeatureSet featureSet = new FeatureSet(in);
|
||||
featureSets.put(featureSet.name, featureSet);
|
||||
}
|
||||
this.featureSets = Collections.unmodifiableMap(featureSets);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeVInt(featureSets.size());
|
||||
for (FeatureSet featureSet : featureSets.values()) {
|
||||
featureSet.writeTo(out);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, FeatureSet> getFeatureSets() {
|
||||
return featureSets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == null || other.getClass() != getClass()) return false;
|
||||
if (this == other) return true;
|
||||
FeatureSetsInfo rhs = (FeatureSetsInfo) other;
|
||||
return Objects.equals(featureSets, rhs.featureSets);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(featureSets);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
List<String> names = new ArrayList<>(this.featureSets.keySet()).stream().sorted().collect(Collectors.toList());
|
||||
for (String name : names) {
|
||||
builder.field(name, featureSets.get(name), params);
|
||||
}
|
||||
return builder.endObject();
|
||||
}
|
||||
|
||||
public static class FeatureSet implements ToXContentObject, Writeable {
|
||||
private final String name;
|
||||
@Nullable private final String description;
|
||||
private final boolean available;
|
||||
private final boolean enabled;
|
||||
@Nullable private final Map<String, Object> nativeCodeInfo;
|
||||
|
||||
public FeatureSet(String name, @Nullable String description, boolean available, boolean enabled,
|
||||
@Nullable Map<String, Object> nativeCodeInfo) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.available = available;
|
||||
this.enabled = enabled;
|
||||
this.nativeCodeInfo = nativeCodeInfo;
|
||||
}
|
||||
|
||||
public FeatureSet(StreamInput in) throws IOException {
|
||||
this(in.readString(), in.readOptionalString(), in.readBoolean(), in.readBoolean(),
|
||||
in.getVersion().onOrAfter(Version.V_5_4_0) ? in.readMap() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeString(name);
|
||||
out.writeOptionalString(description);
|
||||
out.writeBoolean(available);
|
||||
out.writeBoolean(enabled);
|
||||
if (out.getVersion().onOrAfter(Version.V_5_4_0)) {
|
||||
out.writeMap(nativeCodeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public boolean available() {
|
||||
return available;
|
||||
}
|
||||
|
||||
public boolean enabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Map<String, Object> nativeCodeInfo() {
|
||||
return nativeCodeInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == null || other.getClass() != getClass()) return false;
|
||||
if (this == other) return true;
|
||||
FeatureSet rhs = (FeatureSet) other;
|
||||
return Objects.equals(name, rhs.name)
|
||||
&& Objects.equals(description, rhs.description)
|
||||
&& available == rhs.available
|
||||
&& enabled == rhs.enabled
|
||||
&& Objects.equals(nativeCodeInfo, rhs.nativeCodeInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, description, available, enabled, nativeCodeInfo);
|
||||
}
|
||||
|
||||
private static final ConstructingObjectParser<FeatureSet, String> PARSER = new ConstructingObjectParser<>(
|
||||
"feature_set", true, (a, name) -> {
|
||||
String description = (String) a[0];
|
||||
boolean available = (Boolean) a[1];
|
||||
boolean enabled = (Boolean) a[2];
|
||||
@SuppressWarnings("unchecked") // Matches up with declaration below
|
||||
Map<String, Object> nativeCodeInfo = (Map<String, Object>) a[3];
|
||||
return new FeatureSet(name, description, available, enabled, nativeCodeInfo);
|
||||
});
|
||||
static {
|
||||
PARSER.declareString(optionalConstructorArg(), new ParseField("description"));
|
||||
PARSER.declareBoolean(constructorArg(), new ParseField("available"));
|
||||
PARSER.declareBoolean(constructorArg(), new ParseField("enabled"));
|
||||
PARSER.declareObject(optionalConstructorArg(), (p, name) -> p.map(), new ParseField("native_code_info"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
if (description != null) {
|
||||
builder.field("description", description);
|
||||
}
|
||||
builder.field("available", available);
|
||||
builder.field("enabled", enabled);
|
||||
if (nativeCodeInfo != null) {
|
||||
builder.field("native_code_info", nativeCodeInfo);
|
||||
}
|
||||
return builder.endObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Request and Response objects for miscellaneous X-Pack APIs.
|
||||
*/
|
||||
package org.elasticsearch.protocol.xpack;
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.elasticsearch.protocol.license;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
public class LicenseStatusTests extends ESTestCase {
|
||||
public void testSerialization() throws IOException {
|
||||
LicenseStatus status = randomFrom(LicenseStatus.values());
|
||||
assertSame(status, copyWriteable(status, writableRegistry(), LicenseStatus::readFrom));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.protocol.xpack;
|
||||
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.protocol.license.LicenseStatus;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse.BuildInfo;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse.LicenseInfo;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse.FeatureSetsInfo;
|
||||
import org.elasticsearch.protocol.xpack.XPackInfoResponse.FeatureSetsInfo.FeatureSet;
|
||||
import org.elasticsearch.test.AbstractStreamableXContentTestCase;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.io.IOException;
|
||||
|
||||
public class XPackInfoResponseTests extends AbstractStreamableXContentTestCase<XPackInfoResponse> {
|
||||
@Override
|
||||
protected XPackInfoResponse doParseInstance(XContentParser parser) throws IOException {
|
||||
return XPackInfoResponse.fromXContent(parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected XPackInfoResponse createBlankInstance() {
|
||||
return new XPackInfoResponse();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Predicate<String> getRandomFieldsExcludeFilter() {
|
||||
return path -> path.equals("features")
|
||||
|| (path.startsWith("features") && path.endsWith("native_code_info"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ToXContent.Params getToXContentParams() {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
if (randomBoolean()) {
|
||||
params.put("human", randomBoolean() ? "true" : "false");
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
params.put("categories", "_none");
|
||||
}
|
||||
return new ToXContent.MapParams(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected XPackInfoResponse createTestInstance() {
|
||||
return new XPackInfoResponse(
|
||||
randomBoolean() ? null : randomBuildInfo(),
|
||||
randomBoolean() ? null : randomLicenseInfo(),
|
||||
randomBoolean() ? null : randomFeatureSetsInfo());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected XPackInfoResponse mutateInstance(XPackInfoResponse response) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Function<XPackInfoResponse, XPackInfoResponse> mutator = randomFrom(
|
||||
r -> new XPackInfoResponse(
|
||||
mutateBuildInfo(r.getBuildInfo()),
|
||||
r.getLicenseInfo(),
|
||||
r.getFeatureSetsInfo()),
|
||||
r -> new XPackInfoResponse(
|
||||
r.getBuildInfo(),
|
||||
mutateLicenseInfo(r.getLicenseInfo()),
|
||||
r.getFeatureSetsInfo()),
|
||||
r -> new XPackInfoResponse(
|
||||
r.getBuildInfo(),
|
||||
r.getLicenseInfo(),
|
||||
mutateFeatureSetsInfo(r.getFeatureSetsInfo())));
|
||||
return mutator.apply(response);
|
||||
}
|
||||
|
||||
private BuildInfo randomBuildInfo() {
|
||||
return new BuildInfo(
|
||||
randomAlphaOfLength(10),
|
||||
randomAlphaOfLength(15));
|
||||
}
|
||||
|
||||
private BuildInfo mutateBuildInfo(BuildInfo buildInfo) {
|
||||
if (buildInfo == null) {
|
||||
return randomBuildInfo();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private LicenseInfo randomLicenseInfo() {
|
||||
return new LicenseInfo(
|
||||
randomAlphaOfLength(10),
|
||||
randomAlphaOfLength(4),
|
||||
randomAlphaOfLength(5),
|
||||
randomFrom(LicenseStatus.values()),
|
||||
randomLong());
|
||||
}
|
||||
|
||||
private LicenseInfo mutateLicenseInfo(LicenseInfo licenseInfo) {
|
||||
if (licenseInfo == null) {
|
||||
return randomLicenseInfo();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private FeatureSetsInfo randomFeatureSetsInfo() {
|
||||
int size = between(0, 10);
|
||||
Set<FeatureSet> featureSets = new HashSet<>(size);
|
||||
while (featureSets.size() < size) {
|
||||
featureSets.add(randomFeatureSet());
|
||||
}
|
||||
return new FeatureSetsInfo(featureSets);
|
||||
}
|
||||
|
||||
private FeatureSetsInfo mutateFeatureSetsInfo(FeatureSetsInfo featureSetsInfo) {
|
||||
if (featureSetsInfo == null) {
|
||||
return randomFeatureSetsInfo();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private FeatureSet randomFeatureSet() {
|
||||
return new FeatureSet(
|
||||
randomAlphaOfLength(5),
|
||||
randomBoolean() ? null : randomAlphaOfLength(20),
|
||||
randomBoolean(),
|
||||
randomBoolean(),
|
||||
randomNativeCodeInfo());
|
||||
}
|
||||
|
||||
private Map<String, Object> randomNativeCodeInfo() {
|
||||
if (randomBoolean()) {
|
||||
return null;
|
||||
}
|
||||
int size = between(0, 10);
|
||||
Map<String, Object> nativeCodeInfo = new HashMap<>(size);
|
||||
while (nativeCodeInfo.size() < size) {
|
||||
nativeCodeInfo.put(randomAlphaOfLength(5), randomAlphaOfLength(5));
|
||||
}
|
||||
return nativeCodeInfo;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue