- Notifications
You must be signed in to change notification settings - Fork 25.6k
HLREST: Add x-pack-info API #31870
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
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()) { | ||
| Contributor 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 Member Author 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 { | ||
| Member Author 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. Contributor 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 :) Member Author 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. Member 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, | ||
| Member 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") | ||
| Member Author 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"); | ||
| Contributor 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) Member Author 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.