-
Notifications
You must be signed in to change notification settings - Fork 25k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HLREST: Add x-pack-info API #31870
HLREST: Add x-pack-info API #31870
Changes from 17 commits
29eda7c
2f467fb
333b1f0
fbcbff0
5842092
9de82f8
bfdb479
d6699df
35a965c
f3dc606
82af58e
422150c
51d427e
00948be
58506b9
df508dc
6f43ebe
f0a7163
c406f21
743cc81
3a5c8fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -104,6 +104,7 @@ | |
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.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 @@ static Request deleteScript(DeleteStoredScriptRequest deleteStoredScriptRequest) | |
return request; | ||
} | ||
|
||
static Request xPackInfo(XPackInfoRequest infoRequest) { | ||
Request request = new Request(HttpGet.METHOD_NAME, "/_xpack"); | ||
if (false == infoRequest.isVerbose()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can't because it is backwards! This API's defaults to human on the REST side if it isn't specified but |
||
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)); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,6 +66,8 @@ | |
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 final RankEvalResponse rankEval(RankEvalRequest rankEvalRequest, RequestO | |
emptySet()); | ||
} | ||
|
||
|
||
/** | ||
* Executes a request using the Multi Search Template API. | ||
* | ||
|
@@ -678,9 +680,9 @@ public final RankEvalResponse rankEval(RankEvalRequest rankEvalRequest, RequestO | |
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 final void multiSearchTemplateAsync(MultiSearchTemplateRequest multiSearc | |
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 final void fieldCapsAsync(FieldCapabilitiesRequest fieldCapabilitiesReque | |
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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See commit message for explanation of the location. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see the point in this. Im not sure we should diverge from what the other language clients do here until we all do it, tho. Ill let you talk with @elastic/es-clients about it :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I'll end up being one of the first of many rather than a deviation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would have added XPackClient and exposed it as part of the xpack namespace, that is aligned with what we did up until now and also in sync with the spec. I feel like I may have missed some discussions around this though. Maybe we plan on updating the spec as well at some point? |
||
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, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we need the async version of this? Maybe we could do without? |
||
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, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,8 +21,13 @@ | |
|
||
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 void testPing() throws IOException { | |
assertTrue(highLevelClient().ping(RequestOptions.DEFAULT)); | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This just bothered me. |
||
public void testInfo() throws IOException { | ||
MainResponse info = highLevelClient().info(RequestOptions.DEFAULT); | ||
// compare with what the low level client outputs | ||
|
@@ -41,6 +45,7 @@ public void testInfo() throws IOException { | |
|
||
// 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,35 @@ public void testInfo() throws IOException { | |
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"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are we considering all of the description etc a contract that we need to validate does not change? The reason i ask is cuz maybe it does not make sense to test this much detail as to what the output of the strings are.. I get that we can easily check available/enabled, but id hate to see a test fail here cuz we changed the description (unless we view it as a contract) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll remove the words, yeah. |
||
assertEquals("Graph Data Exploration for the Elastic Stack", graph.description()); | ||
assertFalse(graph.available()); | ||
assertTrue(graph.enabled()); | ||
assertNull(graph.nativeCodeInfo()); | ||
FeatureSet monitoring = info.getFeatureSetsInfo().getFeatureSets().get("monitoring"); | ||
assertEquals("Monitoring for the Elastic Stack", monitoring.description()); | ||
assertTrue(monitoring.available()); | ||
assertTrue(monitoring.enabled()); | ||
assertNull(monitoring.nativeCodeInfo()); | ||
FeatureSet ml = info.getFeatureSetsInfo().getFeatureSets().get("ml"); | ||
assertEquals("Machine Learning for the Elastic Stack", ml.description()); | ||
assertFalse(ml.available()); | ||
assertTrue(ml.enabled()); | ||
assertEquals(mainResponse.getVersion().toString(), | ||
ml.nativeCodeInfo().get("version").toString().replace("-SNAPSHOT", "")); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plan to do in a follow up.