Introduced the X-Pack Info API
- Removed Shield's Info API - Removed Watcher's Info API Closes elastic/elasticsearch#2014 Original commit: elastic/x-pack-elasticsearch@6910cb1d6e
This commit is contained in:
parent
98c34f278f
commit
8aa48ffaff
|
@ -685,6 +685,7 @@ public class License implements ToXContent {
|
|||
}
|
||||
|
||||
public enum Status {
|
||||
|
||||
ACTIVE("active"),
|
||||
INVALID("invalid"),
|
||||
EXPIRED("expired");
|
||||
|
@ -698,5 +699,23 @@ public class License implements ToXContent {
|
|||
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 + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
---
|
||||
"Test watcher is protected by shield":
|
||||
- do:
|
||||
headers: {es-shield-runas-user: powerless_user}
|
||||
headers: { es-shield-runas-user: powerless_user }
|
||||
catch: forbidden
|
||||
watcher.info: {}
|
||||
watcher.stats: {}
|
||||
# there seems to be a bug in the yaml parser we use, where a single element list
|
||||
# has the END_LIST token skipped...so here we just rerun the same request without
|
||||
# the impersonation to show it works
|
||||
- do:
|
||||
watcher.info: {}
|
||||
- is_true: version.build_hash
|
||||
watcher.stats: {}
|
||||
- match: { watcher_state: started }
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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.plugin;
|
||||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.client.ElasticsearchClient;
|
||||
import org.elasticsearch.license.core.License;
|
||||
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseAction;
|
||||
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseRequest;
|
||||
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseRequestBuilder;
|
||||
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseResponse;
|
||||
import org.elasticsearch.license.plugin.action.get.GetLicenseAction;
|
||||
import org.elasticsearch.license.plugin.action.get.GetLicenseRequest;
|
||||
import org.elasticsearch.license.plugin.action.get.GetLicenseRequestBuilder;
|
||||
import org.elasticsearch.license.plugin.action.get.GetLicenseResponse;
|
||||
import org.elasticsearch.license.plugin.action.put.PutLicenseAction;
|
||||
import org.elasticsearch.license.plugin.action.put.PutLicenseRequest;
|
||||
import org.elasticsearch.license.plugin.action.put.PutLicenseRequestBuilder;
|
||||
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class LicensingClient {
|
||||
|
||||
private final ElasticsearchClient client;
|
||||
|
||||
public LicensingClient(ElasticsearchClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public PutLicenseRequestBuilder preparePutLicense(License license) {
|
||||
return new PutLicenseRequestBuilder(client).setLicense(license);
|
||||
}
|
||||
|
||||
public void putLicense(PutLicenseRequest request, ActionListener<PutLicenseResponse> listener) {
|
||||
client.execute(PutLicenseAction.INSTANCE, request, listener);
|
||||
}
|
||||
|
||||
public GetLicenseRequestBuilder prepareGetLicense() {
|
||||
return new GetLicenseRequestBuilder(client);
|
||||
}
|
||||
|
||||
public void getLicense(GetLicenseRequest request, ActionListener<GetLicenseResponse> listener) {
|
||||
client.execute(GetLicenseAction.INSTANCE, request, listener);
|
||||
}
|
||||
|
||||
public DeleteLicenseRequestBuilder prepareDeleteLicense() {
|
||||
return new DeleteLicenseRequestBuilder(client);
|
||||
}
|
||||
|
||||
public void deleteLicense(DeleteLicenseRequest request, ActionListener<DeleteLicenseResponse> listener) {
|
||||
client.execute(DeleteLicenseAction.INSTANCE, request, listener);
|
||||
}
|
||||
}
|
|
@ -11,6 +11,10 @@ import org.elasticsearch.client.ElasticsearchClient;
|
|||
public class DeleteLicenseRequestBuilder extends AcknowledgedRequestBuilder<DeleteLicenseRequest, DeleteLicenseResponse,
|
||||
DeleteLicenseRequestBuilder> {
|
||||
|
||||
public DeleteLicenseRequestBuilder(ElasticsearchClient client) {
|
||||
this(client, DeleteLicenseAction.INSTANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new get licenses request builder
|
||||
*
|
||||
|
|
|
@ -11,6 +11,10 @@ import org.elasticsearch.client.ElasticsearchClient;
|
|||
public class GetLicenseRequestBuilder extends MasterNodeReadOperationRequestBuilder<GetLicenseRequest, GetLicenseResponse,
|
||||
GetLicenseRequestBuilder> {
|
||||
|
||||
public GetLicenseRequestBuilder(ElasticsearchClient client) {
|
||||
this(client, GetLicenseAction.INSTANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new get licenses request builder
|
||||
*
|
||||
|
|
|
@ -14,6 +14,10 @@ import org.elasticsearch.license.core.License;
|
|||
*/
|
||||
public class PutLicenseRequestBuilder extends AcknowledgedRequestBuilder<PutLicenseRequest, PutLicenseResponse, PutLicenseRequestBuilder> {
|
||||
|
||||
public PutLicenseRequestBuilder(ElasticsearchClient client) {
|
||||
this(client, PutLicenseAction.INSTANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs register license request
|
||||
*
|
||||
|
|
|
@ -67,7 +67,6 @@ import org.elasticsearch.shield.license.ShieldLicenseState;
|
|||
import org.elasticsearch.shield.license.ShieldLicensee;
|
||||
import org.elasticsearch.shield.rest.ShieldRestModule;
|
||||
import org.elasticsearch.shield.rest.action.RestAuthenticateAction;
|
||||
import org.elasticsearch.shield.rest.action.RestShieldInfoAction;
|
||||
import org.elasticsearch.shield.rest.action.realm.RestClearRealmCacheAction;
|
||||
import org.elasticsearch.shield.rest.action.role.RestPutRoleAction;
|
||||
import org.elasticsearch.shield.rest.action.role.RestClearRolesCacheAction;
|
||||
|
@ -298,9 +297,6 @@ public class Security {
|
|||
return;
|
||||
}
|
||||
|
||||
// we want to expose the shield rest action even when the plugin is disabled
|
||||
module.registerRestHandler(RestShieldInfoAction.class);
|
||||
|
||||
if (enabled) {
|
||||
module.registerTransport(Security.NAME, ShieldNettyTransport.class);
|
||||
module.registerTransportService(Security.NAME, ShieldServerTransportService.class);
|
||||
|
|
|
@ -1,106 +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.shield.rest.action;
|
||||
|
||||
import org.elasticsearch.Build;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.cluster.ClusterName;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.inject.internal.Nullable;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.rest.BaseRestHandler;
|
||||
import org.elasticsearch.rest.BytesRestResponse;
|
||||
import org.elasticsearch.rest.RestChannel;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
import org.elasticsearch.shield.ShieldBuild;
|
||||
import org.elasticsearch.shield.Security;
|
||||
import org.elasticsearch.shield.license.ShieldLicenseState;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||
import static org.elasticsearch.rest.RestRequest.Method.HEAD;
|
||||
|
||||
public class RestShieldInfoAction extends BaseRestHandler {
|
||||
|
||||
private final ClusterName clusterName;
|
||||
private final ShieldLicenseState shieldLicenseState;
|
||||
private final boolean shieldEnabled;
|
||||
|
||||
@Inject
|
||||
public RestShieldInfoAction(Settings settings, RestController controller, Client client, ClusterName clusterName,
|
||||
@Nullable ShieldLicenseState licenseState) {
|
||||
super(settings, client);
|
||||
this.clusterName = clusterName;
|
||||
this.shieldLicenseState = licenseState;
|
||||
this.shieldEnabled = Security.enabled(settings);
|
||||
controller.registerHandler(GET, "/_shield", this);
|
||||
controller.registerHandler(HEAD, "/_shield", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleRequest(RestRequest request, RestChannel channel, Client client) throws Exception {
|
||||
if (request.method() == RestRequest.Method.HEAD) {
|
||||
channel.sendResponse(new BytesRestResponse(RestStatus.OK));
|
||||
return;
|
||||
}
|
||||
|
||||
XContentBuilder builder = channel.newBuilder();
|
||||
|
||||
// Default to pretty printing, but allow ?pretty=false to disable
|
||||
if (!request.hasParam("pretty")) {
|
||||
builder.prettyPrint().lfAtEnd();
|
||||
}
|
||||
|
||||
builder.startObject();
|
||||
|
||||
builder.field("status", resolveStatus());
|
||||
if (settings.get("name") != null) {
|
||||
builder.field("name", settings.get("name"));
|
||||
}
|
||||
builder.field("cluster_name", clusterName.value());
|
||||
builder.startObject("version")
|
||||
.field("number", Version.CURRENT.toString())
|
||||
.field("build_hash", ShieldBuild.CURRENT.hash())
|
||||
.field("build_timestamp", ShieldBuild.CURRENT.timestamp())
|
||||
.field("build_snapshot", Build.CURRENT.isSnapshot())
|
||||
.endObject();
|
||||
builder.field("tagline", "You Know, for Security");
|
||||
builder.endObject();
|
||||
|
||||
channel.sendResponse(new BytesRestResponse(RestStatus.OK, builder));
|
||||
}
|
||||
|
||||
private Status resolveStatus() {
|
||||
if (shieldEnabled) {
|
||||
assert shieldLicenseState != null;
|
||||
// TODO this is error prone since the state could change between checks. We can also make this status better
|
||||
// but we may remove this endpoint since it no longer serves much purpose
|
||||
if (shieldLicenseState.securityEnabled() && shieldLicenseState.statsAndHealthEnabled()) {
|
||||
return Status.ENABLED;
|
||||
}
|
||||
return Status.UNLICENSED;
|
||||
}
|
||||
return Status.DISABLED;
|
||||
}
|
||||
|
||||
private static enum Status {
|
||||
ENABLED("enabled"), DISABLED("disabled"), UNLICENSED("unlicensed");
|
||||
|
||||
private final String status;
|
||||
|
||||
Status(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -95,50 +95,4 @@ public class ShieldPluginEnabledDisabledTests extends ShieldIntegTestCase {
|
|||
assertThat(transport, matcher);
|
||||
}
|
||||
}
|
||||
|
||||
public void testShieldInfoStatus() throws IOException {
|
||||
HttpServerTransport httpServerTransport = internalCluster().getDataNodeInstance(HttpServerTransport.class);
|
||||
OperationMode mode;
|
||||
if (enabled) {
|
||||
mode = randomFrom(OperationMode.values());
|
||||
LicensingTests.enableLicensing(mode);
|
||||
} else {
|
||||
// this is the default right now
|
||||
mode = OperationMode.BASIC;
|
||||
}
|
||||
|
||||
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||
HttpResponse response = new HttpRequestBuilder(httpClient).httpTransport(httpServerTransport)
|
||||
.method("GET")
|
||||
.path("/_shield")
|
||||
.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
basicAuthHeaderValue(ShieldSettingsSource.DEFAULT_USER_NAME,
|
||||
new SecuredString(ShieldSettingsSource.DEFAULT_PASSWORD.toCharArray()))).execute();
|
||||
assertThat(response.getStatusCode(), is(OK.getStatus()));
|
||||
|
||||
String expectedValue;
|
||||
if (enabled) {
|
||||
if (mode == OperationMode.BASIC) {
|
||||
expectedValue = "unlicensed";
|
||||
} else {
|
||||
expectedValue = "enabled";
|
||||
}
|
||||
} else {
|
||||
expectedValue = "disabled";
|
||||
}
|
||||
assertThat(new JsonPath(response.getBody()).evaluate("status").toString(), equalTo(expectedValue));
|
||||
|
||||
if (enabled) {
|
||||
LicensingTests.disableLicensing();
|
||||
response = new HttpRequestBuilder(httpClient).httpTransport(httpServerTransport)
|
||||
.method("GET")
|
||||
.path("/_shield")
|
||||
.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
basicAuthHeaderValue(ShieldSettingsSource.DEFAULT_USER_NAME,
|
||||
new SecuredString(ShieldSettingsSource.DEFAULT_PASSWORD.toCharArray()))).execute();
|
||||
assertThat(response.getStatusCode(), is(OK.getStatus()));
|
||||
assertThat(new JsonPath(response.getBody()).evaluate("status").toString(), equalTo("unlicensed"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,24 +37,25 @@ public class ShieldPluginTests extends ShieldIntegTestCase {
|
|||
public void testThatPluginIsLoaded() throws IOException {
|
||||
HttpServerTransport httpServerTransport = internalCluster().getDataNodeInstance(HttpServerTransport.class);
|
||||
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||
logger.info("executing unauthorized request to /_shield infos");
|
||||
logger.info("executing unauthorized request to /_xpack info");
|
||||
HttpResponse response = new HttpRequestBuilder(httpClient).httpTransport(httpServerTransport)
|
||||
.method("GET")
|
||||
.path("/_shield")
|
||||
.path("/_xpack")
|
||||
.execute();
|
||||
assertThat(response.getStatusCode(), is(UNAUTHORIZED.getStatus()));
|
||||
|
||||
logger.info("executing authorized request to /_shield infos");
|
||||
logger.info("executing authorized request to /_xpack infos");
|
||||
response = new HttpRequestBuilder(httpClient).httpTransport(httpServerTransport)
|
||||
.method("GET")
|
||||
.path("/_shield")
|
||||
.path("/_xpack")
|
||||
.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
basicAuthHeaderValue(ShieldSettingsSource.DEFAULT_USER_NAME,
|
||||
new SecuredString(ShieldSettingsSource.DEFAULT_PASSWORD.toCharArray())))
|
||||
.execute();
|
||||
assertThat(response.getStatusCode(), is(OK.getStatus()));
|
||||
assertThat(response.getBody(), allOf(containsString("status"), containsString("cluster_name"), containsString("number"),
|
||||
containsString("build_hash"), containsString("build_timestamp"), containsString("build_snapshot")));
|
||||
assertThat(response.getBody(), allOf(containsString("status"), containsString("hash"),
|
||||
containsString("timestamp"), containsString("uid"),
|
||||
containsString("type"), containsString("status")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.elasticsearch.graph.Graph;
|
|||
import org.elasticsearch.shield.action.ShieldActionModule;
|
||||
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
|
||||
import org.elasticsearch.test.ShieldIntegTestCase;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -107,6 +108,9 @@ public class KnownActionsTests extends ShieldIntegTestCase {
|
|||
// loading es core actions
|
||||
loadActions(collectSubClasses(Action.class, Action.class), actions);
|
||||
|
||||
// loading all xpack top level actions
|
||||
loadActions(collectSubClasses(Action.class, XPackPlugin.class), actions);
|
||||
|
||||
// loading shield actions
|
||||
loadActions(collectSubClasses(Action.class, ShieldActionModule.class), actions);
|
||||
|
||||
|
@ -115,8 +119,7 @@ public class KnownActionsTests extends ShieldIntegTestCase {
|
|||
|
||||
// also loading all actions from the graph plugin
|
||||
loadActions(collectSubClasses(Action.class, Graph.class), actions);
|
||||
|
||||
|
||||
|
||||
return unmodifiableSet(actions);
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ indices:data/write/index
|
|||
indices:data/write/script/delete
|
||||
indices:data/write/script/put
|
||||
indices:data/write/update
|
||||
cluster:monitor/xpack/info
|
||||
cluster:monitor/xpack/license/get
|
||||
cluster:admin/xpack/license/delete
|
||||
cluster:admin/xpack/license/put
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* 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.shield;
|
||||
package org.elasticsearch.xpack;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
|
@ -17,16 +17,17 @@ import java.util.Properties;
|
|||
/**
|
||||
*
|
||||
*/
|
||||
public class ShieldBuild {
|
||||
public class XPackBuild {
|
||||
|
||||
public static final ShieldBuild CURRENT;
|
||||
|
||||
public static final XPackBuild CURRENT;
|
||||
|
||||
static {
|
||||
String hash = "NA";
|
||||
String hashShort = "NA";
|
||||
String timestamp = "NA";
|
||||
|
||||
try (InputStream is = ShieldBuild.class.getResourceAsStream("/shield-build.properties")) {
|
||||
try (InputStream is = XPackBuild.class.getResourceAsStream("/xpack-build.properties")) {
|
||||
Properties props = new Properties();
|
||||
props.load(is);
|
||||
hash = props.getProperty("hash", hash);
|
||||
|
@ -41,14 +42,14 @@ public class ShieldBuild {
|
|||
// just ignore...
|
||||
}
|
||||
|
||||
CURRENT = new ShieldBuild(hash, hashShort, timestamp);
|
||||
CURRENT = new XPackBuild(hash, hashShort, timestamp);
|
||||
}
|
||||
|
||||
private String hash;
|
||||
private String hashShort;
|
||||
private String timestamp;
|
||||
|
||||
ShieldBuild(String hash, String hashShort, String timestamp) {
|
||||
XPackBuild(String hash, String hashShort, String timestamp) {
|
||||
this.hash = hash;
|
||||
this.hashShort = hashShort;
|
||||
this.timestamp = timestamp;
|
||||
|
@ -66,16 +67,16 @@ public class ShieldBuild {
|
|||
return timestamp;
|
||||
}
|
||||
|
||||
public static ShieldBuild readBuild(StreamInput in) throws IOException {
|
||||
public static XPackBuild readBuild(StreamInput in) throws IOException {
|
||||
String hash = in.readString();
|
||||
String hashShort = in.readString();
|
||||
String timestamp = in.readString();
|
||||
return new ShieldBuild(hash, hashShort, timestamp);
|
||||
return new XPackBuild(hash, hashShort, timestamp);
|
||||
}
|
||||
|
||||
public static void writeBuild(ShieldBuild build, StreamOutput out) throws IOException {
|
||||
public static void writeBuild(XPackBuild build, StreamOutput out) throws IOException {
|
||||
out.writeString(build.hash());
|
||||
out.writeString(build.hashShort());
|
||||
out.writeString(build.timestamp());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,11 +5,17 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack;
|
||||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.license.plugin.LicensingClient;
|
||||
import org.elasticsearch.marvel.client.MonitoringClient;
|
||||
import org.elasticsearch.shield.authc.support.SecuredString;
|
||||
import org.elasticsearch.shield.client.SecurityClient;
|
||||
import org.elasticsearch.watcher.client.WatcherClient;
|
||||
import org.elasticsearch.xpack.action.XPackInfoAction;
|
||||
import org.elasticsearch.xpack.action.XPackInfoRequest;
|
||||
import org.elasticsearch.xpack.action.XPackInfoRequestBuilder;
|
||||
import org.elasticsearch.xpack.action.XPackInfoResponse;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
@ -24,17 +30,27 @@ public class XPackClient {
|
|||
|
||||
private final Client client;
|
||||
|
||||
private final LicensingClient licensingClient;
|
||||
private final MonitoringClient monitoringClient;
|
||||
private final SecurityClient securityClient;
|
||||
private final WatcherClient watcherClient;
|
||||
|
||||
public XPackClient(Client client) {
|
||||
this.client = client;
|
||||
this.licensingClient = new LicensingClient(client);
|
||||
this.monitoringClient = new MonitoringClient(client);
|
||||
this.securityClient = new SecurityClient(client);
|
||||
this.watcherClient = new WatcherClient(client);
|
||||
}
|
||||
|
||||
public Client es() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public LicensingClient licensing() {
|
||||
return licensingClient;
|
||||
}
|
||||
|
||||
public MonitoringClient monitoring() {
|
||||
return monitoringClient;
|
||||
}
|
||||
|
@ -58,6 +74,14 @@ public class XPackClient {
|
|||
* @param passwd The password of the user. This char array can be cleared after calling this method.
|
||||
*/
|
||||
public XPackClient withAuth(String username, char[] passwd) {
|
||||
return withHeaders(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue(username, new SecuredString(passwd))));
|
||||
return withHeaders(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue(username, new SecuredString(passwd))));
|
||||
}
|
||||
|
||||
public XPackInfoRequestBuilder prepareInfo() {
|
||||
return new XPackInfoRequestBuilder(client);
|
||||
}
|
||||
|
||||
public void info(XPackInfoRequest request, ActionListener<XPackInfoResponse> listener) {
|
||||
client.execute(XPackInfoAction.INSTANCE, request, listener);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,10 +25,13 @@ import org.elasticsearch.script.ScriptModule;
|
|||
import org.elasticsearch.shield.authc.AuthenticationModule;
|
||||
import org.elasticsearch.shield.Security;
|
||||
import org.elasticsearch.watcher.Watcher;
|
||||
import org.elasticsearch.xpack.action.TransportXPackInfoAction;
|
||||
import org.elasticsearch.xpack.action.XPackInfoAction;
|
||||
import org.elasticsearch.xpack.common.init.LazyInitializationModule;
|
||||
import org.elasticsearch.xpack.common.init.LazyInitializationService;
|
||||
import org.elasticsearch.xpack.extensions.XPackExtension;
|
||||
import org.elasticsearch.xpack.extensions.XPackExtensionsService;
|
||||
import org.elasticsearch.xpack.rest.RestXPackInfoAction;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.security.AccessController;
|
||||
|
@ -75,6 +78,7 @@ public class XPackPlugin extends Plugin {
|
|||
}
|
||||
|
||||
protected final Settings settings;
|
||||
protected boolean transportClientMode;
|
||||
protected final XPackExtensionsService extensionsService;
|
||||
|
||||
protected Licensing licensing;
|
||||
|
@ -85,6 +89,7 @@ public class XPackPlugin extends Plugin {
|
|||
|
||||
public XPackPlugin(Settings settings) {
|
||||
this.settings = settings;
|
||||
transportClientMode = transportClientMode(settings);
|
||||
this.licensing = new Licensing(settings);
|
||||
this.security = new Security(settings);
|
||||
this.marvel = new Marvel(settings);
|
||||
|
@ -166,6 +171,9 @@ public class XPackPlugin extends Plugin {
|
|||
}
|
||||
|
||||
public void onModule(NetworkModule module) {
|
||||
if (!transportClientMode) {
|
||||
module.registerRestHandler(RestXPackInfoAction.class);
|
||||
}
|
||||
licensing.onModule(module);
|
||||
marvel.onModule(module);
|
||||
security.onModule(module);
|
||||
|
@ -174,6 +182,9 @@ public class XPackPlugin extends Plugin {
|
|||
}
|
||||
|
||||
public void onModule(ActionModule module) {
|
||||
if (!transportClientMode) {
|
||||
module.registerAction(XPackInfoAction.INSTANCE, TransportXPackInfoAction.class);
|
||||
}
|
||||
licensing.onModule(module);
|
||||
marvel.onModule(module);
|
||||
security.onModule(module);
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.xpack.action;
|
||||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.support.ActionFilters;
|
||||
import org.elasticsearch.action.support.HandledTransportAction;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.license.core.License;
|
||||
import org.elasticsearch.license.plugin.core.LicensesService;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.xpack.XPackBuild;
|
||||
import org.elasticsearch.xpack.action.XPackInfoResponse.LicenseInfo;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class TransportXPackInfoAction extends HandledTransportAction<XPackInfoRequest, XPackInfoResponse> {
|
||||
|
||||
private final LicensesService licensesService;
|
||||
|
||||
@Inject
|
||||
public TransportXPackInfoAction(Settings settings, ThreadPool threadPool, TransportService transportService,
|
||||
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
|
||||
LicensesService licensesService) {
|
||||
super(settings, XPackInfoAction.NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver,
|
||||
XPackInfoRequest::new);
|
||||
this.licensesService = licensesService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecute(XPackInfoRequest request, ActionListener<XPackInfoResponse> listener) {
|
||||
XPackInfoResponse.BuildInfo buildInfo = new XPackInfoResponse.BuildInfo(XPackBuild.CURRENT);
|
||||
License license = licensesService.getLicense();
|
||||
LicenseInfo licenseInfo = license != null ? new LicenseInfo(license) : null;
|
||||
XPackInfoResponse response = new XPackInfoResponse(buildInfo, licenseInfo);
|
||||
listener.onResponse(response);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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.xpack.action;
|
||||
|
||||
import org.elasticsearch.action.Action;
|
||||
import org.elasticsearch.client.ElasticsearchClient;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class XPackInfoAction extends Action<XPackInfoRequest, XPackInfoResponse, XPackInfoRequestBuilder> {
|
||||
|
||||
public static final String NAME = "cluster:monitor/xpack/info";
|
||||
public static final XPackInfoAction INSTANCE = new XPackInfoAction();
|
||||
|
||||
public XPackInfoAction() {
|
||||
super(NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XPackInfoRequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||
return new XPackInfoRequestBuilder(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XPackInfoResponse newResponse() {
|
||||
return new XPackInfoResponse();
|
||||
}
|
||||
}
|
|
@ -0,0 +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.
|
||||
*/
|
||||
package org.elasticsearch.xpack.action;
|
||||
|
||||
import org.elasticsearch.action.ActionRequest;
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class XPackInfoRequest extends ActionRequest<XPackInfoRequest> {
|
||||
|
||||
public XPackInfoRequest() {}
|
||||
|
||||
@Override
|
||||
public ActionRequestValidationException validate() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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.xpack.action;
|
||||
|
||||
import org.elasticsearch.action.ActionRequestBuilder;
|
||||
import org.elasticsearch.client.ElasticsearchClient;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class XPackInfoRequestBuilder extends ActionRequestBuilder<XPackInfoRequest, XPackInfoResponse, XPackInfoRequestBuilder> {
|
||||
|
||||
public XPackInfoRequestBuilder(ElasticsearchClient client) {
|
||||
this(client, XPackInfoAction.INSTANCE);
|
||||
}
|
||||
|
||||
public XPackInfoRequestBuilder(ElasticsearchClient client, XPackInfoAction action) {
|
||||
super(client, action, new XPackInfoRequest());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* 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.xpack.action;
|
||||
|
||||
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.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.license.core.License;
|
||||
import org.elasticsearch.xpack.XPackBuild;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class XPackInfoResponse extends ActionResponse {
|
||||
|
||||
private BuildInfo buildInfo;
|
||||
private @Nullable LicenseInfo licenseInfo;
|
||||
|
||||
public XPackInfoResponse() {}
|
||||
|
||||
public XPackInfoResponse(BuildInfo buildInfo, @Nullable LicenseInfo licenseInfo) {
|
||||
this.buildInfo = buildInfo;
|
||||
this.licenseInfo = licenseInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
super.writeTo(out);
|
||||
buildInfo.writeTo(out);
|
||||
if (licenseInfo != null) {
|
||||
out.writeBoolean(true);
|
||||
licenseInfo.writeTo(out);
|
||||
} else {
|
||||
out.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
this.buildInfo = new BuildInfo(in);
|
||||
this.licenseInfo = in.readBoolean() ? new LicenseInfo(in) : null;
|
||||
}
|
||||
|
||||
public static class LicenseInfo implements ToXContent {
|
||||
|
||||
private final String uid;
|
||||
private final String type;
|
||||
private final long expiryDate;
|
||||
private final License.Status status;
|
||||
|
||||
public LicenseInfo(License license) {
|
||||
this(license.uid(), license.type(), license.status(), license.expiryDate());
|
||||
}
|
||||
|
||||
public LicenseInfo(StreamInput in) throws IOException {
|
||||
this(in.readString(), in.readString(), License.Status.readFrom(in), in.readLong());
|
||||
}
|
||||
|
||||
public LicenseInfo(String uid, String type, License.Status status, long expiryDate) {
|
||||
this.uid = uid;
|
||||
this.type = type;
|
||||
this.status = status;
|
||||
this.expiryDate = expiryDate;
|
||||
}
|
||||
|
||||
public String getUid() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public long getExpiryDate() {
|
||||
return expiryDate;
|
||||
}
|
||||
|
||||
public License.Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
return builder.startObject()
|
||||
.field("uid", uid)
|
||||
.field("type", type)
|
||||
.field("mode", License.OperationMode.resolve(type).name().toLowerCase(Locale.ROOT))
|
||||
.field("status", status.label())
|
||||
.dateValueField("expiry_date_in_millis", "expiry_date", expiryDate)
|
||||
.endObject();
|
||||
}
|
||||
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeString(uid);
|
||||
out.writeString(type);
|
||||
status.writeTo(out);
|
||||
out.writeLong(expiryDate);
|
||||
}
|
||||
}
|
||||
|
||||
public static class BuildInfo implements ToXContent {
|
||||
|
||||
private final String hash;
|
||||
private final String timestamp;
|
||||
|
||||
public BuildInfo(XPackBuild build) {
|
||||
this(build.hash(), build.timestamp());
|
||||
}
|
||||
|
||||
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("timestamp", timestamp)
|
||||
.endObject();
|
||||
}
|
||||
|
||||
public void writeTo(StreamOutput output) throws IOException {
|
||||
output.writeString(hash);
|
||||
output.writeString(timestamp);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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.xpack.rest;
|
||||
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.rest.BytesRestResponse;
|
||||
import org.elasticsearch.rest.RestChannel;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.RestResponse;
|
||||
import org.elasticsearch.rest.action.support.RestBuilderListener;
|
||||
import org.elasticsearch.xpack.XPackClient;
|
||||
import org.elasticsearch.xpack.action.XPackInfoResponse;
|
||||
|
||||
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 {
|
||||
|
||||
@Inject
|
||||
public RestXPackInfoAction(Settings settings, RestController controller, Client client) {
|
||||
super(settings, client);
|
||||
controller.registerHandler(HEAD, URI_BASE, this);
|
||||
controller.registerHandler(GET, URI_BASE, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleRequest(RestRequest request, RestChannel restChannel, XPackClient client) throws Exception {
|
||||
client.prepareInfo().execute(new RestBuilderListener<XPackInfoResponse>(restChannel) {
|
||||
@Override
|
||||
public RestResponse buildResponse(XPackInfoResponse infoResponse, XContentBuilder builder) throws Exception {
|
||||
|
||||
// we treat HEAD requests as simple pings to ensure that X-Pack is installed
|
||||
// we still execute the action as we want this request to be authorized
|
||||
if (request.method() == RestRequest.Method.HEAD) {
|
||||
return new BytesRestResponse(OK);
|
||||
}
|
||||
|
||||
builder.startObject();
|
||||
builder.field("build", infoResponse.getBuildInfo(), request);
|
||||
if (infoResponse.getLicenseInfo() != null) {
|
||||
builder.field("license", infoResponse.getLicenseInfo(), request);
|
||||
} else {
|
||||
builder.nullField("license");
|
||||
}
|
||||
builder.field("tagline", "You know, for X");
|
||||
builder.endObject();
|
||||
return new BytesRestResponse(OK, builder);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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.xpack.rest;
|
||||
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.rest.BaseRestHandler;
|
||||
import org.elasticsearch.rest.RestChannel;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.xpack.XPackClient;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public abstract class XPackRestHandler extends BaseRestHandler {
|
||||
|
||||
protected static String URI_BASE = "_xpack";
|
||||
|
||||
public XPackRestHandler(Settings settings, Client client) {
|
||||
super(settings, client);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void handleRequest(RestRequest request, RestChannel channel, Client client) throws Exception {
|
||||
handleRequest(request, channel, new XPackClient(client));
|
||||
}
|
||||
|
||||
protected abstract void handleRequest(RestRequest request, RestChannel channel, XPackClient client) throws Exception;
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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.xpack.action;
|
||||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.support.ActionFilters;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.license.core.License;
|
||||
import org.elasticsearch.license.plugin.core.LicensesService;
|
||||
import org.elasticsearch.shield.user.AnonymousUser;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.core.IsNull.notNullValue;
|
||||
import static org.hamcrest.core.IsNull.nullValue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class TransportXPackInfoActionTests extends ESTestCase {
|
||||
|
||||
private boolean anonymousEnabled;
|
||||
|
||||
@Before
|
||||
public void maybeEnableAnonymous() {
|
||||
anonymousEnabled = randomBoolean();
|
||||
if (anonymousEnabled) {
|
||||
Settings settings = Settings.builder().put(AnonymousUser.ROLES_SETTING.getKey(), "superuser").build();
|
||||
AnonymousUser.initialize(settings);
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void resetAnonymous() {
|
||||
AnonymousUser.initialize(Settings.EMPTY);
|
||||
}
|
||||
|
||||
public void testDoExecute() throws Exception {
|
||||
|
||||
LicensesService licensesService = mock(LicensesService.class);
|
||||
|
||||
TransportXPackInfoAction action = new TransportXPackInfoAction(Settings.EMPTY, mock(ThreadPool.class),
|
||||
mock(TransportService.class), mock(ActionFilters.class), mock(IndexNameExpressionResolver.class), licensesService);
|
||||
|
||||
License license = mock(License.class);
|
||||
long expiryDate = randomLong();
|
||||
when(license.expiryDate()).thenReturn(expiryDate);
|
||||
License.Status status = randomFrom(License.Status.values());
|
||||
when(license.status()).thenReturn(status);
|
||||
String type = randomAsciiOfLength(10);
|
||||
when(license.type()).thenReturn(type);
|
||||
String uid = randomAsciiOfLength(30);
|
||||
when(license.uid()).thenReturn(uid);
|
||||
when(licensesService.getLicense()).thenReturn(license);
|
||||
|
||||
XPackInfoRequest request = new XPackInfoRequest();
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final AtomicReference<XPackInfoResponse> response = new AtomicReference<>();
|
||||
final AtomicReference<Throwable> error = new AtomicReference<>();
|
||||
action.doExecute(request, new ActionListener<XPackInfoResponse>() {
|
||||
@Override
|
||||
public void onResponse(XPackInfoResponse infoResponse) {
|
||||
response.set(infoResponse);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable e) {
|
||||
error.set(e);
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
if (!latch.await(5, TimeUnit.SECONDS)) {
|
||||
fail("waiting too long for ");
|
||||
}
|
||||
|
||||
assertThat(error.get(), nullValue());
|
||||
assertThat(response.get(), notNullValue());
|
||||
|
||||
assertThat(response.get().getBuildInfo(), notNullValue());
|
||||
assertThat(response.get().getLicenseInfo(), notNullValue());
|
||||
assertThat(response.get().getLicenseInfo().getExpiryDate(), is(expiryDate));
|
||||
assertThat(response.get().getLicenseInfo().getStatus(), is(status));
|
||||
assertThat(response.get().getLicenseInfo().getType(), is(type));
|
||||
assertThat(response.get().getLicenseInfo().getUid(), is(uid));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"xpack.info": {
|
||||
"documentation": "Retrieve information about xpack, including buid number/timestamp and license status",
|
||||
"methods": [ "GET", "HEAD" ],
|
||||
"url": {
|
||||
"path": "/_xpack",
|
||||
"paths": [ "/_xpack" ],
|
||||
"parts": {},
|
||||
"params": {}
|
||||
},
|
||||
"body": null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
# Integration tests xpack info API
|
||||
#
|
||||
"X-Pack Info":
|
||||
- do:
|
||||
cluster.health:
|
||||
wait_for_status: yellow
|
||||
|
||||
- do:
|
||||
license.delete: {}
|
||||
- match: { acknowledged: true }
|
||||
|
||||
# we don't have a license now
|
||||
- do:
|
||||
xpack.info: {}
|
||||
- is_true: build.hash
|
||||
- is_true: build.timestamp
|
||||
- is_false: license
|
||||
|
||||
# lets put an active license
|
||||
- do:
|
||||
license.post:
|
||||
body: >
|
||||
{
|
||||
"license": {
|
||||
"uid": "893361dc-9749-4997-93cb-802e3dofh7aa",
|
||||
"type": "internal",
|
||||
"subscription_type": "none",
|
||||
"issue_date_in_millis": 1443484800000,
|
||||
"feature": "watcher",
|
||||
"expiry_date_in_millis": 1914278399999,
|
||||
"max_nodes": 1,
|
||||
"issued_to": "issuedTo",
|
||||
"issuer": "issuer",
|
||||
"signature": "AAAAAQAAAA0Sc90guRIaQEmgLvMnAAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQCQ94dju0pnDZR3Uuypi0ic3aQJ+nvVqe+U8u79Dga5n1qIjcHDh7HvIBJEkF+tnVPlo/PXV/x7BZSwVY1PVErit+6rYix1yuHEgqwxmx/VdRICjCaZM6tk0Ob4dZCPv6Ebn2Mmk89KHC/PwiLPqF6QfwV/Pkpa8k2A3ORJmvYSDvXhe6tCs8dqc4ebrsFxqrZjwWh5CZSpzqqZBFXlngDv2N0hHhpGlueRszD0JJ5dfEL5ZA1DDOrgO9OJVejSHyRqe1L5QRUNdXPVfS+EAG0Dd1cNdJ/sMpYCPnVjbw6iq2/YgM3cuztsXVBY7ij4WnoP3ce7Zjs9TwHn+IqzftC6"
|
||||
}
|
||||
}
|
||||
- match: { license_status: "valid" }
|
||||
|
||||
- do:
|
||||
license.get: {}
|
||||
- match: { license.uid: "893361dc-9749-4997-93cb-802e3dofh7aa" }
|
||||
- match: { license.type: "internal" }
|
||||
- match: { license.status: "active" }
|
||||
|
||||
- do:
|
||||
xpack.info: {}
|
||||
- is_true: build.hash
|
||||
- is_true: build.timestamp
|
||||
- is_true: license
|
||||
- match: { license.uid: "893361dc-9749-4997-93cb-802e3dofh7aa" }
|
||||
- match: { license.type: "internal" }
|
||||
- match: { license.mode: "platinum" }
|
||||
- match: { license.status: "active" }
|
||||
- match: { license.expiry_date_in_millis: 1914278399999 }
|
|
@ -48,7 +48,6 @@ import org.elasticsearch.watcher.rest.action.RestGetWatchAction;
|
|||
import org.elasticsearch.watcher.rest.action.RestHijackOperationAction;
|
||||
import org.elasticsearch.watcher.rest.action.RestPutWatchAction;
|
||||
import org.elasticsearch.watcher.rest.action.RestWatchServiceAction;
|
||||
import org.elasticsearch.watcher.rest.action.RestWatcherInfoAction;
|
||||
import org.elasticsearch.watcher.rest.action.RestWatcherStatsAction;
|
||||
import org.elasticsearch.watcher.support.WatcherIndexTemplateRegistry.TemplateConfig;
|
||||
import org.elasticsearch.watcher.support.clock.ClockModule;
|
||||
|
@ -218,7 +217,6 @@ public class Watcher {
|
|||
module.registerRestHandler(RestPutWatchAction.class);
|
||||
module.registerRestHandler(RestDeleteWatchAction.class);
|
||||
module.registerRestHandler(RestWatcherStatsAction.class);
|
||||
module.registerRestHandler(RestWatcherInfoAction.class);
|
||||
module.registerRestHandler(RestGetWatchAction.class);
|
||||
module.registerRestHandler(RestWatchServiceAction.class);
|
||||
module.registerRestHandler(RestAckWatchAction.class);
|
||||
|
|
|
@ -61,7 +61,7 @@ public class WatcherModule extends AbstractModule {
|
|||
}
|
||||
}
|
||||
|
||||
public static final Integer getHistoryIndexTemplateVersion() {
|
||||
public static Integer getHistoryIndexTemplateVersion() {
|
||||
try (InputStream is = WatcherModule.class.getResourceAsStream(PROPERTIES_FILE)) {
|
||||
Properties properties = new Properties();
|
||||
properties.load(is);
|
||||
|
|
|
@ -1,55 +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.watcher.rest.action;
|
||||
|
||||
import org.elasticsearch.Build;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.rest.BytesRestResponse;
|
||||
import org.elasticsearch.rest.RestChannel;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.RestResponse;
|
||||
import org.elasticsearch.rest.action.support.RestBuilderListener;
|
||||
import org.elasticsearch.watcher.client.WatcherClient;
|
||||
import org.elasticsearch.watcher.rest.WatcherRestHandler;
|
||||
import org.elasticsearch.watcher.transport.actions.stats.WatcherStatsRequest;
|
||||
import org.elasticsearch.watcher.transport.actions.stats.WatcherStatsResponse;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||
import static org.elasticsearch.rest.RestStatus.OK;
|
||||
|
||||
public class RestWatcherInfoAction extends WatcherRestHandler {
|
||||
|
||||
@Inject
|
||||
public RestWatcherInfoAction(Settings settings, RestController controller, Client client) {
|
||||
super(settings, client);
|
||||
controller.registerHandler(GET, URI_BASE, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleRequest(RestRequest request, RestChannel restChannel, WatcherClient client) throws Exception {
|
||||
client.watcherStats(new WatcherStatsRequest(), new RestBuilderListener<WatcherStatsResponse>(restChannel) {
|
||||
@Override
|
||||
public RestResponse buildResponse(WatcherStatsResponse watcherStatsResponse, XContentBuilder builder) throws Exception {
|
||||
builder.startObject()
|
||||
.startObject("version")
|
||||
.field("number", Version.CURRENT.toString())
|
||||
.field("build_hash", watcherStatsResponse.getBuild().hash())
|
||||
.field("build_timestamp", watcherStatsResponse.getBuild().timestamp())
|
||||
.field("build_snapshot", Build.CURRENT.isSnapshot())
|
||||
.endObject()
|
||||
.field("tagline", "You Know, for Alerts & Automation")
|
||||
.endObject();
|
||||
return new BytesRestResponse(OK, builder);
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
version=${project.version}
|
||||
hash=${buildNumber}
|
||||
timestamp=${timestamp}
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"watcher.info": {
|
||||
"documentation": "http://www.elastic.co/guide/en/watcher/current/appendix-api-info.html",
|
||||
"methods": [ "GET" ],
|
||||
"url": {
|
||||
"path": "/_watcher/",
|
||||
"paths": [ "/_watcher/" ],
|
||||
"parts": {
|
||||
},
|
||||
"params": {
|
||||
}
|
||||
},
|
||||
"body": null
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
"Test watcher info api":
|
||||
- do: {watcher.info: {}}
|
||||
- is_true: version.build_hash
|
||||
- is_true: version.build_timestamp
|
Loading…
Reference in New Issue