Merge branch 'master' into reporting/rich-completion-notifications

Original commit: elastic/x-pack-elasticsearch@c2b4626b7e
This commit is contained in:
Shaunak Kashyap 2016-08-04 18:01:49 -07:00
commit 099d82cbb9
265 changed files with 4402 additions and 4310 deletions

View File

@ -1,9 +1,13 @@
apply plugin: 'elasticsearch.build' apply plugin: 'elasticsearch.build'
dependencies { dependencies {
compile project(':x-plugins:elasticsearch:license:base') compile project(':x-plugins:elasticsearch:x-pack')
compile "org.elasticsearch:elasticsearch:${version}" compile "org.elasticsearch:elasticsearch:${version}"
testCompile "org.elasticsearch.test:framework:${version}" testCompile "org.elasticsearch.test:framework:${version}"
} }
project.forbiddenPatterns {
exclude '**/*.key'
}
dependencyLicenses.enabled = false dependencyLicenses.enabled = false

View File

@ -7,13 +7,12 @@ package org.elasticsearch.license.licensor;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BytesRefIterator; import org.apache.lucene.util.BytesRefIterator;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.license.core.CryptUtils; import org.elasticsearch.license.CryptUtils;
import org.elasticsearch.license.core.License; import org.elasticsearch.license.License;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;

View File

@ -20,8 +20,8 @@ import java.security.KeyPair;
import java.security.KeyPairGenerator; import java.security.KeyPairGenerator;
import java.security.SecureRandom; import java.security.SecureRandom;
import static org.elasticsearch.license.core.CryptUtils.writeEncryptedPrivateKey; import static org.elasticsearch.license.CryptUtils.writeEncryptedPrivateKey;
import static org.elasticsearch.license.core.CryptUtils.writeEncryptedPublicKey; import static org.elasticsearch.license.CryptUtils.writeEncryptedPublicKey;
public class KeyPairGeneratorTool extends Command { public class KeyPairGeneratorTool extends Command {

View File

@ -20,7 +20,7 @@ import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.license.core.License; import org.elasticsearch.license.License;
import org.elasticsearch.license.licensor.LicenseSigner; import org.elasticsearch.license.licensor.LicenseSigner;
public class LicenseGeneratorTool extends Command { public class LicenseGeneratorTool extends Command {

View File

@ -20,8 +20,8 @@ import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.license.core.License; import org.elasticsearch.license.License;
import org.elasticsearch.license.core.LicenseVerifier; import org.elasticsearch.license.LicenseVerifier;
public class LicenseVerificationTool extends Command { public class LicenseVerificationTool extends Command {

View File

@ -6,9 +6,9 @@
package org.elasticsearch.license.licensor; package org.elasticsearch.license.licensor;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.DateUtils; import org.elasticsearch.license.DateUtils;
import org.elasticsearch.license.core.License; import org.elasticsearch.license.License;
import org.elasticsearch.license.core.LicenseVerifier; import org.elasticsearch.license.LicenseVerifier;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;

View File

@ -13,8 +13,8 @@ import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.license.core.DateUtils; import org.elasticsearch.license.DateUtils;
import org.elasticsearch.license.core.License; import org.elasticsearch.license.License;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.hamcrest.MatcherAssert; import org.hamcrest.MatcherAssert;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;

View File

@ -13,7 +13,7 @@ import org.elasticsearch.cli.Command;
import org.elasticsearch.cli.CommandTestCase; import org.elasticsearch.cli.CommandTestCase;
import org.elasticsearch.cli.ExitCodes; import org.elasticsearch.cli.ExitCodes;
import org.elasticsearch.cli.UserException; import org.elasticsearch.cli.UserException;
import org.elasticsearch.license.core.License; import org.elasticsearch.license.License;
import org.elasticsearch.license.licensor.TestUtils; import org.elasticsearch.license.licensor.TestUtils;
import org.junit.Before; import org.junit.Before;

View File

@ -14,7 +14,7 @@ import org.elasticsearch.cli.CommandTestCase;
import org.elasticsearch.cli.ExitCodes; import org.elasticsearch.cli.ExitCodes;
import org.elasticsearch.cli.UserException; import org.elasticsearch.cli.UserException;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.License; import org.elasticsearch.license.License;
import org.elasticsearch.license.licensor.TestUtils; import org.elasticsearch.license.licensor.TestUtils;
import org.junit.Before; import org.junit.Before;

View File

@ -1,36 +0,0 @@
elasticsearch-license
=====================
Elasticsearch Licensing core, tools and plugin
## Core
Contains core data structures, utilities used by **Licensor** and **Plugin**.
See `core/` and `core-shaded/`
## Licensor
Contains a collection of tools to generate key-pairs, licenses and validate licenses.
See `licensor/`
see [wiki] (https://github.com/elasticsearch/elasticsearch-license/wiki) for documentation on
[Licensing Tools Usage & Reference] (https://github.com/elasticsearch/elasticsearch-license/wiki/License-Tools-Usage-&-Reference)
## Plugin
**NOTE**: The license plugin has to be packaged with the right public key when being deployed to public repositories in maven
or uploaded to s3. Use `-Dkeys.path=<PATH_TO_KEY_DIR>` with maven command to package the plugin with a specified key.
See `plugin/`
see [Getting Started] (https://github.com/elasticsearch/elasticsearch-license/blob/master/docs/getting-started.asciidoc) to install license plugin.
see [Licensing REST APIs] (https://github.com/elasticsearch/elasticsearch-license/blob/master/docs/license.asciidoc)
to use the license plugin from an elasticsearch deployment.
see [wiki] (https://github.com/elasticsearch/elasticsearch-license/wiki) for documentation on
- [License Plugin Consumer Interface] (https://github.com/elasticsearch/elasticsearch-license/wiki/License---Consumer-Interface)
- [License Plugin Release Process] (https://github.com/elasticsearch/elasticsearch-license/wiki/Plugin-Release-Process)
- [License Plugin Design] (https://github.com/elasticsearch/elasticsearch-license/wiki/License-Plugin--Design)

View File

@ -1,20 +0,0 @@
apply plugin: 'elasticsearch.build'
dependencies {
compile "org.elasticsearch:elasticsearch:${version}"
testCompile "org.elasticsearch.test:framework:${version}"
}
compactProfile = 'full'
dependencyLicenses.enabled = false
jar {
baseName = 'license-core'
}
modifyPom {
project {
artifactId 'license-core'
}
}

View File

@ -1,201 +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.core;
import org.elasticsearch.common.joda.DateMathParser;
import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.joda.Joda;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.hamcrest.MatcherAssert;
import org.joda.time.format.DateTimeFormatter;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.Callable;
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomBoolean;
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomInt;
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomIntBetween;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.test.ESTestCase.randomFrom;
import static org.hamcrest.core.IsEqual.equalTo;
public class TestUtils {
private static final FormatDateTimeFormatter formatDateTimeFormatter = Joda.forPattern("yyyy-MM-dd");
private static final DateMathParser dateMathParser = new DateMathParser(formatDateTimeFormatter);
private static final DateTimeFormatter dateTimeFormatter = formatDateTimeFormatter.printer();
public static String dateMathString(String time, final long now) {
return dateTimeFormatter.print(dateMathParser.parse(time, new Callable<Long>() {
@Override
public Long call() throws Exception {
return now;
}
}));
}
public static long dateMath(String time, final long now) {
return dateMathParser.parse(time, new Callable<Long>() {
@Override
public Long call() throws Exception {
return now;
}
});
}
public static LicenseSpec generateRandomLicenseSpec(int version) {
boolean datesInMillis = randomBoolean();
long now = System.currentTimeMillis();
String uid = UUID.randomUUID().toString();
String feature = "feature__" + randomInt();
String issuer = "issuer__" + randomInt();
String issuedTo = "issuedTo__" + randomInt();
final String type;
final String subscriptionType;
if (version < License.VERSION_NO_FEATURE_TYPE) {
subscriptionType = randomFrom("gold", "silver", "platinum");
type = "subscription";//randomFrom("subscription", "internal", "development");
} else {
subscriptionType = null;
type = randomFrom("basic", "dev", "gold", "silver", "platinum");
}
int maxNodes = randomIntBetween(5, 100);
if (datesInMillis) {
long issueDateInMillis = dateMath("now", now);
long expiryDateInMillis = dateMath("now+10d/d", now);
return new LicenseSpec(version, uid, feature, issueDateInMillis, expiryDateInMillis, type, subscriptionType, issuedTo, issuer,
maxNodes);
} else {
String issueDate = dateMathString("now", now);
String expiryDate = dateMathString("now+10d/d", now);
return new LicenseSpec(version, uid, feature, issueDate, expiryDate, type, subscriptionType, issuedTo, issuer, maxNodes);
}
}
public static String generateLicenseSpecString(LicenseSpec licenseSpec) throws IOException {
XContentBuilder licenses = jsonBuilder();
licenses.startObject();
licenses.startArray("licenses");
licenses.startObject()
.field("uid", licenseSpec.uid)
.field("type", licenseSpec.type)
.field("subscription_type", licenseSpec.subscriptionType)
.field("issued_to", licenseSpec.issuedTo)
.field("issuer", licenseSpec.issuer)
.field("feature", licenseSpec.feature)
.field("max_nodes", licenseSpec.maxNodes);
if (licenseSpec.issueDate != null) {
licenses.field("issue_date", licenseSpec.issueDate);
} else {
licenses.field("issue_date_in_millis", licenseSpec.issueDateInMillis);
}
if (licenseSpec.expiryDate != null) {
licenses.field("expiry_date", licenseSpec.expiryDate);
} else {
licenses.field("expiry_date_in_millis", licenseSpec.expiryDateInMillis);
}
licenses.field("version", licenseSpec.version);
licenses.endObject();
licenses.endArray();
licenses.endObject();
return licenses.string();
}
public static License generateLicenses(LicenseSpec spec) {
License.Builder builder = License.builder()
.uid(spec.uid)
.feature(spec.feature)
.type(spec.type)
.subscriptionType(spec.subscriptionType)
.issuedTo(spec.issuedTo)
.issuer(spec.issuer)
.maxNodes(spec.maxNodes);
if (spec.expiryDate != null) {
builder.expiryDate(DateUtils.endOfTheDay(spec.expiryDate));
} else {
builder.expiryDate(spec.expiryDateInMillis);
}
if (spec.issueDate != null) {
builder.issueDate(DateUtils.beginningOfTheDay(spec.issueDate));
} else {
builder.issueDate(spec.issueDateInMillis);
}
return builder.build();
}
public static void assertLicenseSpec(LicenseSpec spec, License license) {
MatcherAssert.assertThat(license.uid(), equalTo(spec.uid));
MatcherAssert.assertThat(license.issuedTo(), equalTo(spec.issuedTo));
MatcherAssert.assertThat(license.issuer(), equalTo(spec.issuer));
MatcherAssert.assertThat(license.type(), equalTo(spec.type));
MatcherAssert.assertThat(license.maxNodes(), equalTo(spec.maxNodes));
if (spec.issueDate != null) {
MatcherAssert.assertThat(license.issueDate(), equalTo(DateUtils.beginningOfTheDay(spec.issueDate)));
} else {
MatcherAssert.assertThat(license.issueDate(), equalTo(spec.issueDateInMillis));
}
if (spec.expiryDate != null) {
MatcherAssert.assertThat(license.expiryDate(), equalTo(DateUtils.endOfTheDay(spec.expiryDate)));
} else {
MatcherAssert.assertThat(license.expiryDate(), equalTo(spec.expiryDateInMillis));
}
}
public static class LicenseSpec {
public final int version;
public final String feature;
public final String issueDate;
public final long issueDateInMillis;
public final String expiryDate;
public final long expiryDateInMillis;
public final String uid;
public final String type;
public final String subscriptionType;
public final String issuedTo;
public final String issuer;
public final int maxNodes;
public LicenseSpec(String issueDate, String expiryDate) {
this(License.VERSION_CURRENT, UUID.randomUUID().toString(), "feature", issueDate, expiryDate, "trial", "none", "customer",
"elasticsearch", 5);
}
public LicenseSpec(int version, String uid, String feature, long issueDateInMillis, long expiryDateInMillis, String type,
String subscriptionType, String issuedTo, String issuer, int maxNodes) {
this.version = version;
this.feature = feature;
this.issueDateInMillis = issueDateInMillis;
this.issueDate = null;
this.expiryDateInMillis = expiryDateInMillis;
this.expiryDate = null;
this.uid = uid;
this.type = type;
this.subscriptionType = subscriptionType;
this.issuedTo = issuedTo;
this.issuer = issuer;
this.maxNodes = maxNodes;
}
public LicenseSpec(int version, String uid, String feature, String issueDate, String expiryDate, String type,
String subscriptionType, String issuedTo, String issuer, int maxNodes) {
this.version = version;
this.feature = feature;
this.issueDate = issueDate;
this.issueDateInMillis = -1;
this.expiryDate = expiryDate;
this.expiryDateInMillis = -1;
this.uid = uid;
this.type = type;
this.subscriptionType = subscriptionType;
this.issuedTo = issuedTo;
this.issuer = issuer;
this.maxNodes = maxNodes;
}
}
}

View File

@ -1,7 +0,0 @@
subprojects {
project.afterEvaluate {
project.forbiddenPatterns {
exclude '**/*.key'
}
}
}

View File

@ -1,11 +0,0 @@
es.logger.level=INFO
log4j.rootLogger=${es.logger.level}, out
log4j.logger.org.apache.http=INFO, out
log4j.additivity.org.apache.http=false
log4j.logger.org.elasticsearch.license=TRACE
log4j.appender.out=org.apache.log4j.ConsoleAppender
log4j.appender.out.layout=org.apache.log4j.PatternLayout
log4j.appender.out.layout.conversionPattern=[%d{ISO8601}][%-5p][%-25c] %m%n

View File

@ -13,6 +13,7 @@ import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Response; import org.elasticsearch.client.Response;
import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData; import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
@ -113,6 +114,7 @@ public class IndexAuditIT extends ESIntegTestCase {
protected Settings externalClusterClientSettings() { protected Settings externalClusterClientSettings() {
return Settings.builder() return Settings.builder()
.put(Security.USER_SETTING.getKey(), USER + ":" + PASS) .put(Security.USER_SETTING.getKey(), USER + ":" + PASS)
.put(NetworkModule.TRANSPORT_TYPE_KEY, randomFrom("security3", "security4"))
.build(); .build();
} }

View File

@ -1,11 +0,0 @@
/*
* Messy tests that depend on mustache directly. Fix these!
*/
apply plugin: 'elasticsearch.messy-test'
dependencies {
testCompile project(path: ':x-plugins:elasticsearch:x-pack', configuration: 'testArtifacts')
testCompile project(path: ':modules:lang-mustache', configuration: 'runtime')
}

View File

@ -1,393 +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.messy.tests;
import org.elasticsearch.action.admin.cluster.storedscripts.PutStoredScriptRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.mustache.MustachePlugin;
import org.elasticsearch.search.aggregations.AggregatorParsers;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.suggest.Suggesters;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.xpack.common.text.TextTemplate;
import org.elasticsearch.xpack.watcher.actions.ActionWrapper;
import org.elasticsearch.xpack.watcher.actions.ExecutableActions;
import org.elasticsearch.xpack.watcher.condition.always.ExecutableAlwaysCondition;
import org.elasticsearch.xpack.watcher.execution.TriggeredExecutionContext;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.input.Input;
import org.elasticsearch.xpack.watcher.input.search.ExecutableSearchInput;
import org.elasticsearch.xpack.watcher.input.search.SearchInput;
import org.elasticsearch.xpack.watcher.input.search.SearchInputFactory;
import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput;
import org.elasticsearch.xpack.watcher.input.simple.SimpleInput;
import org.elasticsearch.xpack.watcher.support.WatcherScript;
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource;
import org.elasticsearch.xpack.watcher.trigger.schedule.IntervalSchedule;
import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTrigger;
import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTriggerEvent;
import org.elasticsearch.xpack.watcher.watch.Payload;
import org.elasticsearch.xpack.watcher.watch.Watch;
import org.elasticsearch.xpack.watcher.watch.WatchStatus;
import org.joda.time.DateTime;
import org.joda.time.chrono.ISOChronology;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import static java.util.Collections.emptyMap;
import static org.elasticsearch.common.unit.TimeValue.timeValueSeconds;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE;
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.getRandomSupportedSearchType;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.joda.time.DateTimeZone.UTC;
/**
*/
@ClusterScope(scope = SUITE, numClientNodes = 0, transportClientRatio = 0, randomDynamicTemplates = false, supportsDedicatedMasters = false,
numDataNodes = 1)
public class SearchInputIT extends ESIntegTestCase {
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
Collection<Class<? extends Plugin>> types = new ArrayList<>();
types.addAll(super.nodePlugins());
types.add(MustachePlugin.class);
types.add(CustomScriptContextPlugin.class);
return types;
}
private static final String TEMPLATE_QUERY = "{\"query\":{\"bool\":{\"must\":{\"match\":{\"event_type\":{\"query\":\"a\"," +
"\"type\":\"boolean\"}}},\"filter\":{\"range\":{\"_timestamp\":" +
"{\"from\":\"{{ctx.trigger.scheduled_time}}||-{{seconds_param}}\",\"to\":\"{{ctx.trigger.scheduled_time}}\"," +
"\"include_lower\":true,\"include_upper\":true}}}}}}";
@Override
public Settings nodeSettings(int nodeOrdinal) {
final Path tempDir = createTempDir();
final Path configPath = tempDir.resolve("config");
final Path scriptPath = configPath.resolve("scripts");
try {
Files.createDirectories(scriptPath);
} catch (IOException e) {
throw new RuntimeException("failed to create config dir");
}
try (InputStream stream = SearchInputIT.class.getResourceAsStream("/org/elasticsearch/xpack/watcher/input/search/config/scripts" +
"/test_disk_template.mustache");
OutputStream out = Files.newOutputStream(scriptPath.resolve("test_disk_template.mustache"))) {
Streams.copy(stream, out);
} catch (IOException e) {
throw new RuntimeException("failed to copy mustache template");
}
//Set path so ScriptService will pick up the test scripts
return Settings.builder().put(super.nodeSettings(nodeOrdinal))
.put("path.conf", configPath).build();
}
@Override
protected Settings transportClientSettings() {
return Settings.builder()
.put(super.transportClientSettings())
.build();
}
public void testExecute() throws Exception {
SearchSourceBuilder searchSourceBuilder = searchSource().query(
boolQuery().must(matchQuery("event_type", "a")).must(rangeQuery("_timestamp")
.from("{{ctx.trigger.scheduled_time}}||-30s").to("{{ctx.trigger.triggered_time}}")));
SearchRequest searchRequest = client()
.prepareSearch()
.setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
.request()
.source(searchSourceBuilder);
WatcherSearchTemplateRequest request = new WatcherSearchTemplateRequest(searchRequest);
ExecutableSearchInput searchInput = new ExecutableSearchInput(new SearchInput(request, null, null, null), logger,
WatcherClientProxy.of(client()), watcherSearchTemplateService(), null);
WatchExecutionContext ctx = new TriggeredExecutionContext(
new Watch("test-watch",
new ScheduleTrigger(new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES))),
new ExecutableSimpleInput(new SimpleInput(new Payload.Simple()), logger),
new ExecutableAlwaysCondition(logger),
null,
null,
new ExecutableActions(new ArrayList<ActionWrapper>()),
null,
new WatchStatus(new DateTime(0, UTC), emptyMap())),
new DateTime(0, UTC),
new ScheduleTriggerEvent("test-watch", new DateTime(0, UTC), new DateTime(0, UTC)),
timeValueSeconds(5));
SearchInput.Result result = searchInput.execute(ctx, new Payload.Simple());
assertThat(XContentMapValues.extractValue("hits.total", result.payload().data()), equalTo(0));
assertNotNull(result.executedRequest());
assertThat(result.status(), is(Input.Result.Status.SUCCESS));
assertEquals(result.executedRequest().searchType(), request.getRequest().searchType());
assertArrayEquals(result.executedRequest().indices(), request.getRequest().indices());
assertEquals(result.executedRequest().indicesOptions(), request.getRequest().indicesOptions());
XContentSource source = toXContentSource(result);
assertThat(source.getValue("query.bool.must.1.range._timestamp.from"), equalTo("1970-01-01T00:00:00.000Z||-30s"));
assertThat(source.getValue("query.bool.must.1.range._timestamp.to"), equalTo("1970-01-01T00:00:00.000Z"));
}
public void testSearchInlineTemplate() throws Exception {
WatchExecutionContext ctx = createContext();
Map<String, Object> triggerParams = new HashMap<String, Object>();
triggerParams.put("triggered_time", new DateTime(1970, 01, 01, 00, 01, 00, 000, ISOChronology.getInstanceUTC()));
triggerParams.put("scheduled_time", new DateTime(1970, 01, 01, 00, 01, 00, 000, ISOChronology.getInstanceUTC()));
Map<String, Object> ctxParams = new HashMap<String, Object>();
ctxParams.put("id", ctx.id().value());
ctxParams.put("metadata", null);
ctxParams.put("vars", new HashMap<String, Object>());
ctxParams.put("watch_id", "test-watch");
ctxParams.put("trigger", triggerParams);
ctxParams.put("payload", new Payload.Simple().data());
ctxParams.put("execution_time", new DateTime(1970, 01, 01, 00, 01, 00, 000, ISOChronology.getInstanceUTC()));
Map<String, Object> expectedParams = new HashMap<String, Object>();
expectedParams.put("seconds_param", "30s");
expectedParams.put("ctx", ctxParams);
Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s");
WatcherScript template = WatcherScript.inline(TEMPLATE_QUERY).lang("mustache").params(params).build();
SearchRequest request = client().prepareSearch()
.setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
.setIndices("test-search-index").request();
SearchInput.Result executedResult = executeSearchInput(request, template, ctx);
assertNotNull(executedResult.executedRequest());
assertThat(executedResult.status(), is(Input.Result.Status.SUCCESS));
if (getNumShards("test-search-index").numPrimaries > 1) {
assertEquals(executedResult.executedRequest().searchType(), request.searchType());
}
assertArrayEquals(executedResult.executedRequest().indices(), request.indices());
assertEquals(executedResult.executedRequest().indicesOptions(), request.indicesOptions());
XContentSource source = toXContentSource(executedResult);
assertThat(source.getValue("query.bool.filter.0.range._timestamp.from"), equalTo("1970-01-01T00:01:00.000Z||-30s"));
assertThat(source.getValue("query.bool.filter.0.range._timestamp.to"), equalTo("1970-01-01T00:01:00.000Z"));
}
public void testSearchIndexedTemplate() throws Exception {
WatchExecutionContext ctx = createContext();
PutStoredScriptRequest indexedScriptRequest = client().admin().cluster().preparePutStoredScript()
.setId("test-template")
.setScriptLang("mustache")
.setSource(new BytesArray(TEMPLATE_QUERY))
.request();
assertThat(client().admin().cluster().putStoredScript(indexedScriptRequest).actionGet().isAcknowledged(), is(true));
Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s");
WatcherScript template = WatcherScript.indexed("test-template").lang("mustache").params(params).build();
jsonBuilder().value(TextTemplate.indexed("test-template").params(params).build()).bytes();
SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
.setIndices("test-search-index").request();
SearchInput.Result executedResult = executeSearchInput(request, template, ctx);
assertNotNull(executedResult.executedRequest());
assertThat(executedResult.status(), is(Input.Result.Status.SUCCESS));
if (getNumShards("test-search-index").numPrimaries > 1) {
assertEquals(executedResult.executedRequest().searchType(), request.searchType());
}
assertArrayEquals(executedResult.executedRequest().indices(), request.indices());
assertEquals(executedResult.executedRequest().indicesOptions(), request.indicesOptions());
XContentSource source = toXContentSource(executedResult);
assertThat(source.getValue("query.bool.filter.0.range._timestamp.from"), equalTo("1970-01-01T00:01:00.000Z||-30s"));
assertThat(source.getValue("query.bool.filter.0.range._timestamp.to"), equalTo("1970-01-01T00:01:00.000Z"));
}
public void testSearchOnDiskTemplate() throws Exception {
WatchExecutionContext ctx = createContext();
Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s");
WatcherScript template = WatcherScript.file("test_disk_template").lang("mustache").params(params).build();
SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
.setIndices("test-search-index").request();
SearchInput.Result executedResult = executeSearchInput(request, template, ctx);
assertNotNull(executedResult.executedRequest());
assertThat(executedResult.status(), is(Input.Result.Status.SUCCESS));
assertArrayEquals(executedResult.executedRequest().indices(), request.indices());
assertEquals(executedResult.executedRequest().indicesOptions(), request.indicesOptions());
}
public void testDifferentSearchType() throws Exception {
SearchSourceBuilder searchSourceBuilder = searchSource().query(
boolQuery().must(matchQuery("event_type", "a")).must(rangeQuery("_timestamp")
.from("{{ctx.trigger.scheduled_time}}||-30s").to("{{ctx.trigger.triggered_time}}"))
);
SearchType searchType = getRandomSupportedSearchType();
SearchRequest searchRequest = client()
.prepareSearch()
.setSearchType(searchType)
.request()
.source(searchSourceBuilder);
WatcherSearchTemplateRequest request = new WatcherSearchTemplateRequest(searchRequest);
ExecutableSearchInput searchInput = new ExecutableSearchInput(new SearchInput(request, null, null, null), logger,
WatcherClientProxy.of(client()), watcherSearchTemplateService(), null);
WatchExecutionContext ctx = new TriggeredExecutionContext(
new Watch("test-watch",
new ScheduleTrigger(new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES))),
new ExecutableSimpleInput(new SimpleInput(new Payload.Simple()), logger),
new ExecutableAlwaysCondition(logger),
null,
null,
new ExecutableActions(new ArrayList<ActionWrapper>()),
null,
new WatchStatus(new DateTime(0, UTC), emptyMap())),
new DateTime(0, UTC),
new ScheduleTriggerEvent("test-watch", new DateTime(0, UTC), new DateTime(0, UTC)),
timeValueSeconds(5));
SearchInput.Result result = searchInput.execute(ctx, new Payload.Simple());
assertThat(XContentMapValues.extractValue("hits.total", result.payload().data()), equalTo(0));
assertNotNull(result.executedRequest());
assertThat(result.status(), is(Input.Result.Status.SUCCESS));
assertEquals(result.executedRequest().searchType(), searchType);
assertArrayEquals(result.executedRequest().indices(), searchRequest.indices());
assertEquals(result.executedRequest().indicesOptions(), searchRequest.indicesOptions());
XContentSource source = toXContentSource(result);
assertThat(source.getValue("query.bool.must.1.range._timestamp.from"), equalTo("1970-01-01T00:00:00.000Z||-30s"));
assertThat(source.getValue("query.bool.must.1.range._timestamp.to"), equalTo("1970-01-01T00:00:00.000Z"));
}
public void testParserValid() throws Exception {
SearchRequest searchRequest = client().prepareSearch()
.setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
.request()
.source(searchSource()
.query(boolQuery().must(matchQuery("event_type", "a")).must(rangeQuery("_timestamp")
.from("{{ctx.trigger.scheduled_time}}||-30s").to("{{ctx.trigger.triggered_time}}"))));
TimeValue timeout = randomBoolean() ? TimeValue.timeValueSeconds(randomInt(10)) : null;
XContentBuilder builder = jsonBuilder().value(
new SearchInput(new WatcherSearchTemplateRequest(searchRequest), null, timeout, null));
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken();
IndicesQueriesRegistry indicesQueryRegistry = internalCluster().getInstance(IndicesQueriesRegistry.class);
SearchInputFactory factory = new SearchInputFactory(Settings.EMPTY, WatcherClientProxy.of(client()), indicesQueryRegistry,
null, null, scriptService());
SearchInput searchInput = factory.parseInput("_id", parser);
assertEquals(SearchInput.TYPE, searchInput.type());
assertThat(searchInput.getTimeout(), equalTo(timeout));
}
private WatchExecutionContext createContext() {
return new TriggeredExecutionContext(
new Watch("test-watch",
new ScheduleTrigger(new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES))),
new ExecutableSimpleInput(new SimpleInput(new Payload.Simple()), logger),
new ExecutableAlwaysCondition(logger),
null,
null,
new ExecutableActions(new ArrayList<ActionWrapper>()),
null,
new WatchStatus(new DateTime(50000, UTC), emptyMap())),
new DateTime(60000, UTC),
new ScheduleTriggerEvent("test-watch", new DateTime(60000, UTC), new DateTime(60000, UTC)),
timeValueSeconds(5));
}
private SearchInput.Result executeSearchInput(SearchRequest request, WatcherScript template,
WatchExecutionContext ctx) throws IOException {
createIndex("test-search-index");
ensureGreen("test-search-index");
SearchInput.Builder siBuilder = SearchInput.builder(new WatcherSearchTemplateRequest(request, template));
SearchInput si = siBuilder.build();
ExecutableSearchInput searchInput = new ExecutableSearchInput(si, logger, WatcherClientProxy.of(client()),
watcherSearchTemplateService(), null);
return searchInput.execute(ctx, new Payload.Simple());
}
protected WatcherSearchTemplateService watcherSearchTemplateService() {
String master = internalCluster().getMasterName();
return new WatcherSearchTemplateService(internalCluster().clusterService(master).getSettings(),
internalCluster().getInstance(ScriptService.class, master),
internalCluster().getInstance(IndicesQueriesRegistry.class, master),
internalCluster().getInstance(AggregatorParsers.class, master),
internalCluster().getInstance(Suggesters.class, master)
);
}
protected ScriptService scriptService() {
return internalCluster().getInstance(ScriptService.class);
}
private XContentSource toXContentSource(SearchInput.Result result) throws IOException {
try (XContentBuilder builder = jsonBuilder()) {
result.executedRequest().source().toXContent(builder, ToXContent.EMPTY_PARAMS);
return new XContentSource(builder);
}
}
/**
* Custom plugin that registers XPack script context.
*/
public static class CustomScriptContextPlugin extends Plugin implements ScriptPlugin {
@Override
public ScriptContext.Plugin getCustomScriptContexts() {
return WatcherScript.CTX_PLUGIN;
}
}
}

View File

@ -1,23 +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.
*/
/**
* This package contains tests that use mustache to test what looks
* to be unrelated functionality, or functionality that should be
* tested with a mock instead. Instead of doing an epic battle
* with these tests, they are temporarily moved here to the mustache
* module's tests, but that is likely not where they belong. Please
* help by cleaning them up and we can remove this package!
*
* <ul>
* <li>If the test is testing templating integration with another core subsystem,
* fix it to use a mock instead, so it can be in the core tests again</li>
* <li>If the test is just being lazy, and does not really need templating to test
* something, clean it up!</li>
* </ul>
*/
package org.elasticsearch.messy.tests;

View File

@ -1,26 +0,0 @@
{
"query": {
"bool": {
"must" : [
{
"match": {
"event_type": {
"query": "a",
"type": "boolean"
}
}
},
{
"range": {
"_timestamp": {
"from": "{{ctx.trigger.scheduled_time}}||-{{seconds_param}}",
"to": "{{ctx.trigger.scheduled_time}}",
"include_lower": true,
"include_upper": true
}
}
}
]
}
}
}

View File

@ -1,26 +0,0 @@
{
"query": {
"bool": {
"must" : [
{
"match": {
"event_type": {
"query": "a",
"type": "boolean"
}
}
},
{
"range": {
"_timestamp": {
"from": "{{ctx.trigger.scheduled_time}}||-{{seconds_param}}",
"to": "{{ctx.trigger.scheduled_time}}",
"include_lower": true,
"include_upper": true
}
}
}
]
}
}
}

View File

@ -8,6 +8,8 @@ integTest {
cluster { cluster {
setting 'script.inline', 'true' setting 'script.inline', 'true'
plugin ':x-plugins:elasticsearch:x-pack' plugin ':x-plugins:elasticsearch:x-pack'
// Whitelist reindexing from the local node so we can test it.
setting 'reindex.remote.whitelist', 'myself'
extraConfigFile 'x-pack/roles.yml', 'roles.yml' extraConfigFile 'x-pack/roles.yml', 'roles.yml'
[ [
test_admin: 'superuser', test_admin: 'superuser',

View File

@ -10,6 +10,8 @@ admin:
# Search and write on both source and destination indices. It should work if you could just search on the source and # Search and write on both source and destination indices. It should work if you could just search on the source and
# write to the destination but that isn't how security works. # write to the destination but that isn't how security works.
minimal: minimal:
cluster:
- cluster:monitor/main
indices: indices:
- names: source - names: source
privileges: privileges:
@ -26,18 +28,24 @@ minimal:
# Read only operations on indices # Read only operations on indices
readonly: readonly:
cluster:
- cluster:monitor/main
indices: indices:
- names: '*' - names: '*'
privileges: [ read ] privileges: [ read ]
# Write operations on destination index, none on source index # Write operations on destination index, none on source index
dest_only: dest_only:
cluster:
- cluster:monitor/main
indices: indices:
- names: dest - names: dest
privileges: [ write ] privileges: [ write ]
# Search and write on both source and destination indices with document level security filtering out some docs. # Search and write on both source and destination indices with document level security filtering out some docs.
can_not_see_hidden_docs: can_not_see_hidden_docs:
cluster:
- cluster:monitor/main
indices: indices:
- names: source - names: source
privileges: privileges:
@ -59,6 +67,8 @@ can_not_see_hidden_docs:
# Search and write on both source and destination indices with field level security. # Search and write on both source and destination indices with field level security.
can_not_see_hidden_fields: can_not_see_hidden_fields:
cluster:
- cluster:monitor/main
indices: indices:
- names: source - names: source
privileges: privileges:

View File

@ -147,10 +147,9 @@
indices.refresh: {} indices.refresh: {}
- do: - do:
headers: {es-security-runas-user: dest_only_user} headers: {es-security-runas-user: minimal_user}
catch: forbidden catch: forbidden
reindex: reindex:
refresh: true
body: body:
source: source:
index: source index: source

View File

@ -0,0 +1,418 @@
---
"Reindex from remote as superuser works":
- skip:
features: catch_unauthorized
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
reindex:
body:
source:
remote:
host: http://${host}
username: test_admin
password: changeme
index: source
dest:
index: dest
- match: {created: 1}
---
"Reindex from remote searching as user with minimal privileges works":
- skip:
features: catch_unauthorized
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
reindex:
refresh: true
body:
source:
remote:
host: http://${host}
username: minimal_user
password: changeme
index: source
dest:
index: dest
- match: {created: 1}
- do:
search:
index: dest
body:
query:
match:
text: test
- match: { hits.total: 1 }
---
"Reindex from remote reading as readonly user works when the indexing user is allowed to index":
- skip:
features: catch_unauthorized
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
reindex:
refresh: true
body:
source:
remote:
host: http://${host}
username: readonly_user
password: changeme
index: source
dest:
index: dest
- do:
search:
index: dest
body:
query:
match:
text: test
- match: { hits.total: 1 }
---
"Reindex from remote as user that can't read from the source is forbidden":
- skip:
features: catch_unauthorized
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
catch: forbidden
reindex:
body:
source:
remote:
host: http://${host}
username: dest_only_user
password: changeme
index: source
dest:
index: dest
---
"Using a script to write to an index to which you don't have access is forbidden even if you read as a superuser":
- do:
index:
index: source
type: tweet
id: 1
body: { "user": "kimchy" }
- do:
index:
index: source
type: tweet
id: 2
body: { "user": "another" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
headers: {es-security-runas-user: minimal_user}
catch: forbidden
reindex:
body:
source:
remote:
host: http://${host}
username: test_admin
password: changeme
index: source
dest:
index: dest
script:
inline: if (ctx._source.user == "kimchy") {ctx._index = 'other_dest'}
- do:
indices.refresh: {}
# The index to which the user tried the unauthorized write didn't even get created
- do:
catch: missing
search:
index: other_dest
# Even the authorized index won't have made it because it was in the same batch as the unauthorized one.
# If there had been lots of documents being copied then some might have made it into the authorized index.
- do:
catch: missing
search:
index: dest
---
"Reindex from remote misses hidden docs":
- skip:
features: catch_unauthorized
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test" }
- do:
index:
index: source
type: foo
id: 2
body: { "text": "test", "hidden": true }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
reindex:
refresh: true
body:
source:
remote:
host: http://${host}
username: can_not_see_hidden_docs_user
password: changeme
index: source
dest:
index: dest
- match: {created: 1}
# We copied just one doc, presumably the one without the hidden field
- do:
search:
index: dest
body:
query:
match:
text: test
- match: { hits.total: 1 }
# We didn't copy the doc with the hidden field
- do:
search:
index: dest
body:
query:
match:
hidden: true
- match: { hits.total: 0 }
---
"Reindex misses hidden fields":
- skip:
features: catch_unauthorized
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test", "foo": "z", "bar": "z" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
reindex:
refresh: true
body:
source:
remote:
host: http://${host}
username: can_not_see_hidden_fields_user
password: changeme
index: source
dest:
index: dest
- match: {created: 1}
- do:
search:
index: dest
body:
query:
match:
foo: z
- match: { hits.total: 1 }
- do:
search:
index: dest
body:
query:
match:
bar: z
- match: { hits.total: 1 }
- do:
search:
index: dest
body:
query:
match:
text: test
- match: { hits.total: 0 }
---
"Reindex from remote with bad password is unauthorized":
- skip:
features: catch_unauthorized
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
catch: unauthorized
reindex:
body:
source:
remote:
host: http://${host}
username: test_admin
password: badpass
index: source
dest:
index: dest
---
"Reindex from remote with no username or password is unauthorized":
- skip:
features: catch_unauthorized
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
catch: unauthorized
reindex:
body:
source:
remote:
host: http://${host}
index: source
dest:
index: dest

View File

@ -10,10 +10,11 @@ import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo; import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse; import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.transport.MockTransportClient; import org.elasticsearch.xpack.XPackTransportClient;
import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
@ -39,6 +40,7 @@ public class SecurityTransportClientIT extends ESIntegTestCase {
protected Settings externalClusterClientSettings() { protected Settings externalClusterClientSettings() {
return Settings.builder() return Settings.builder()
.put(Security.USER_SETTING.getKey(), ADMIN_USER_PW) .put(Security.USER_SETTING.getKey(), ADMIN_USER_PW)
.put(NetworkModule.TRANSPORT_TYPE_KEY, randomFrom("security3", "security4"))
.build(); .build();
} }
@ -116,6 +118,6 @@ public class SecurityTransportClientIT extends ESIntegTestCase {
.put("cluster.name", clusterName) .put("cluster.name", clusterName)
.build(); .build();
return new MockTransportClient(settings, XPackPlugin.class).addTransportAddress(publishAddress); return new XPackTransportClient(settings).addTransportAddress(publishAddress);
} }
} }

View File

@ -13,6 +13,7 @@ import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException; import org.elasticsearch.client.ResponseException;
import org.elasticsearch.client.transport.NoNodeAvailableException; import org.elasticsearch.client.transport.NoNodeAvailableException;
import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
@ -22,7 +23,6 @@ import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.XPackTransportClient; import org.elasticsearch.xpack.XPackTransportClient;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -39,6 +39,7 @@ public class CustomRealmIT extends ESIntegTestCase {
return Settings.builder() return Settings.builder()
.put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER) .put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER)
.put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW) .put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW)
.put(NetworkModule.TRANSPORT_TYPE_KEY, randomFrom("security3", "security4"))
.build(); .build();
} }

View File

@ -154,12 +154,12 @@ project.rootProject.subprojects.findAll { it.path.startsWith(':plugins:') }.each
integTest { integTest {
cluster { cluster {
setting 'xpack.monitoring.collection.interval', '3s' setting 'xpack.monitoring.collection.interval', '3s'
setting 'xpack.monitoring.collection.exporters._http.type', 'http' setting 'xpack.monitoring.exporters._http.type', 'http'
setting 'xpack.monitoring.collection.exporters._http.enabled', 'false' setting 'xpack.monitoring.exporters._http.enabled', 'false'
setting 'xpack.monitoring.collection.exporters._http.ssl.truststore.path', clientKeyStore.name setting 'xpack.monitoring.exporters._http.ssl.truststore.path', clientKeyStore.name
setting 'xpack.monitoring.collection.exporters._http.ssl.truststore.password', 'keypass' setting 'xpack.monitoring.exporters._http.ssl.truststore.password', 'keypass'
setting 'xpack.monitoring.collection.exporters._http.auth.username', 'monitoring_agent' setting 'xpack.monitoring.exporters._http.auth.username', 'monitoring_agent'
setting 'xpack.monitoring.collection.exporters._http.auth.password', 'changeme' setting 'xpack.monitoring.exporters._http.auth.password', 'changeme'
setting 'xpack.security.transport.ssl.enabled', 'true' setting 'xpack.security.transport.ssl.enabled', 'true'
setting 'xpack.security.http.ssl.enabled', 'true' setting 'xpack.security.http.ssl.enabled', 'true'

View File

@ -47,6 +47,15 @@ import static org.hamcrest.Matchers.greaterThanOrEqualTo;
*/ */
public class SmokeTestMonitoringWithSecurityIT extends ESIntegTestCase { public class SmokeTestMonitoringWithSecurityIT extends ESIntegTestCase {
private boolean useSecurity3;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
useSecurity3 = randomBoolean();
}
private static final String USER = "test_user"; private static final String USER = "test_user";
private static final String PASS = "changeme"; private static final String PASS = "changeme";
private static final String KEYSTORE_PASS = "keypass"; private static final String KEYSTORE_PASS = "keypass";
@ -59,13 +68,18 @@ public class SmokeTestMonitoringWithSecurityIT extends ESIntegTestCase {
@Override @Override
protected Settings externalClusterClientSettings() { protected Settings externalClusterClientSettings() {
return Settings.builder() final Settings.Builder builder =
Settings.builder()
.put(Security.USER_SETTING.getKey(), USER + ":" + PASS) .put(Security.USER_SETTING.getKey(), USER + ":" + PASS)
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true) .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
.put("xpack.security.ssl.keystore.path", clientKeyStore) .put("xpack.security.ssl.keystore.path", clientKeyStore)
.put("xpack.security.ssl.keystore.password", KEYSTORE_PASS) .put("xpack.security.ssl.keystore.password", KEYSTORE_PASS);
.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME) if (useSecurity3) {
.build(); builder.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME3);
} else {
builder.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME4);
}
return builder.build();
} }
@Before @Before
@ -74,8 +88,8 @@ public class SmokeTestMonitoringWithSecurityIT extends ESIntegTestCase {
URI uri = new URI("https", null, httpAddress.getHostString(), httpAddress.getPort(), "/", null, null); URI uri = new URI("https", null, httpAddress.getHostString(), httpAddress.getPort(), "/", null, null);
Settings exporterSettings = Settings.builder() Settings exporterSettings = Settings.builder()
.put("xpack.monitoring.collection.exporters._http.enabled", true) .put("xpack.monitoring.exporters._http.enabled", true)
.put("xpack.monitoring.collection.exporters._http.host", uri.toString()) .put("xpack.monitoring.exporters._http.host", uri.toString())
.build(); .build();
assertAcked(client().admin().cluster().prepareUpdateSettings().setTransientSettings(exporterSettings)); assertAcked(client().admin().cluster().prepareUpdateSettings().setTransientSettings(exporterSettings));
} }
@ -83,8 +97,8 @@ public class SmokeTestMonitoringWithSecurityIT extends ESIntegTestCase {
@After @After
public void disableExporter() { public void disableExporter() {
Settings exporterSettings = Settings.builder() Settings exporterSettings = Settings.builder()
.putNull("xpack.monitoring.collection.exporters._http.enabled") .putNull("xpack.monitoring.exporters._http.enabled")
.putNull("xpack.monitoring.collection.exporters._http.host") .putNull("xpack.monitoring.exporters._http.host")
.build(); .build();
assertAcked(client().admin().cluster().prepareUpdateSettings().setTransientSettings(exporterSettings)); assertAcked(client().admin().cluster().prepareUpdateSettings().setTransientSettings(exporterSettings));
} }

View File

@ -11,9 +11,9 @@
metric: [ settings ] metric: [ settings ]
- is_true: nodes - is_true: nodes
- is_true: nodes.$master.settings.xpack.monitoring.collection.exporters._http.type - is_true: nodes.$master.settings.xpack.monitoring.exporters._http.type
- is_false: nodes.$master.settings.xpack.monitoring.collection.exporters._http.auth.username - is_false: nodes.$master.settings.xpack.monitoring.exporters._http.auth.username
- is_false: nodes.$master.settings.xpack.monitoring.collection.exporters._http.auth.password - is_false: nodes.$master.settings.xpack.monitoring.exporters._http.auth.password
- is_false: nodes.$master.settings.xpack.monitoring.collection.exporters._http.ssl.truststore.path - is_false: nodes.$master.settings.xpack.monitoring.exporters._http.ssl.truststore.path
- is_false: nodes.$master.settings.xpack.monitoring.collection.exporters._http.ssl.truststore.password - is_false: nodes.$master.settings.xpack.monitoring.exporters._http.ssl.truststore.password

View File

@ -35,7 +35,7 @@ import java.util.Map;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
public class WatcherTemplateTests extends ESTestCase { public class WatcherTemplateIT extends ESTestCase {
private TextTemplateEngine engine; private TextTemplateEngine engine;

View File

@ -0,0 +1,157 @@
---
setup:
- do:
cluster.health:
wait_for_status: yellow
- do: {xpack.watcher.stats:{}}
- do:
index:
index: idx
type: type
id: 1
body: >
{
"date" : "2015-01-01T00:00:00",
"value" : "val_1"
}
- do:
index:
index: idx
type: type
id: 2
body: >
{
"date" : "2015-01-02T00:00:00",
"value" : "val_2"
}
- do:
index:
index: idx
type: type
id: 3
body: >
{
"date" : "2015-01-03T00:00:00",
"value" : "val_3"
}
- do:
index:
index: idx
type: type
id: 4
body: >
{
"date" : "2015-01-04T00:00:00",
"value" : "val_4"
}
- do:
indices.refresh:
index: idx
---
"Test input mustache integration":
- do:
xpack.watcher.execute_watch:
body: >
{
"trigger_data" : {
"scheduled_time" : "2015-01-04T00:00:00"
},
"watch" : {
"trigger" : { "schedule" : { "interval" : "10s" } },
"actions" : {
"dummy" : {
"logging" : {
"text" : "executed!"
}
}
},
"input" : {
"search" : {
"request" : {
"indices" : "idx",
"body" : {
"query" : {
"bool" : {
"filter" : [
{
"range" : {
"date" : {
"lte" : "{{ctx.trigger.scheduled_time}}",
"gte" : "{{ctx.trigger.scheduled_time}}||-3d"
}
}
}
]
}
}
}
}
}
}
}
}
- match: { "watch_record.result.input.type": "search" }
- match: { "watch_record.result.input.status": "success" }
- match: { "watch_record.result.input.payload.hits.total": 4 }
# makes sure that the mustache template snippets have been resolved correctly:
- match: { "watch_record.result.input.search.request.body.query.bool.filter.0.range.date.from": "2015-01-04T00:00:00.000Z||-3d" }
- match: { "watch_record.result.input.search.request.body.query.bool.filter.0.range.date.to": "2015-01-04T00:00:00.000Z" }
---
"Test transform mustache integration":
- do:
xpack.watcher.execute_watch:
body: >
{
"trigger_data" : {
"scheduled_time" : "2015-01-04T00:00:00"
},
"watch" : {
"trigger" : { "schedule" : { "interval" : "10s" } },
"input" : { "simple" : { "value" : "val_3" } },
"actions" : {
"dummy" : {
"logging" : {
"text" : "executed!"
}
}
},
"transform" : {
"search" : {
"request" : {
"indices" : "idx",
"body" : {
"query" : {
"bool" : {
"filter" : [
{
"range" : {
"date" : {
"lte" : "{{ctx.trigger.scheduled_time}}",
"gte" : "{{ctx.trigger.scheduled_time}}||-1d"
}
}
},
{
"term" : {
"value" : "{{ctx.payload.value}}"
}
}
]
}
}
}
}
}
}
}
}
- match: { "watch_record.result.transform.type": "search" }
- match: { "watch_record.result.transform.status": "success" }
- match: { "watch_record.result.transform.payload.hits.total": 1 }
- match: { "watch_record.result.transform.payload.hits.hits.0._id": "3" }
# makes sure that the mustache template snippets have been resolved correctly:
- match: { "watch_record.result.transform.search.request.body.query.bool.filter.0.range.date.from": "2015-01-04T00:00:00.000Z||-1d" }
- match: { "watch_record.result.transform.search.request.body.query.bool.filter.0.range.date.to": "2015-01-04T00:00:00.000Z" }
- match: { "watch_record.result.transform.search.request.body.query.bool.filter.1.term.value.value": "val_3" }

View File

@ -1,440 +0,0 @@
SOFTWARE END USER LICENSE AGREEMENT
READ THIS AGREEMENT CAREFULLY, WHICH CONSTITUTES A LEGALLY BINDING AGREEMENT AND GOVERNS YOUR USE OF
ELASTICSEARCHS PROPRIETARY SOFTWARE. BY INSTALLING AND/OR USING SUCH SOFTWARE, YOU ARE INDICATING THAT YOU AGREE TO THE
TERMS AND CONDITIONS SET FORTH IN THIS AGREEMENT. IF YOU DO NOT AGREE WITH SUCH TERMS AND CONDITIONS, YOU MAY NOT
INSTALL OR USE ANY OF THE SOFTWARE.
This END USER LICENSE AGREEMENT (this “Agreement") is entered into by and between the applicable Elasticsearch
entity referenced in Attachment 1 hereto (“Elasticsearch”) and the person or entity (“You”) that has downloaded any of
Elasticsearchs proprietary software to which this Agreement is attached or in connection with which this Agreement is
presented to You (collectively, the “Software”). This Agreement is effective upon the earlier of the date on the
commencement of any License granted pursuant to Section 1.1. below (as applicable, the “Effective Date”).
1. SOFTWARE LICENSE AND RESTRICTIONS
1.1 License Grants.
(a) Trial Version License. Subject to the terms and conditions of this Agreement, Elasticsearch agrees to
grant, and does hereby grant to You, for a period of thirty (30) days from the date on which You first install the
Software (the “Trial Term”), a License to the to use the Eligible Features and Functions of the Software that are
applicable to the Trial Version of the Software.   You understand and agree that upon the expiration of a Trial Term,
You will no longer be able to use the Software, unless you either (i) purchase a Subscription, in which case You will
receive a License under Section 1.1(b) below to use the Eligible Features and Functions of the Software that are
applicable to the Subscription that You purchase, (ii) undertake the Registration of Your use of the Software with
Elasticsearch, in which case You will receive a License under Section 1.1(c) below to the Basic Version of the Software
or (iii) obtain from Elasticsearch written consent (e-mail sufficient) to extend the Trial Term, which may be granted by
Elasticsearch in its sole and absolute discretion.
(b) Subscription License. Subject to the terms and conditions of this Agreement and complete payment of any and
all applicable Subscription fees, Elasticsearch agrees to grant, and does hereby grant to You during the Subscription
Term, and for the restricted scope of this Agreement, a License (i) to use the Eligible Features and Functions of the
Software that are applicable to the Subscription level that You have purchased, (ii) for the number of Nodes (as defined
in the Elasticsearch Support Services Policy) and (iii) for the specific project for which you have purchased a
Subscription. The level of Subscription, the number of Nodes and specific project for which you have purchased such
Subscription, are set forth on the applicable ordering document entered into by Elasticsearch and You for the purchase
of the applicable Subscription (“Order Form”).
(c) Basic Version License. Subject to the terms and conditions of this Agreement, and in consideration of the
Registration of Your use the Software, Elasticsearch agrees to grant, and does hereby grant to You, for a period of one
(1) year from the date of Registration (“Basic Term”), a License to use the Eligible Features and Functions of the
Software that are applicable to the Basic Version of the Software.
1.2 Reservation of Rights; Restrictions. As between Elasticsearch and You, Elasticsearch owns all right title and
interest in and to the Software and any derivative works thereof, and except as expressly set forth in Section 1.1
above, no other license to the Software is granted to You by implication, estoppel or otherwise. You agree not to: (i)
reverse engineer or decompile, decrypt, disassemble or otherwise reduce any Software or any portion thereof to
human-readable form, except and only to the extent any such restriction is prohibited by applicable law, (ii) deploy the
Software on more Nodes (as defined in Elasticsearchs Support Services Policy) than are permitted under the applicable
License grant in Section 1.1 above (iii) where You have purchased a Subscription, use the Software in connection with
any project other than the project for which you have purchased such Subscription, as identified on the applicable Order
Form, (iv) prepare derivative works from, modify, copy or use the Software in any manner except as expressly permitted
in this Agreement; (v) except as expressly permitted in Section 1.1 above, transfer, sell, rent, lease, distribute,
sublicense, loan or otherwise transfer the Software in whole or in part to any third party; (vi) except as may be
expressly permitted on an applicable Order Form, use the Software for providing time-sharing services, any
software-as-a-service offering (“SaaS”), service bureau services or as part of an application services provider or other
service offering; (vii) circumvent the limitations on use of the Software that are imposed or preserved by any License
Key, (viii) alter or remove any proprietary notices in the Software; or (ix) make available to any third party any
analysis of the results of operation of the Software, including benchmarking results, without the prior written consent
of Elasticsearch. The Software may contain or be provided with open source libraries, components, utilities and other
open source software (collectively, “Open Source Software”), which Open Source Software may have applicable license
terms as identified on a website designated by Elasticsearch or otherwise provided with the Software or Documentation.
Notwithstanding anything to the contrary herein, use of the Open Source Software shall be subject to the license terms
and conditions applicable to such Open Source Software, to the extent required by the applicable licensor (which terms
shall not restrict the license rights granted to You hereunder, but may contain additional rights).
1.3 Audit Rights. You agree that, unless such right is waived in writing by Elasticsearch, Elasticsearch shall have the
right, upon fifteen (15) days notice to You, to audit Your use of the Software for compliance with any quantitative
limitations on Your use of the Software that are set forth in the applicable Order Form. You agree to provide
Elasticsearch with the necessary access to the Software to conduct such an audit either (i) remotely, or (ii) if remote
performance is not possible, at Your facilities, during normal business hours and no more than one (1) time in any
twelve (12) month period. In the event any such audit reveals that You have used the Software in excess of the
applicable quantitative limitations, You agree to solely for Your internal business operations, a limited,
non-exclusive, non-transferable, fully paid up,  right and license (without the right to grant or authorize sublicenses)
promptly pay to Elasticsearch an amount equal to the difference between the fees actually paid and the fees that You
should have paid to remain in compliance with such quantitative limitations. This Section 1.3 shall survive for a
period of two (2) years from the termination or expiration of this Agreement.
1.4 Cluster Metadata. You understand and agree that once deployed, and on a daily basis, the Software may provide
metadata to Elasticsearch about Your cluster statistics and associates that metadata with Your IP address. However, no
other information is provided to Elasticsearch by the Software, including any information about the data You process or
store in connection with your use of the Software. Instructions for disabling this feature are contained in the
Software, however leaving this feature active enables Elasticsearch to gather cluster statistics and provide an improved
level of support to You.
2. TERM AND TERMINATION
2.1 Term. Unless earlier terminated under Section 2.2 below, this Agreement shall commence on the Effective Date, and
shall continue in force for the term of the last to expire applicable license set forth in Section 1.1 above.
2.2 Termination. Either party may, upon written notice to the other party, terminate this Agreement for material breach
by the other party automatically and without any other formality, if such party has failed to cure such material breach
within thirty (30) days of receiving written notice of such material breach from the non-breaching party.
Notwithstanding the foregoing, this Agreement shall automatically terminate in the event that You intentionally breach
the scope of the license granted in Section 1.1 of this Agreement, provided that Elasticsearch reserves the right to
retroactively waive such automatic termination upon written notice to You.
2.3 Post Termination or Expiration. Upon termination or expiration of this Agreement, for any reason, You shall
promptly cease the use of the Software and Documentation and destroy (and certify to Elasticsearch in writing the fact
of such destruction), or return to Elasticsearch, all copies of the Software and Documentation then in Your possession
or under Your control.
2.4 Survival. Sections 2.3, 2.4, 3, 4 and 5 (as any such Sections may be modified by Attachment 1, if applicable) shall
survive any termination or expiration of this Agreement.
3. LIMITED WARRANTY AND DISCLAIMER OF WARRANTIES
3.1 Limited Performance Warranty. Subject to You purchasing a Subscription, Elasticsearch warrants that during the
applicable Subscription Term, the Software will perform in all material respects in accordance with the Documentation.
In the event of a breach of the foregoing warranty, Elasticsearchs sole obligation, and Your exclusive remedy shall be
for Elasticsearch to (i) correct any failure(s) of the Software to perform in all material respects in accordance with
the Documentation or (ii) if Elasticsearch is unable to provide such a correction within thirty (30) days of receipt of
notice of the applicable non-conformity, promptly refund to Customer any pre-paid, unused fees paid by You to
Elasticsearch for the applicable Subscription. The warranty set forth in this Section 3.1 does not apply if the
applicable Software or any portion thereof: (a) has been altered, except by or on behalf Elasticsearch; (b) has not been
used, installed, operated, repaired, or maintained in accordance with this Agreement and/or the Documentation; (c) has
been subjected to abnormal physical or electrical stress, misuse, negligence, or accident; or (d) is used on equipment,
products, or systems not meeting specifications identified by Elasticsearch in the Documentation. Additionally, the
warranties set forth herein only apply when notice of a warranty claim is provided to Elasticsearch within the
applicable warranty period specified herein and do not apply to any bug, defect or error caused by or attributable to
software or hardware not supplied by Elasticsearch.
3.2 Malicious Code. Elasticsearch represents and warrants that prior to making it available for delivery to You,
Elasticsearch will use standard industry practices including, without limitation, the use of an updated commercial
anti-virus program, to test the Software for Malicious Code and remove any Malicious Code it discovers. In the event of
a breach of the foregoing warranty, Elasticsearchs sole obligation, and Your exclusive remedy shall be for
Elasticsearch to replace the Software with Software that does not contain any Malicious Code.
3.3 Warranty Disclaimer. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW, THE SOFTWARE IS PROVIDED “AS IS” WITHOUT
WARRANTY OF ANY KIND, AND ELASTICSEARCH AND ITS LICENSORS MAKE NO WARRANTIES WHETHER EXPRESSED, IMPLIED OR STATUTORY
REGARDING OR RELATING TO THE SOFTWARE OR DOCUMENTATION. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW,
ELASTICSEARCH AND ITS LICENSORS SPECIFICALLY DISCLAIM ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NON-INFRINGEMENT WITH RESPECT TO THE SOFTWARE AND DOCUMENTATION, AND WITH RESPECT TO THE USE OF
THE FOREGOING. FURTHER, ELASTICSEARCH DOES NOT WARRANT RESULTS OF USE OR THAT THE SOFTWARE WILL BE ERROR FREE OR THAT
THE USE OF THE SOFTWARE WILL BE UNINTERRUPTED.
4. LIMITATION OF LIABILITY
The provisions of this Section 4 apply if You have not purchased a Subscription. If you have purchased a Subscription,
then the limitations of liability set forth in the applicable Subscription Agreement will apply in lieu of those set
forth in this Section 4.
4.1 Disclaimer of Certain Damages. IN NO EVENT SHALL YOU OR ELASTICSEARCH OR ITS LICENSORS BE LIABLE FOR ANY LOSS OF
PROFITS, LOSS OF USE, BUSINESS INTERRUPTION, LOSS OF DATA, COST OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND IN CONNECTION WITH OR ARISING OUT OF THE USE OR INABILITY TO
USE THE SOFTWARE, OR THE PERFORMANCE OF OR FAILURE TO PERFORM THIS AGREEMENT, WHETHER ALLEGED AS A BREACH OF CONTRACT OR
TORTIOUS CONDUCT, INCLUDING NEGLIGENCE, EVEN IF THE RESPONSIBLE PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES. THE LIMITATIONS OF LIABILITY SET FORTH IN THIS SECTION 4.1 SHALL NOT APPLY TO A BREACH THROUGH GROSS NEGLIGENCE
OR INTENTIONAL MISCONDUCT BY YOU OF THE SCOPE OF THE LICENSE GRANTED IN SECTION 1.1 OR TO ANY OTHER LIABILITY THAT
CANNOT BE EXCLUDED OR LIMITED UNDER APPLICABLE LAW.
4.2 Damages Cap. IN NO EVENT SHALL ELASTICSEARCHS OR ITS LICENSORS AGGREGATE, CUMULATIVE LIABILITY UNDER THIS
AGREEMENT EXCEED ONE THOUSAND DOLLARS ($1,000).
4.3 YOU AGREE THAT THE FOREGOING LIMITATIONS, EXCLUSIONS AND DISCLAIMERS ARE A REASONABLE ALLOCATION OF THE RISK BETWEEN
THE PARTIES AND WILL APPLY TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, EVEN IF ANY REMEDY FAILS IN ITS ESSENTIAL
PURPOSE.
5. DEFINITIONS
The following terms have the meanings ascribed:
5.1 “License” means a limited, non-exclusive, non-transferable, fully paid up, right and license (without the right to
grant or authorize sublicenses) solely for Your internal business operations to (i) install and use, in object code
format, the applicable Eligible Features and Functions of the Software, (ii) use, and distribute internally a reasonable
number of copies of the Documentation, provided that You must include on such copies all Marks and Notices; (iii) permit
Contractors to use the Software and Documentation as set forth in (i) and (ii) above, provided that such use must be
solely for Your benefit, and You shall be responsible for all acts and omissions of such Contractors in connection with
their use of the Software that are contrary to the terms and conditions of this Agreement..
5.2 “License Key” means an alphanumeric code that enables the Eligible Features and Functions of the Software.
5.3 “Basic Version” means that version of the Software available for use without the purchase of a Qualifying
Subscription, but which does require Registration.
5.4 “Contractor” means third party contractors performing services on Your behalf.
5.5 “Documentation” means the published end user documentation provided by Elasticsearch with the Software.
5.6 “Eligible Features and Functions” means those features and functions of the Software that are eligible for use with
respect to a particular version of the Software or level of the Subscription. A list of the Eligible Features and
Functions that correspond to each version of the Software and Subscription levels may be found at
https://www.elastic.co/subscriptions.
5.7 “Malicious Code” means any code that is designed to harm, or otherwise disrupt in any unauthorized manner, the
operation of a recipients computer programs or computer systems or destroy or damage recipients data. For clarity,
Malicious Code shall not include any software bugs or errors handled through Support Services, or any standard features
of functions of the Software and/or any License Key that are intended to enforce the temporal and other limitations on
the scope of the use of the Software to the scope of the license purchased by You.
5.8 “Marks and Notices” means all Elasticsearch trademarks, trade names, logos and notices present on the Documentation
as originally provided by Elasticsearch.
5.9 “Registration” means Elasticsearchs then-current process under which You may register Your use of the Software with
Elasticsearch by providing certain information to Elasticsearch regarding your use of the Software.
5.10 “Subscription” means the right to receive Support Services and a License to the Software.
5.11 “Subscription Term” means the period of time for which You have purchased a Subscription.
5.12 “Trial Version” means that version of the Software available for use without the purchase of a Qualifying
Subscription and without Registration.
6. MISCELLANEOUS
This Agreement, including Attachment 1 hereto, which is hereby incorporated herein by this reference, completely and
exclusively states the entire agreement of the parties regarding the subject matter herein, and it supersedes, and its
terms govern, all prior proposals, agreements, or other communications between the parties, oral or written, regarding
such subject matter. For the avoidance of doubt, the parties hereby expressly acknowledge and agree that if You issue
any purchase order or similar document in connection with its purchase of a license to the Software, You will do so only
for Your internal, administrative purposes and not with the intent to provide any contractual terms. This Agreement may
not be modified except by a subsequently dated, written amendment that expressly amends this Agreement and which is
signed on behalf of Elasticsearch and You, by duly authorized representatives. If any provision hereof is held
unenforceable, this Agreement will continue without said provision and be interpreted to reflect the original intent of
the parties.
ATTACHMENT 1
ADDITIONAL TERMS AND CONDITIONS
A. The following additional terms and conditions apply to all Customers with principal offices in the United States
of America:
(1) Applicable Elasticsearch Entity. The entity providing the license is Elasticsearch, Inc., a Delaware corporation.
(2) Government Rights. The Software product is "Commercial Computer Software," as that term is defined in 48 C.F.R.
2.101, and as the term is used in 48 C.F.R. Part 12, and is a Commercial Item comprised of "commercial computer
software" and "commercial computer software documentation". If acquired by or on behalf of a civilian agency, the U.S.
Government acquires this commercial computer software and/or commercial computer software documentation subject to the
terms of this Agreement, as specified in 48 C.F.R. 12.212 (Computer Software) and 12.211 (Technical Data) of the Federal
Acquisition Regulation ("FAR") and its successors. If acquired by or on behalf of any agency within the Department of
Defense ("DOD"), the U.S. Government acquires this commercial computer software and/or commercial computer software
documentation subject to the terms of the Elasticsearch Software License Agreement as specified in 48 C.F.R. 227.7202-3
and 48 C.F.R. 227.7202-4 of the DOD FAR Supplement ("DFARS") and its successors, and consistent with 48 C.F.R. 227.7202.
This U.S. Government Rights clause, consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202 is in lieu of, and
supersedes, any other FAR, DFARS, or other clause or provision that addresses Government rights in computer software,
computer software documentation or technical data related to the Software under this Agreement and in any Subcontract
under which this commercial computer software and commercial computer software documentation is acquired or licensed.
(3) Export Control. You acknowledge that the goods, software and technology acquired from Elasticsearch are subject
to U.S. export control laws and regulations, including but not limited to the International Traffic In Arms Regulations
(“ITAR”) (22 C.F.R. Parts 120-130 (2010)); the Export Administration Regulations ("EAR") (15 C.F.R. Parts 730-774
(2010)); the U.S. antiboycott regulations in the EAR and U.S. Department of the Treasury regulations; the economic
sanctions regulations and guidelines of the U.S. Department of the Treasury, Office of Foreign Assets Control, and the
USA Patriot Act (Title III of Pub. L. 107-56, signed into law October 26, 2001), as amended.  You are now and will
remain in the future compliant with all such export control laws and regulations, and will not export, re-export,
otherwise transfer any Elasticsearch goods, software or technology or disclose any Elasticsearch software or technology
to any person contrary to such laws or regulations.  You acknowledge that remote access to the Software may in certain
circumstances be considered a re-export of Software, and accordingly, may not be granted in contravention of U.S. export
control laws and regulations.
(4) Governing Law, Jurisdiction and Venue.
(a) Customers in California. If Customer is located in California (as determined by the Customer address on the
applicable Order Form, or for a trial license under 1.1(a), the location of person who installed the Software), this
Agreement will be governed by the laws of the State of California, without regard to its conflict of laws principles,
and all suits hereunder will be brought solely in Federal Court for the Northern District of California, or if that
court lacks subject matter jurisdiction, in any California State Court located in Santa Clara County.
(b) Customers Outside of California. If Customer is located anywhere other than California (as determined by the
Customer address on the applicable Order Form, or for a trial license under 1.1(a), the location of person who installed
the Software), this Agreement will be governed by the laws of the State of Delaware, without regard to its conflict of
laws principles, and all suits hereunder will be brought solely in Federal Court for the District of Delaware, or if
that court lacks subject matter jurisdiction, in any Delaware State Court located in Wilmington, Delaware.
(c) All Customers. This Agreement shall not be governed by the 1980 UN Convention on Contracts for the International
Sale of Goods. The parties hereby irrevocably waive any and all claims and defenses either might otherwise have in any
action or proceeding in any of the applicable courts set forth in (a) or (b) above, based upon any alleged lack of
personal jurisdiction, improper venue, forum non conveniens, or any similar claim or defense.
(d) Equitable Relief. A breach or threatened breach, by either party of Section 4 may cause irreparable harm for
which the non-breaching party shall be entitled to seek injunctive relief without being required to post a bond.
B. The following additional terms and conditions apply to all Customers with principal offices in Canada:
(1) Applicable Elasticsearch Entity. The entity providing the license is Elasticsearch B.C. Ltd., a corporation
incorporated under laws of the Province of British Columbia.
(2) Export Control. You acknowledge that the goods, software and technology acquired from Elasticsearch are subject
to the restrictions and controls set out in Section A(3) above as well as those imposed by the Export and Import Permits
Act (Canada) and the regulations thereunder and that you will comply with all applicable laws and regulations. Without
limitation, You acknowledge that the Marvel Software, or any portion thereof, will not be exported: (a) to any country
on Canada's Area Control List; (b) to any country subject to UN Security Council embargo or action; or (c) contrary to
Canada's Export Control List Item 5505. You are now and will remain in the future compliant with all such export control
laws and regulations, and will not export, re-export, otherwise transfer any Elasticsearch goods, software or technology
or disclose any Elasticsearch software or technology to any person contrary to such laws or regulations.  You will not
export or re-export the Marvel Software, or any portion thereof, directly or indirectly, in violation of the Canadian
export administration laws and regulations to any country or end user, or to any end user who you know or have reason to
know will utilize them in the design, development or production of nuclear, chemical or biological weapons. You further
acknowledge that the Marvel Software product may include technical data subject to such Canadian export regulations.
Elasticsearch does not represent that the Marvel Software is appropriate or available for use in all countries.
Elasticsearch prohibits accessing materials from countries or states where contents are illegal. You are using the
Marvel Software on your own initiative and you are responsible for compliance with all applicable laws. You hereby agree
to indemnify Elasticsearch and its affiliates from any claims, actions, liability or expenses (including reasonable
lawyers' fees) resulting from Your failure to act in accordance with the acknowledgements, agreements, and
representations in this Section B(2).
(3) Governing Law and Dispute Resolution. This Agreement shall be governed by the Province of Ontario and the
federal laws of Canada applicable therein without regard to conflict of laws provisions. The parties hereby irrevocably
waive any and all claims and defenses either might otherwise have in any such action or proceeding in any of such courts
based upon any alleged lack of personal jurisdiction, improper venue, forum non conveniens or any similar claim or
defense. Any dispute, claim or controversy arising out of or relating to this Agreement or the existence, breach,
termination, enforcement, interpretation or validity thereof, including the determination of the scope or applicability
of this agreement to arbitrate, (each, a “Dispute”), which the parties are unable to resolve after good faith
negotiations, shall be submitted first to the upper management level of the parties. The parties, through their upper
management level representatives shall meet within thirty (30) days of the Dispute being referred to them and if the
parties are unable to resolve such Dispute within thirty (30) days of meeting, the parties agree to seek to resolve the
Dispute through mediation with ADR Chambers in the City of Toronto, Ontario, Canada before pursuing any other
proceedings. The costs of the mediator shall be shared equally by the parties. If the Dispute has not been resolved
within thirty (30) days of the notice to desire to mediate, any party may terminate the mediation and proceed to
arbitration and the matter shall be referred to and finally resolved by arbitration at ADR Chambers pursuant to the
general ADR Chambers Rules for Arbitration in the City of Toronto, Ontario, Canada. The arbitration shall proceed in
accordance with the provisions of the Arbitration Act (Ontario). The arbitral panel shall consist of three (3)
arbitrators, selected as follows: each party shall appoint one (1) arbitrator; and those two (2) arbitrators shall
discuss and select a chairman. If the two (2) party-appointed arbitrators are unable to agree on the chairman, the
chairman shall be selected in accordance with the applicable rules of the arbitration body. Each arbitrator shall be
independent of each of the parties. The arbitrators shall have the authority to grant specific performance and to
allocate between the parties the costs of arbitration (including service fees, arbitrator fees and all other fees
related to the arbitration) in such equitable manner as the arbitrators may determine. The prevailing party in any
arbitration shall be entitled to receive reimbursement of its reasonable expenses incurred in connection therewith.
Judgment upon the award so rendered may be entered in a court having jurisdiction or application may be made to such
court for judicial acceptance of any award and an order of enforcement, as the case may be. Notwithstanding the
foregoing, Elasticsearch shall have the right to institute an action in a court of proper jurisdiction for preliminary
injunctive relief pending a final decision by the arbitrator, provided that a permanent injunction and damages shall
only be awarded by the arbitrator. The language to be used in the arbitral proceedings shall be English.
(4) Language. Any translation of this Agreement is done for local requirements and in the event of a dispute
between the English and any non-English version, the English version of this Agreement shall govern. At the request of
the parties, the official language of this Agreement and all communications and documents relating hereto is the English
language, and the English-language version shall govern all interpretation of the Agreement.  À la demande des parties,
la langue officielle de la présente convention ainsi que toutes communications et tous documents s'y rapportant est la
langue anglaise, et la version anglaise est celle qui régit toute interprétation de la présente convention.
(5) Warranty Disclaimer. For Customers with principal offices in the Province of Québec, the following new sentence
is to be added to the end of Section 3.3: “SOME JURISDICTIONS DO NOT ALLOW LIMITATIONS OR EXCLUSIONS OF CERTAIN TYPES OF
DAMAGES AND/OR WARRANTIES AND CONDITIONS. THE LIMITATIONS, EXCLUSIONS AND DISCLAIMERS SET FORTH IN THIS AGREEMENT SHALL
NOT APPLY IF AND ONLY IF AND TO THE EXTENT THAT THE LAWS OF A COMPETENT JURISDICTION REQUIRE LIABILITIES BEYOND AND
DESPITE THESE LIMITATIONS, EXCLUSIONS AND DISCLAIMERS.”
(6) Limitation of Liability. For Customers with principal offices in the Province of Québec, the following new
sentence is to be added to the end of Section 4.1: “SOME JURISDICTIONS DO NOT ALLOW LIMITATIONS OR EXCLUSIONS OF CERTAIN
TYPES OF DAMAGES AND/OR WARRANTIES AND CONDITIONS.  THE LIMITATIONS, EXCLUSIONS AND DISCLAIMERS SET FORTH IN THIS
AGREEMENT SHALL NOT APPLY IF AND ONLY IF AND TO THE EXTENT THAT THE LAWS OF A COMPETENT JURISDICTION REQUIRE LIABILITIES
BEYOND AND DESPITE THESE LIMITATIONS, EXCLUSIONS AND DISCLAIMERS.”
C. The following additional terms and conditions apply to all Customers with principal offices outside of the United
States of America and Canada:
(1) Applicable Elasticsearch Entity. The entity providing the license in Germany is Elasticsearch Gmbh; in France is
Elasticsearch SARL, in the United Kingdom is Elasticsearch Ltd, in Australia is Elasticsearch Pty Ltd., in Japan is
Elasticsearch KK, in Sweden is Elasticsearch AB, in Norway is Elasticsearch AS and in all other countries is
Elasticsearch BV.
(2) Choice of Law. This Agreement shall be governed by and construed in accordance with the laws of the State of New
York, without reference to or application of choice of law rules or principles. Notwithstanding any choice of law
provision or otherwise, the Uniform Computer Information Transactions Act (UCITA) and the United Nations Convention on
the International Sale of Goods shall not apply.
(3) Arbitration. Any dispute, claim or controversy arising out of or relating to this Agreement or the existence,
breach, termination, enforcement, interpretation or validity thereof, including the determination of the scope or
applicability of this agreement to arbitrate, (each, a “Dispute”) shall be referred to and finally resolved by
arbitration under the rules and at the location identified below. The arbitral panel shall consist of three (3)
arbitrators, selected as follows: each party shall appoint one (1) arbitrator; and those two (2) arbitrators shall
discuss and select a chairman. If the two party-appointed arbitrators are unable to agree on the chairman, the chairman
shall be selected in accordance with the applicable rules of the arbitration body. Each arbitrator shall be independent
of each of the parties. The arbitrators shall have the authority to grant specific performance and to allocate between
the parties the costs of arbitration (including service fees, arbitrator fees and all other fees related to the
arbitration) in such equitable manner as the arbitrators may determine. The prevailing party in any arbitration shall
be entitled to receive reimbursement of its reasonable expenses incurred in connection therewith. Judgment upon the
award so rendered may be entered in a court having jurisdiction or application may be made to such court for judicial
acceptance of any award and an order of enforcement, as the case may be. Notwithstanding the foregoing, Elasticsearch
shall have the right to institute an action in a court of proper jurisdiction for preliminary injunctive relief pending
a final decision by the arbitrator, provided that a permanent injunction and damages shall only be awarded by the
arbitrator. The language to be used in the arbitral proceedings shall be English.
In addition, the following terms only apply to Customers with principal offices within Europe, the Middle East or Africa
(EMEA):
Arbitration Rules and Location. Any Dispute shall be referred to and finally resolved by arbitration under the London
Court of International Arbitration (“LCIA”) Rules (which Rules are deemed to be incorporated by reference into this
clause) on the basis that the governing law is the law of the State of New York, USA. The seat, or legal place, of
arbitration shall be London, England.
(b) In addition, the following terms only apply to Customers with principal offices within Asia Pacific, Australia &
New Zealand:
Arbitration Rules and Location. Any Dispute shall be referred to and finally resolved by arbitration under the Rules of
Conciliation and Arbitration of the International Chamber of Commerce (“ICC”) in force on the date when the notice of
arbitration is submitted in accordance with such Rules (which Rules are deemed to be incorporated by reference into this
clause) on the basis that the governing law is the law of the State of New York, USA. The seat, or legal place, of
arbitration shall be Singapore.
(c) In addition, the following terms only apply to Customers with principal offices within the Americas (excluding
North America):
Arbitration Rules and Location. Any Dispute shall be referred to and finally resolved by arbitration under
International Dispute Resolution Procedures of the American Arbitration Association (“AAA”) in force on the date when
the notice of arbitration is submitted in accordance with such Procedures (which Procedures are deemed to be
incorporated by reference into this clause) on the basis that the governing law is the law of the State of New York,
USA. The seat, or legal place, of arbitration shall be New York, New York, USA.
(4) In addition, for Customers with principal offices within the UK, the following new sentence is added to the end
of Section 4.1:
Nothing in this Agreement shall have effect so as to limit or exclude a partys liability for death or personal injury
caused by negligence or for fraud including fraudulent misrepresentation and this Section 4.1 shall take effect subject
to this provision.
(5) In addition, for Customers with principal offices within France, Sections 1.2, 3 and 4.1 of the Agreement are
deleted and replaced with the following new Sections 1.2, 3.3 and 4.1:
1.2 Reservation of Rights; Restrictions. Elasticsearch owns all right title and interest in and to the Software and
any derivative works thereof, and except as expressly set forth in Section 1.1 above, no other license to the Software
is granted to You by implication, or otherwise. You agree not to prepare derivative works from, modify, copy or use the
Software in any manner except as expressly permitted in this Agreement; provided that You may copy the Software for
archival purposes, only where such software is provided on a non-durable medium; and You may decompile the Software,
where necessary for interoperability purposes and where necessary for the correction of errors making the software unfit
for its intended purpose, if such right is not reserved by Elasticsearch as editor of the Software. Pursuant to article
L122-6-1 of the French intellectual property code, Elasticsearch reserves the right to correct any bugs as necessary for
the Software to serve its intended purpose. You agree not to: (i) transfer, sell, rent, lease, distribute, sublicense,
loan or otherwise transfer the Software in whole or in part to any third party; (ii) use the Software for providing
time-sharing services, any software-as-a-service offering (“SaaS”), service bureau services or as part of an application
services provider or other service offering; (iii) alter or remove any proprietary notices in the Software; or (iv) make
available to any third party any analysis of the results of operation of the Software, including benchmarking results,
without the prior written consent of Elasticsearch.
3.3 Warranty Disclaimer. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW, THE SOFTWARE IS PROVIDED “AS IS”
WITHOUT WARRANTY OF ANY KIND, AND ELASTICSEARCH AND ITS LICENSORS MAKE NO WARRANTIES WHETHER EXPRESSED, IMPLIED OR
STATUTORY REGARDING OR RELATING TO THE SOFTWARE OR DOCUMENTATION. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW,
ELASTICSEARCH AND ITS LICENSORS SPECIFICALLY DISCLAIM ALL IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE WITH
RESPECT TO THE SOFTWARE AND DOCUMENTATION, AND WITH RESPECT TO THE USE OF THE FOREGOING. FURTHER, ELASTICSEARCH DOES
NOT WARRANT RESULTS OF USE OR THAT THE SOFTWARE WILL BE ERROR FREE OR THAT THE USE OF THE SOFTWARE WILL BE
UNINTERRUPTED.
4.1 Disclaimer of Certain Damages. IN NO EVENT SHALL YOU OR ELASTICSEARCH OR ITS LICENSORS BE LIABLE FOR ANY LOSS OF
PROFITS, LOSS OF USE, BUSINESS INTERRUPTION, LOSS OF DATA, COST OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT OR
UNFORESEEABLE DAMAGES OF ANY KIND IN CONNECTION WITH OR ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE, OR THE
PERFORMANCE OF OR FAILURE TO PERFORM THIS AGREEMENT, WHETHER ALLEGED AS A BREACH OF CONTRACT OR TORTIOUS CONDUCT,
INCLUDING NEGLIGENCE. THE LIMITATIONS OF LIABILITY SET FORTH IN THIS SECTION 4.1 SHALL NOT APPLY TO A BREACH, THROUGH
GROSS NEGLIGENCE OR INTENTIONAL MISCONDUCT BY YOU, OF THE SCOPE OF THE LICENSE GRANTED IN SECTION 1.1, OR IN CASE OF
DEATH OR PERSONAL INJURY.
(6) In addition, for Customers with principal offices within Australia, Sections 4.1, 4.2 and 4.3 of the Agreement
are deleted and replaced with the following new Sections 4.1, 4.2 and 4.3:
4.1 Disclaimer of Certain Damages. Subject to clause 4.3, a party is not liable for Consequential Loss however
caused (including by the negligence of that party) suffered or incurred by the other party in connection with this
agreement. “Consequential Loss” means loss of revenues, loss of reputation, indirect loss, loss of profits,
consequential loss, loss of actual or anticipated savings, indirect loss, lost opportunities, including opportunities to
enter into arrangements with third parties, loss or damage in connection with claims against by third parties, or loss
or corruption or data.
4.2 Damages Cap. SUBJECT TO CLAUSES 4.1 AND 4.3, ANY LIABILITY OF ELASTICSEARCH FOR ANY LOSS OR DAMAGE, HOWEVER
CAUSED (INCLUDING BY THE NEGLIGENCE OF ELASTICSEARCH), SUFFERED BY YOU IN CONNECTION WITH THIS AGREEMENT IS LIMITED TO
THE AMOUNT YOU PAID, IN THE TWELVE (12) MONTHS IMMEDIATELY PRIOR TO THE EVENT GIVING RISE TO LIABILITY, UNDER THE
ELASTICSEARCH SUPPORT SERVICES AGREEMENT IN CONNECTION WITH WHICH YOU OBTAINED THE LICENSE TO USE THE SOFTWARE. THE
LIMITATION SET OUT IN THIS SECTION 4.2 IS AN AGGREGATE LIMIT FOR ALL CLAIMS, WHENEVER MADE.
4.3 Limitation and Disclaimer Exceptions. If the Competition and Consumer Act 2010 (Cth) or any other legislation or
any other legislation states that there is a guarantee in relation to any good or service supplied by Elasticsearch in
connection with this agreement, and Elasticsearchs liability for failing to comply with that guarantee cannot be
excluded but may be limited, Sections 4.1 and 4.2 do not apply to that liability and instead Elasticsearchs liability
for such failure is limited (at Elasticsearchs election) to, in the case of a supply of goods, the Elasticsearch
replacing the goods or supplying equivalent goods or repairing the goods, or in the case of a supply of services,
Elasticsearch supplying the services again or paying the cost of having the services supplied again.
(7) In addition, for Customers with principal offices within Japan, Sections 1.2, 3 and 4.1 of the Agreement are
deleted and replaced with the following new Sections 1.2, 3.3 and 4.1:
1.2 Reservation of Rights; Restrictions. As between Elasticsearch and You, Elasticsearch owns all right title and
interest in and to the Software and any derivative works thereof, and except as expressly set forth in Section 1.1
above, no other license to the Software is granted to You by implication or otherwise. You agree not to: (i) prepare
derivative works from, modify, copy or use the Software in any manner except as expressly permitted in this Agreement or
applicable law; (ii) transfer, sell, rent, lease, distribute, sublicense, loan or otherwise transfer the Software in
whole or in part to any third party; (iii) use the Software for providing time-sharing services, any
software-as-a-service offering (“SaaS”), service bureau services or as part of an application services provider or other
service offering; (iv) alter or remove any proprietary notices in the Software; or (v) make available to any third party
any analysis of the results of operation of the Software, including benchmarking results, without the prior written
consent of Elasticsearch.
3.3 Warranty Disclaimer. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW, THE SOFTWARE IS PROVIDED “AS IS”
WITHOUT WARRANTY OF ANY KIND, AND ELASTICSEARCH AND ITS LICENSORS MAKE NO WARRANTIES WHETHER EXPRESSED, IMPLIED OR
STATUTORY REGARDING OR RELATING TO THE SOFTWARE OR DOCUMENTATION. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW,
ELASTICSEARCH AND ITS LICENSORS SPECIFICALLY DISCLAIM ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NON-INFRINGEMENT WITH RESPECT TO THE SOFTWARE AND DOCUMENTATION, AND WITH RESPECT TO THE USE OF
THE FOREGOING. FURTHER, ELASTICSEARCH DOES NOT WARRANT RESULTS OF USE OR THAT THE SOFTWARE WILL BE ERROR FREE OR THAT
THE USE OF THE SOFTWARE WILL BE UNINTERRUPTED.
4.1 Disclaimer of Certain Damages. IN NO EVENT SHALL YOU OR ELASTICSEARCH OR ITS LICENSORS BE LIABLE FOR ANY LOSS OF
PROFITS, LOSS OF USE, BUSINESS INTERRUPTION, LOSS OF DATA, COST OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY
SPECIALINDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND IN CONNECTION WITH OR ARISING OUT OF THE USE
OR INABILITY TO USE THE SOFTWARE, OR THE PERFORMANCE OF OR FAILURE TO PERFORM THIS AGREEMENT, WHETHER ALLEGED AS A
BREACH OF CONTRACT OR TORTIOUS CONDUCT, INCLUDING NEGLIGENCE, EVEN IF THE RESPONSIBLE PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES. THE LIMITATIONS OF LIABILITY SET FORTH IN THIS SECTION 4.1 SHALL NOT APPLY TO A BREACH
THROUGH GROSS NEGLIGENCE OR INTENTIONAL MISCONDUCT BY YOU OF THE SCOPE OF THE LICENSE GRANTED IN SECTION 1.1 OR TO ANY
OTHER LIABILITY THAT CANNOT BE EXCLUDED OR LIMITED UNDER APPLICABLE LAW.

View File

@ -1,6 +1,5 @@
import org.elasticsearch.gradle.MavenFilteringHack import org.elasticsearch.gradle.MavenFilteringHack
import org.elasticsearch.gradle.test.NodeInfo import org.elasticsearch.gradle.test.NodeInfo
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
group 'org.elasticsearch.plugin' group 'org.elasticsearch.plugin'
@ -27,12 +26,9 @@ licenseHeaders {
} }
dependencies { dependencies {
// license deps
compile project(':x-plugins:elasticsearch:license:base')
testCompile project(':x-plugins:elasticsearch:license:licensor')
// security deps // security deps
compile project(path: ':modules:transport-netty3', configuration: 'runtime') compile project(path: ':modules:transport-netty3', configuration: 'runtime')
compile project(path: ':modules:transport-netty4', configuration: 'runtime')
compile 'dk.brics.automaton:automaton:1.11-8' compile 'dk.brics.automaton:automaton:1.11-8'
compile 'com.unboundid:unboundid-ldapsdk:3.1.1' compile 'com.unboundid:unboundid-ldapsdk:3.1.1'
compile 'org.bouncycastle:bcprov-jdk15on:1.54' compile 'org.bouncycastle:bcprov-jdk15on:1.54'
@ -78,6 +74,11 @@ for (String module : ['', 'license-plugin/', 'security/', 'watcher/', 'monitorin
} }
} }
// make LicenseSigner available for testing signed licenses
sourceSets.test.java {
srcDir '../license-tools/src/main/java'
}
compileJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes,-serial,-try,-unchecked" compileJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes,-serial,-try,-unchecked"
compileTestJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes,-serial,-try,-unchecked" compileTestJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes,-serial,-try,-unchecked"
@ -117,8 +118,10 @@ forbiddenPatterns {
// TODO: standardize packaging config for plugins // TODO: standardize packaging config for plugins
bundlePlugin { bundlePlugin {
from(projectDir) { from(project(':x-plugins').projectDir) {
include 'LICENSE.txt' include 'LICENSE.txt'
}
from(projectDir) {
include 'NOTICE.txt' include 'NOTICE.txt'
} }
from('bin/x-pack') { from('bin/x-pack') {
@ -236,29 +239,3 @@ thirdPartyAudit.excludes = [
'javax.activation.URLDataSource', 'javax.activation.URLDataSource',
'javax.activation.UnsupportedDataTypeException' 'javax.activation.UnsupportedDataTypeException'
] ]
modifyPom { MavenPom pom ->
pom.withXml { XmlProvider xml ->
// first find if we have dependencies at all, and grab the node
NodeList depsNodes = xml.asNode().get('dependencies')
if (depsNodes.isEmpty()) {
return
}
// find the 'base' dependency and replace it with the correct name because the project name is
// always used even when the pom of the other project is correct
Iterator<Node> childNodeIter = depsNodes.get(0).children().iterator()
while (childNodeIter.hasNext()) {
Node depNode = childNodeIter.next()
String groupId = depNode.get('groupId').get(0).text()
Node artifactIdNode = depNode.get('artifactId').get(0)
String artifactId = artifactIdNode.text()
String scope = depNode.get("scope").get(0).text()
if (groupId.equals('org.elasticsearch') && artifactId.equals('base')) {
artifactIdNode.replaceNode(new Node(null, 'artifactId', 'license-core'))
} else if ('test'.equals(scope)) {
childNodeIter.remove()
}
}
}
}

View File

@ -5,16 +5,15 @@
*/ */
package org.elasticsearch.xpack.graph; package org.elasticsearch.xpack.graph;
import java.io.IOException;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.xpack.XPackFeatureSet; import org.elasticsearch.xpack.XPackFeatureSet;
import java.io.IOException;
/** /**
* *
*/ */
@ -24,10 +23,9 @@ public class GraphFeatureSet implements XPackFeatureSet {
private final XPackLicenseState licenseState; private final XPackLicenseState licenseState;
@Inject @Inject
public GraphFeatureSet(Settings settings, @Nullable XPackLicenseState licenseState, NamedWriteableRegistry namedWriteableRegistry) { public GraphFeatureSet(Settings settings, @Nullable XPackLicenseState licenseState) {
this.enabled = Graph.enabled(settings); this.enabled = Graph.enabled(settings);
this.licenseState = licenseState; this.licenseState = licenseState;
namedWriteableRegistry.register(Usage.class, Usage.writeableName(Graph.NAME), Usage::new);
} }
@Override @Override
@ -55,7 +53,7 @@ public class GraphFeatureSet implements XPackFeatureSet {
return new Usage(available(), enabled()); return new Usage(available(), enabled());
} }
static class Usage extends XPackFeatureSet.Usage { public static class Usage extends XPackFeatureSet.Usage {
public Usage(StreamInput input) throws IOException { public Usage(StreamInput input) throws IOException {
super(input); super(input);

View File

@ -16,7 +16,6 @@ import java.util.Map;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
@ -27,23 +26,24 @@ import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.indices.query.IndicesQueriesRegistry; import org.elasticsearch.indices.query.IndicesQueriesRegistry;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestChannel; import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.action.support.RestActions; import org.elasticsearch.rest.action.support.RestActions;
import org.elasticsearch.rest.action.support.RestToXContentListener; import org.elasticsearch.rest.action.support.RestToXContentListener;
import org.elasticsearch.xpack.XPackClient;
import org.elasticsearch.xpack.graph.action.GraphExploreRequest; import org.elasticsearch.xpack.graph.action.GraphExploreRequest;
import org.elasticsearch.xpack.graph.action.GraphExploreResponse; import org.elasticsearch.xpack.graph.action.GraphExploreResponse;
import org.elasticsearch.xpack.graph.action.Hop; import org.elasticsearch.xpack.graph.action.Hop;
import org.elasticsearch.xpack.graph.action.VertexRequest; import org.elasticsearch.xpack.graph.action.VertexRequest;
import org.elasticsearch.xpack.graph.action.GraphExploreRequest.TermBoost; import org.elasticsearch.xpack.graph.action.GraphExploreRequest.TermBoost;
import org.elasticsearch.xpack.rest.XPackRestHandler;
/** /**
* @see GraphExploreRequest * @see GraphExploreRequest
*/ */
public class RestGraphAction extends BaseRestHandler { public class RestGraphAction extends XPackRestHandler {
private IndicesQueriesRegistry indicesQueriesRegistry; private IndicesQueriesRegistry indicesQueriesRegistry;
public static final ParseField TIMEOUT_FIELD = new ParseField("timeout"); public static final ParseField TIMEOUT_FIELD = new ParseField("timeout");
@ -68,21 +68,23 @@ public class RestGraphAction extends BaseRestHandler {
@Inject @Inject
public RestGraphAction(Settings settings, RestController controller, IndicesQueriesRegistry indicesQueriesRegistry) { public RestGraphAction(Settings settings, RestController controller, IndicesQueriesRegistry indicesQueriesRegistry) {
super(settings); super(settings);
// @deprecated TODO need to add deprecation support as per https://github.com/elastic/x-plugins/issues/1760#issuecomment-217507517
controller.registerHandler(GET, "/{index}/_graph/explore", this);
controller.registerHandler(POST, "/{index}/_graph/explore", this);
controller.registerHandler(GET, "/{index}/{type}/_graph/explore", this);
controller.registerHandler(POST, "/{index}/{type}/_graph/explore", this);
// new REST endpoint
controller.registerHandler(GET, "/{index}/_xpack/graph/_explore", this);
controller.registerHandler(POST, "/{index}/_xpack/graph/_explore", this);
controller.registerHandler(GET, "/{index}/{type}/_xpack/graph/_explore", this);
controller.registerHandler(POST, "/{index}/{type}/_xpack/graph/_explore", this);
this.indicesQueriesRegistry = indicesQueriesRegistry; this.indicesQueriesRegistry = indicesQueriesRegistry;
// @deprecated Remove in 6.0
// NOTE: Old versions did not end with "/_explore"; they were just "/explore"
controller.registerWithDeprecatedHandler(GET, "/{index}" + URI_BASE + "/_graph/_explore", this,
GET, "/{index}/_graph/explore", deprecationLogger);
controller.registerWithDeprecatedHandler(POST, "/{index}" + URI_BASE + "/_graph/_explore", this,
POST, "/{index}/_graph/explore", deprecationLogger);
controller.registerWithDeprecatedHandler(GET, "/{index}/{type}" + URI_BASE + "/_graph/_explore", this,
GET, "/{index}/{type}/_graph/explore", deprecationLogger);
controller.registerWithDeprecatedHandler(POST, "/{index}/{type}" + URI_BASE + "/_graph/_explore", this,
POST, "/{index}/{type}/_graph/explore", deprecationLogger);
} }
@Override @Override
public void handleRequest(final RestRequest request, final RestChannel channel, final NodeClient client) throws IOException { public void handleRequest(final RestRequest request, final RestChannel channel, final XPackClient client) throws IOException {
GraphExploreRequest graphRequest = new GraphExploreRequest(Strings.splitStringByCommaToArray(request.param("index"))); GraphExploreRequest graphRequest = new GraphExploreRequest(Strings.splitStringByCommaToArray(request.param("index")));
graphRequest.indicesOptions(IndicesOptions.fromRequest(request, graphRequest.indicesOptions())); graphRequest.indicesOptions(IndicesOptions.fromRequest(request, graphRequest.indicesOptions()));
graphRequest.routing(request.param("routing")); graphRequest.routing(request.param("routing"));
@ -109,7 +111,7 @@ public class RestGraphAction extends BaseRestHandler {
} }
graphRequest.types(Strings.splitStringByCommaToArray(request.param("type"))); graphRequest.types(Strings.splitStringByCommaToArray(request.param("type")));
client.execute(INSTANCE, graphRequest, new RestToXContentListener<GraphExploreResponse>(channel)); client.es().execute(INSTANCE, graphRequest, new RestToXContentListener<GraphExploreResponse>(channel));
} }
private void parseHop(XContentParser parser, QueryParseContext context, Hop currentHop, private void parseHop(XContentParser parser, QueryParseContext context, Hop currentHop,

View File

@ -5,17 +5,13 @@
*/ */
package org.elasticsearch.xpack.graph; package org.elasticsearch.xpack.graph;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.junit.Before; import org.junit.Before;
import static org.hamcrest.core.Is.is; import static org.hamcrest.core.Is.is;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
/** /**
@ -24,21 +20,14 @@ import static org.mockito.Mockito.when;
public class GraphFeatureSetTests extends ESTestCase { public class GraphFeatureSetTests extends ESTestCase {
private XPackLicenseState licenseState; private XPackLicenseState licenseState;
private NamedWriteableRegistry namedWriteableRegistry;
@Before @Before
public void init() throws Exception { public void init() throws Exception {
licenseState = mock(XPackLicenseState.class); licenseState = mock(XPackLicenseState.class);
namedWriteableRegistry = mock(NamedWriteableRegistry.class);
}
public void testWritableRegistration() throws Exception {
new GraphFeatureSet(Settings.EMPTY, licenseState, namedWriteableRegistry);
verify(namedWriteableRegistry).register(eq(GraphFeatureSet.Usage.class), eq("xpack.usage.graph"), anyObject());
} }
public void testAvailable() throws Exception { public void testAvailable() throws Exception {
GraphFeatureSet featureSet = new GraphFeatureSet(Settings.EMPTY, licenseState, namedWriteableRegistry); GraphFeatureSet featureSet = new GraphFeatureSet(Settings.EMPTY, licenseState);
boolean available = randomBoolean(); boolean available = randomBoolean();
when(licenseState.isGraphAllowed()).thenReturn(available); when(licenseState.isGraphAllowed()).thenReturn(available);
assertThat(featureSet.available(), is(available)); assertThat(featureSet.available(), is(available));
@ -54,7 +43,7 @@ public class GraphFeatureSetTests extends ESTestCase {
} else { } else {
settings.put("xpack.graph.enabled", enabled); settings.put("xpack.graph.enabled", enabled);
} }
GraphFeatureSet featureSet = new GraphFeatureSet(settings.build(), licenseState, namedWriteableRegistry); GraphFeatureSet featureSet = new GraphFeatureSet(settings.build(), licenseState);
assertThat(featureSet.enabled(), is(enabled)); assertThat(featureSet.enabled(), is(enabled));
} }

View File

@ -3,8 +3,8 @@
"documentation": "https://www.elastic.co/guide/en/graph/current/explore.html", "documentation": "https://www.elastic.co/guide/en/graph/current/explore.html",
"methods": ["GET", "POST"], "methods": ["GET", "POST"],
"url": { "url": {
"path": "/{index}/_xpack/graph/_explore", "path": "/{index}/_xpack/_graph/_explore",
"paths": ["/{index}/_xpack/graph/_explore", "/{index}/{type}/_xpack/graph/_explore"], "paths": ["/{index}/_xpack/_graph/_explore", "/{index}/{type}/_xpack/_graph/_explore"],
"parts" : { "parts" : {
"index": { "index": {
"type" : "list", "type" : "list",

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.core; package org.elasticsearch.license;
import javax.crypto.BadPaddingException; import javax.crypto.BadPaddingException;

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.core; package org.elasticsearch.license;
import org.elasticsearch.common.joda.FormatDateTimeFormatter; import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.joda.Joda; import org.elasticsearch.common.joda.Joda;

View File

@ -7,7 +7,6 @@ package org.elasticsearch.license;
import org.elasticsearch.common.logging.LoggerMessageFormat; import org.elasticsearch.common.logging.LoggerMessageFormat;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.License;
import org.elasticsearch.xpack.scheduler.SchedulerEngine; import org.elasticsearch.xpack.scheduler.SchedulerEngine;
import java.util.UUID; import java.util.UUID;

View File

@ -8,7 +8,6 @@ package org.elasticsearch.license;
import org.elasticsearch.action.ActionResponse; import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.license.core.License;
import java.io.IOException; import java.io.IOException;

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.core; package org.elasticsearch.license;
import org.apache.lucene.util.CollectionUtil; import org.apache.lucene.util.CollectionUtil;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;

View File

@ -25,9 +25,6 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.gateway.GatewayService; import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.core.LicenseVerifier;
import org.elasticsearch.license.core.OperationModeFileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.scheduler.SchedulerEngine; import org.elasticsearch.xpack.scheduler.SchedulerEngine;

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.core; package org.elasticsearch.license;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BytesRefIterator; import org.apache.lucene.util.BytesRefIterator;

View File

@ -5,29 +5,15 @@
*/ */
package org.elasticsearch.license; package org.elasticsearch.license;
import org.apache.lucene.util.CollectionUtil;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.AbstractDiffable; import org.elasticsearch.cluster.AbstractDiffable;
import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.license.core.License;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List;
import static org.elasticsearch.license.core.CryptUtils.decrypt;
import static org.elasticsearch.license.core.CryptUtils.encrypt;
/** /**
* Contains metadata about registered licenses * Contains metadata about registered licenses
@ -101,34 +87,13 @@ class LicensesMetaData extends AbstractDiffable<MetaData.Custom> implements Meta
@Override @Override
public LicensesMetaData fromXContent(XContentParser parser) throws IOException { public LicensesMetaData fromXContent(XContentParser parser) throws IOException {
List<License> pre20Licenses = new ArrayList<>(1);
License license = LICENSE_TOMBSTONE; License license = LICENSE_TOMBSTONE;
XContentParser.Token token; XContentParser.Token token;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) { if (token == XContentParser.Token.FIELD_NAME) {
String fieldName = parser.currentName(); String fieldName = parser.currentName();
if (fieldName != null) { if (fieldName != null) {
// for back compat with 1.x license metadata if (fieldName.equals(Fields.LICENSE)) {
if (fieldName.equals(Fields.TRIAL_LICENSES) || fieldName.equals(Fields.SIGNED_LICENCES)) {
token = parser.nextToken();
if (token == XContentParser.Token.START_ARRAY) {
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
if (parser.currentToken().isValue()) {
// trial license
byte[] data = decrypt(Base64.getDecoder().decode(parser.text()));
try (XContentParser trialLicenseParser =
XContentFactory.xContent(XContentType.JSON).createParser(data)) {
trialLicenseParser.nextToken();
License pre20TrialLicense = License.fromXContent(trialLicenseParser);
pre20Licenses.add(TrialLicense.create(License.builder().fromPre20LicenseSpec(pre20TrialLicense)));
}
} else {
// signed license
pre20Licenses.add(License.fromXContent(parser));
}
}
}
} else if (fieldName.equals(Fields.LICENSE)) {
token = parser.nextToken(); token = parser.nextToken();
if (token == XContentParser.Token.START_OBJECT) { if (token == XContentParser.Token.START_OBJECT) {
license = License.fromXContent(parser); license = License.fromXContent(parser);
@ -139,23 +104,6 @@ class LicensesMetaData extends AbstractDiffable<MetaData.Custom> implements Meta
} }
} }
} }
// when we see old license metadata,
// we try to choose the license that has the latest issue date that is not expired
if (!pre20Licenses.isEmpty()) {
// take the best unexpired license
CollectionUtil.timSort(pre20Licenses, License.LATEST_ISSUE_DATE_FIRST);
long now = System.currentTimeMillis();
for (License oldLicense : pre20Licenses) {
if (oldLicense.expiryDate() > now) {
license = oldLicense;
break;
}
}
// take the best expired license
if (license == LICENSE_TOMBSTONE && !pre20Licenses.isEmpty()) {
license = pre20Licenses.get(0);
}
}
return new LicensesMetaData(license); return new LicensesMetaData(license);
} }
@ -173,23 +121,6 @@ class LicensesMetaData extends AbstractDiffable<MetaData.Custom> implements Meta
@Override @Override
public void writeTo(StreamOutput streamOutput) throws IOException { public void writeTo(StreamOutput streamOutput) throws IOException {
if (streamOutput.getVersion().before(Version.V_2_0_0)) {
if (license == LICENSE_TOMBSTONE) {
streamOutput.writeVInt(0); // no signed license
streamOutput.writeVInt(0); // no trial license
} else if (!License.isAutoGeneratedLicense(license.signature())) {
streamOutput.writeVInt(1); // one signed license
license.writeTo(streamOutput);
streamOutput.writeVInt(0); // no trial license
} else {
streamOutput.writeVInt(0); // no signed license
streamOutput.writeVInt(1); // one trial license
XContentBuilder contentBuilder = XContentFactory.contentBuilder(XContentType.JSON);
license.toXContent(contentBuilder,
new ToXContent.MapParams(Collections.singletonMap(License.LICENSE_SPEC_VIEW_MODE, "true")));
streamOutput.writeString(Base64.getEncoder().encodeToString(encrypt(BytesReference.toBytes(contentBuilder.bytes()))));
}
} else {
if (license == LICENSE_TOMBSTONE) { if (license == LICENSE_TOMBSTONE) {
streamOutput.writeBoolean(false); // no license streamOutput.writeBoolean(false); // no license
} else { } else {
@ -197,51 +128,17 @@ class LicensesMetaData extends AbstractDiffable<MetaData.Custom> implements Meta
license.writeTo(streamOutput); license.writeTo(streamOutput);
} }
} }
}
@Override @Override
public LicensesMetaData readFrom(StreamInput streamInput) throws IOException { public LicensesMetaData readFrom(StreamInput streamInput) throws IOException {
License license = LICENSE_TOMBSTONE; License license = LICENSE_TOMBSTONE;
if (streamInput.getVersion().before(Version.V_2_0_0)) {
int size = streamInput.readVInt();
List<License> licenses = new ArrayList<>();
for (int i = 0; i < size; i++) {
licenses.add(License.readLicense(streamInput));
}
int numTrialLicenses = streamInput.readVInt();
for (int i = 0; i < numTrialLicenses; i++) {
byte[] data = decrypt(Base64.getDecoder().decode(streamInput.readString()));
try (XContentParser trialLicenseParser = XContentFactory.xContent(XContentType.JSON).createParser(data)) {
trialLicenseParser.nextToken();
License pre20TrialLicense = License.fromXContent(trialLicenseParser);
licenses.add(TrialLicense.create(License.builder().fromPre20LicenseSpec(pre20TrialLicense)));
}
}
// when we see read licenses from old pre v2.0,
// we try to choose the license that has the latest issue date that is not expired
CollectionUtil.timSort(licenses, License.LATEST_ISSUE_DATE_FIRST);
long now = System.currentTimeMillis();
for (License oldLicense : licenses) {
if (oldLicense.expiryDate() > now) {
license = oldLicense;
break;
}
}
// take the best expired license
if (license == LICENSE_TOMBSTONE && !licenses.isEmpty()) {
license = licenses.get(0);
}
} else {
if (streamInput.readBoolean()) { if (streamInput.readBoolean()) {
license = License.readLicense(streamInput); license = License.readLicense(streamInput);
} }
}
return new LicensesMetaData(license); return new LicensesMetaData(license);
} }
private static final class Fields { private static final class Fields {
private static final String SIGNED_LICENCES = "signed_licenses";
private static final String TRIAL_LICENSES = "trial_licenses";
private static final String LICENSE = "license"; private static final String LICENSE = "license";
} }
} }

View File

@ -45,10 +45,6 @@ public class Licensing implements ActionPlugin {
isTribeNode = isTribeNode(settings); isTribeNode = isTribeNode(settings);
} }
public Collection<Module> nodeModules() {
return Collections.emptyList();
}
@Override @Override
public List<ActionHandler<? extends ActionRequest<?>, ? extends ActionResponse>> getActions() { public List<ActionHandler<? extends ActionRequest<?>, ? extends ActionResponse>> getActions() {
if (isTribeNode) { if (isTribeNode) {
@ -69,14 +65,6 @@ public class Licensing implements ActionPlugin {
RestDeleteLicenseAction.class); RestDeleteLicenseAction.class);
} }
public Collection<Object> createComponents(ClusterService clusterService, Clock clock, Environment environment,
ResourceWatcherService resourceWatcherService,
XPackLicenseState licenseState) {
LicenseService licenseService = new LicenseService(settings, clusterService, clock,
environment, resourceWatcherService, licenseState);
return Arrays.asList(licenseService, licenseState);
}
public List<Setting<?>> getSettings() { public List<Setting<?>> getSettings() {
// TODO convert this wildcard to a real setting // TODO convert this wildcard to a real setting
return Collections.singletonList(Setting.groupSetting("license.", Setting.Property.NodeScope)); return Collections.singletonList(Setting.groupSetting("license.", Setting.Property.NodeScope));

View File

@ -7,7 +7,6 @@ package org.elasticsearch.license;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
import org.elasticsearch.client.ElasticsearchClient; import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.license.core.License;
/** /**
* *

View File

@ -3,11 +3,11 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.core; package org.elasticsearch.license;
import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.license.core.License.OperationMode; import org.elasticsearch.license.License.OperationMode;
import org.elasticsearch.watcher.FileChangesListener; import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher; import org.elasticsearch.watcher.FileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.watcher.ResourceWatcherService;
@ -26,7 +26,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* In case of failure to read a valid operation mode from <code>licenseModePath</code>, * In case of failure to read a valid operation mode from <code>licenseModePath</code>,
* the operation mode will default to PLATINUM * the operation mode will default to PLATINUM
*/ */
public final class OperationModeFileWatcher extends FileChangesListener { public final class OperationModeFileWatcher implements FileChangesListener {
private final ResourceWatcherService resourceWatcherService; private final ResourceWatcherService resourceWatcherService;
private final Path licenseModePath; private final Path licenseModePath;
private final AtomicBoolean initialized = new AtomicBoolean(); private final AtomicBoolean initialized = new AtomicBoolean();

View File

@ -10,7 +10,6 @@ import org.elasticsearch.action.ValidateActions;
import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.action.support.master.AcknowledgedRequest;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.license.core.License;
import java.io.IOException; import java.io.IOException;
@ -29,7 +28,7 @@ public class PutLicenseRequest extends AcknowledgedRequest<PutLicenseRequest> {
} }
/** /**
* Parses license from json format to an instance of {@link org.elasticsearch.license.core.License} * Parses license from json format to an instance of {@link License}
* *
* @param licenseDefinition licenses definition * @param licenseDefinition licenses definition
*/ */

View File

@ -7,7 +7,6 @@ package org.elasticsearch.license;
import org.elasticsearch.action.support.master.AcknowledgedRequestBuilder; import org.elasticsearch.action.support.master.AcknowledgedRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient; import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.license.core.License;
/** /**
* Register license request builder * Register license request builder

View File

@ -9,7 +9,6 @@ import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.license.core.License;
import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.BytesRestResponse;
import org.elasticsearch.rest.RestChannel; import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestController;

View File

@ -11,15 +11,14 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.license.core.License;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Base64; import java.util.Base64;
import java.util.Collections; import java.util.Collections;
import static org.elasticsearch.license.core.CryptUtils.decrypt; import static org.elasticsearch.license.CryptUtils.decrypt;
import static org.elasticsearch.license.core.CryptUtils.encrypt; import static org.elasticsearch.license.CryptUtils.encrypt;
class TrialLicense { class TrialLicense {

View File

@ -7,7 +7,7 @@
/** /**
* Licensing for xpack. * Licensing for xpack.
* *
* A {@link org.elasticsearch.license.core.License} is a signed set of json properties that determine what features * A {@link org.elasticsearch.license.License} is a signed set of json properties that determine what features
* are available in a running cluster. Licenses are registered through a * are available in a running cluster. Licenses are registered through a
* {@link org.elasticsearch.license.PutLicenseRequest}. This action is handled by the master node, which places * {@link org.elasticsearch.license.PutLicenseRequest}. This action is handled by the master node, which places
* the signed license into the cluster state. Each node listens for cluster state updates via the * the signed license into the cluster state. Each node listens for cluster state updates via the

View File

@ -17,7 +17,6 @@ import org.elasticsearch.common.component.Lifecycle;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.LocalTransportAddress; import org.elasticsearch.common.transport.LocalTransportAddress;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.license.core.License;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.support.clock.ClockMock; import org.elasticsearch.xpack.support.clock.ClockMock;

View File

@ -11,8 +11,6 @@ import org.elasticsearch.cluster.ClusterStateUpdateTask;
import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.LicensesMetaData;
import org.elasticsearch.xpack.monitoring.Monitoring; import org.elasticsearch.xpack.monitoring.Monitoring;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.Security;

View File

@ -6,7 +6,6 @@
package org.elasticsearch.license; package org.elasticsearch.license;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.License;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import static org.elasticsearch.common.unit.TimeValue.timeValueMillis; import static org.elasticsearch.common.unit.TimeValue.timeValueMillis;

View File

@ -15,7 +15,6 @@ import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.common.transport.LocalTransportAddress; import org.elasticsearch.common.transport.LocalTransportAddress;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.License;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;

View File

@ -3,13 +3,13 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.core; package org.elasticsearch.license;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import java.util.Locale; import java.util.Locale;
import static org.elasticsearch.license.core.License.OperationMode; import static org.elasticsearch.license.License.OperationMode;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
/** /**

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.core; package org.elasticsearch.license;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.watcher.FileWatcher; import org.elasticsearch.watcher.FileWatcher;
@ -12,7 +12,6 @@ import org.junit.Before;
import java.nio.file.Path; import java.nio.file.Path;
import static org.elasticsearch.license.core.OperationModeFileWatcherTests.writeMode;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
@ -47,7 +46,7 @@ public class LicenseOperationModeUpdateTests extends ESTestCase {
.build(); .build();
assertThat(license.operationMode(), equalTo(License.OperationMode.resolve(type))); assertThat(license.operationMode(), equalTo(License.OperationMode.resolve(type)));
writeMode("gold", licenseModeFile); OperationModeFileWatcherTests.writeMode("gold", licenseModeFile);
license.setOperationModeFileWatcher(operationModeFileWatcher); license.setOperationModeFileWatcher(operationModeFileWatcher);
verifyZeroInteractions(resourceWatcherService); verifyZeroInteractions(resourceWatcherService);
assertThat(license.operationMode(), equalTo(License.OperationMode.resolve(type))); assertThat(license.operationMode(), equalTo(License.OperationMode.resolve(type)));
@ -65,7 +64,7 @@ public class LicenseOperationModeUpdateTests extends ESTestCase {
.build(); .build();
assertThat(license.operationMode(), equalTo(License.OperationMode.PLATINUM)); assertThat(license.operationMode(), equalTo(License.OperationMode.PLATINUM));
writeMode("gold", licenseModeFile); OperationModeFileWatcherTests.writeMode("gold", licenseModeFile);
license.setOperationModeFileWatcher(operationModeFileWatcher); license.setOperationModeFileWatcher(operationModeFileWatcher);
verify(resourceWatcherService, times(1)).add(any(FileWatcher.class), eq(ResourceWatcherService.Frequency.HIGH)); verify(resourceWatcherService, times(1)).add(any(FileWatcher.class), eq(ResourceWatcherService.Frequency.HIGH));
assertThat(license.operationMode(), equalTo(License.OperationMode.GOLD)); assertThat(license.operationMode(), equalTo(License.OperationMode.GOLD));

View File

@ -6,7 +6,6 @@
package org.elasticsearch.license; package org.elasticsearch.license;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.License;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.scheduler.SchedulerEngine; import org.elasticsearch.xpack.scheduler.SchedulerEngine;
import org.junit.Before; import org.junit.Before;

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.core; package org.elasticsearch.license;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;

View File

@ -9,10 +9,10 @@ import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.license.core.License;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.xpack.MockNetty3Plugin; import org.elasticsearch.xpack.MockNetty3Plugin;
import org.elasticsearch.xpack.MockNetty4Plugin;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -49,7 +49,7 @@ public class LicenseServiceClusterTests extends AbstractLicensesIntegrationTestC
@Override @Override
protected Collection<Class<? extends Plugin>> nodePlugins() { protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(XPackPlugin.class, MockNetty3Plugin.class); return Arrays.asList(XPackPlugin.class, MockNetty3Plugin.class, MockNetty4Plugin.class);
} }
@Override @Override

View File

@ -8,7 +8,6 @@ package org.elasticsearch.license;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
import org.elasticsearch.cluster.ClusterStateUpdateTask; import org.elasticsearch.cluster.ClusterStateUpdateTask;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.License;
import static org.elasticsearch.license.TestUtils.generateSignedLicense; import static org.elasticsearch.license.TestUtils.generateSignedLicense;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;

View File

@ -15,7 +15,6 @@ import org.elasticsearch.cluster.ack.ClusterStateUpdateResponse;
import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.License;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESSingleNodeTestCase; import org.elasticsearch.test.ESSingleNodeTestCase;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;

View File

@ -5,13 +5,10 @@
*/ */
package org.elasticsearch.license; package org.elasticsearch.license;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.metadata.RepositoriesMetaData; import org.elasticsearch.cluster.metadata.RepositoriesMetaData;
import org.elasticsearch.cluster.metadata.RepositoryMetaData; import org.elasticsearch.cluster.metadata.RepositoryMetaData;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
@ -20,14 +17,11 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.license.core.License;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import java.util.Base64;
import java.util.Collections; import java.util.Collections;
import java.util.UUID; import java.util.UUID;
import static org.elasticsearch.license.core.CryptUtils.encrypt;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.nullValue;
@ -90,120 +84,6 @@ public class LicensesMetaDataSerializationTests extends ESTestCase {
assertThat(licensesMetaDataFromXContent.getLicense(), equalTo(trialLicense)); assertThat(licensesMetaDataFromXContent.getLicense(), equalTo(trialLicense));
} }
public void test1xLicensesMetaDataFromXContent() throws Exception {
License signedLicense = TestUtils.generateSignedLicense(TimeValue.timeValueHours(2));
long issueDate = signedLicense.issueDate() - TimeValue.timeValueMillis(200).getMillis();
License.Builder specBuilder = License.builder()
.uid(UUID.randomUUID().toString())
.issuedTo("customer")
.maxNodes(5)
.issueDate(issueDate)
.expiryDate(issueDate + TimeValue.timeValueHours(2).getMillis());
final License trialLicense = TrialLicense.create(specBuilder);
// trial license
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
builder.startObject("licenses");
builder.startArray("trial_licenses");
XContentBuilder contentBuilder = XContentFactory.contentBuilder(XContentType.JSON);
trialLicense.toXContent(contentBuilder, new ToXContent.MapParams(Collections.singletonMap(License.LICENSE_SPEC_VIEW_MODE, "true")));
builder.value(Base64.getEncoder().encodeToString(encrypt(BytesReference.toBytes(contentBuilder.bytes()))));
builder.endArray();
builder.startArray("signed_licenses");
builder.endArray();
builder.endObject();
builder.endObject();
LicensesMetaData licensesMetaDataFromXContent = getLicensesMetaDataFromXContent(builder.bytes());
assertThat(licensesMetaDataFromXContent.getLicense(), equalTo(trialLicense));
// signed license
builder = XContentFactory.jsonBuilder();
builder.startObject();
builder.startObject("licenses");
builder.startArray("trial_licenses");
builder.endArray();
builder.startArray("signed_licenses");
signedLicense.toXContent(builder, ToXContent.EMPTY_PARAMS);
builder.endArray();
builder.endObject();
builder.endObject();
licensesMetaDataFromXContent = getLicensesMetaDataFromXContent(builder.bytes());
assertThat(licensesMetaDataFromXContent.getLicense(), equalTo(signedLicense));
// trial and signed license
builder = XContentFactory.jsonBuilder();
builder.startObject();
builder.startObject("licenses");
builder.startArray("trial_licenses");
contentBuilder = XContentFactory.contentBuilder(XContentType.JSON);
trialLicense.toXContent(contentBuilder, new ToXContent.MapParams(Collections.singletonMap(License.LICENSE_SPEC_VIEW_MODE, "true")));
builder.value(Base64.getEncoder().encodeToString(encrypt(BytesReference.toBytes(contentBuilder.bytes()))));
builder.endArray();
builder.startArray("signed_licenses");
signedLicense.toXContent(builder, ToXContent.EMPTY_PARAMS);
builder.endArray();
builder.endObject();
builder.endObject();
licensesMetaDataFromXContent = getLicensesMetaDataFromXContent(builder.bytes());
assertThat(licensesMetaDataFromXContent.getLicense(), equalTo(signedLicense));
// license with later issue date is selected
long laterIssueDate = trialLicense.issueDate() + TimeValue.timeValueHours(2).getMillis();
License signedLicenseIssuedLater = TestUtils.generateSignedLicense(laterIssueDate, TimeValue.timeValueHours(2));
builder = XContentFactory.jsonBuilder();
builder.startObject();
builder.startObject("licenses");
builder.startArray("trial_licenses");
contentBuilder = XContentFactory.contentBuilder(XContentType.JSON);
trialLicense.toXContent(contentBuilder, new ToXContent.MapParams(Collections.singletonMap(License.LICENSE_SPEC_VIEW_MODE, "true")));
builder.value(Base64.getEncoder().encodeToString(encrypt(BytesReference.toBytes(contentBuilder.bytes()))));
builder.endArray();
builder.startArray("signed_licenses");
signedLicense.toXContent(builder, ToXContent.EMPTY_PARAMS);
signedLicenseIssuedLater.toXContent(builder, ToXContent.EMPTY_PARAMS);
builder.endArray();
builder.endObject();
builder.endObject();
licensesMetaDataFromXContent = getLicensesMetaDataFromXContent(builder.bytes());
assertThat(licensesMetaDataFromXContent.getLicense(), equalTo(signedLicenseIssuedLater));
}
public void test1xLicensesMetaDataFromStream() throws Exception {
long issueDate = System.currentTimeMillis();
License.Builder specBuilder = License.builder()
.uid(UUID.randomUUID().toString())
.issuedTo("customer")
.maxNodes(5)
.issueDate(issueDate)
.expiryDate(issueDate + TimeValue.timeValueHours(1).getMillis());
final License trialLicense = TrialLicense.create(specBuilder);
// trial license
BytesStreamOutput output = new BytesStreamOutput();
output.writeVInt(0);
output.writeVInt(1);
XContentBuilder contentBuilder = XContentFactory.contentBuilder(XContentType.JSON);
trialLicense.toXContent(contentBuilder, new ToXContent.MapParams(Collections.singletonMap(License.LICENSE_SPEC_VIEW_MODE, "true")));
output.writeString(Base64.getEncoder().encodeToString(encrypt(BytesReference.toBytes(contentBuilder.bytes()))));
try (StreamInput input = output.bytes().streamInput()) {
input.setVersion(Version.V_2_0_0_beta1);
LicensesMetaData licensesMetaData = LicensesMetaData.PROTO.readFrom(input);
assertThat(licensesMetaData.getLicense(), equalTo(trialLicense));
}
// signed license
License signedLicense = TestUtils.generateSignedLicense(TimeValue.timeValueHours(2));
output = new BytesStreamOutput();
output.writeVInt(1);
signedLicense.writeTo(output);
output.writeVInt(0);
try (StreamInput input = output.bytes().streamInput()) {
input.setVersion(Version.V_2_0_0_beta1);
LicensesMetaData licensesMetaData = LicensesMetaData.PROTO.readFrom(input);
assertThat(licensesMetaData.getLicense(), equalTo(signedLicense));
}
}
public void testLicenseTombstoneFromXContext() throws Exception { public void testLicenseTombstoneFromXContext() throws Exception {
final XContentBuilder builder = XContentFactory.jsonBuilder(); final XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject("licenses"); builder.startObject("licenses");

View File

@ -8,7 +8,6 @@ package org.elasticsearch.license;
import org.elasticsearch.action.ActionFuture; import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.License;
import org.elasticsearch.xpack.monitoring.Monitoring; import org.elasticsearch.xpack.monitoring.Monitoring;
import org.elasticsearch.node.Node; import org.elasticsearch.node.Node;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.core; package org.elasticsearch.license;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;

View File

@ -5,6 +5,7 @@
*/ */
package org.elasticsearch.license; package org.elasticsearch.license;
import com.carrotsearch.randomizedtesting.RandomizedTest;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.io.PathUtils; import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.joda.DateMathParser; import org.elasticsearch.common.joda.DateMathParser;
@ -15,10 +16,12 @@ import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.licensor.LicenseSigner; import org.elasticsearch.license.licensor.LicenseSigner;
import org.hamcrest.MatcherAssert;
import org.joda.time.format.DateTimeFormatter;
import org.junit.Assert; import org.junit.Assert;
import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -27,6 +30,9 @@ import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomBoolean;
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomInt;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.test.ESTestCase.assertNotNull; import static org.elasticsearch.test.ESTestCase.assertNotNull;
import static org.elasticsearch.test.ESTestCase.awaitBusy; import static org.elasticsearch.test.ESTestCase.awaitBusy;
import static org.elasticsearch.test.ESTestCase.randomAsciiOfLength; import static org.elasticsearch.test.ESTestCase.randomAsciiOfLength;
@ -39,6 +45,16 @@ public class TestUtils {
private static final FormatDateTimeFormatter formatDateTimeFormatter = Joda.forPattern("yyyy-MM-dd"); private static final FormatDateTimeFormatter formatDateTimeFormatter = Joda.forPattern("yyyy-MM-dd");
private static final DateMathParser dateMathParser = new DateMathParser(formatDateTimeFormatter); private static final DateMathParser dateMathParser = new DateMathParser(formatDateTimeFormatter);
private static final DateTimeFormatter dateTimeFormatter = formatDateTimeFormatter.printer();
public static String dateMathString(String time, final long now) {
return dateTimeFormatter.print(dateMathParser.parse(time, new Callable<Long>() {
@Override
public Long call() throws Exception {
return now;
}
}));
}
public static long dateMath(String time, final long now) { public static long dateMath(String time, final long now) {
return dateMathParser.parse(time, new Callable<Long>() { return dateMathParser.parse(time, new Callable<Long>() {
@ -48,6 +64,159 @@ public class TestUtils {
} }
}); });
} }
public static LicenseSpec generateRandomLicenseSpec(int version) {
boolean datesInMillis = randomBoolean();
long now = System.currentTimeMillis();
String uid = UUID.randomUUID().toString();
String feature = "feature__" + randomInt();
String issuer = "issuer__" + randomInt();
String issuedTo = "issuedTo__" + randomInt();
final String type;
final String subscriptionType;
if (version < License.VERSION_NO_FEATURE_TYPE) {
subscriptionType = randomFrom("gold", "silver", "platinum");
type = "subscription";//randomFrom("subscription", "internal", "development");
} else {
subscriptionType = null;
type = randomFrom("basic", "dev", "gold", "silver", "platinum");
}
int maxNodes = RandomizedTest.randomIntBetween(5, 100);
if (datesInMillis) {
long issueDateInMillis = dateMath("now", now);
long expiryDateInMillis = dateMath("now+10d/d", now);
return new LicenseSpec(version, uid, feature, issueDateInMillis, expiryDateInMillis, type, subscriptionType, issuedTo, issuer,
maxNodes);
} else {
String issueDate = dateMathString("now", now);
String expiryDate = dateMathString("now+10d/d", now);
return new LicenseSpec(version, uid, feature, issueDate, expiryDate, type, subscriptionType, issuedTo, issuer, maxNodes);
}
}
public static String generateLicenseSpecString(LicenseSpec licenseSpec) throws IOException {
XContentBuilder licenses = jsonBuilder();
licenses.startObject();
licenses.startArray("licenses");
licenses.startObject()
.field("uid", licenseSpec.uid)
.field("type", licenseSpec.type)
.field("subscription_type", licenseSpec.subscriptionType)
.field("issued_to", licenseSpec.issuedTo)
.field("issuer", licenseSpec.issuer)
.field("feature", licenseSpec.feature)
.field("max_nodes", licenseSpec.maxNodes);
if (licenseSpec.issueDate != null) {
licenses.field("issue_date", licenseSpec.issueDate);
} else {
licenses.field("issue_date_in_millis", licenseSpec.issueDateInMillis);
}
if (licenseSpec.expiryDate != null) {
licenses.field("expiry_date", licenseSpec.expiryDate);
} else {
licenses.field("expiry_date_in_millis", licenseSpec.expiryDateInMillis);
}
licenses.field("version", licenseSpec.version);
licenses.endObject();
licenses.endArray();
licenses.endObject();
return licenses.string();
}
public static License generateLicenses(LicenseSpec spec) {
License.Builder builder = License.builder()
.uid(spec.uid)
.feature(spec.feature)
.type(spec.type)
.subscriptionType(spec.subscriptionType)
.issuedTo(spec.issuedTo)
.issuer(spec.issuer)
.maxNodes(spec.maxNodes);
if (spec.expiryDate != null) {
builder.expiryDate(DateUtils.endOfTheDay(spec.expiryDate));
} else {
builder.expiryDate(spec.expiryDateInMillis);
}
if (spec.issueDate != null) {
builder.issueDate(DateUtils.beginningOfTheDay(spec.issueDate));
} else {
builder.issueDate(spec.issueDateInMillis);
}
return builder.build();
}
public static void assertLicenseSpec(LicenseSpec spec, License license) {
MatcherAssert.assertThat(license.uid(), equalTo(spec.uid));
MatcherAssert.assertThat(license.issuedTo(), equalTo(spec.issuedTo));
MatcherAssert.assertThat(license.issuer(), equalTo(spec.issuer));
MatcherAssert.assertThat(license.type(), equalTo(spec.type));
MatcherAssert.assertThat(license.maxNodes(), equalTo(spec.maxNodes));
if (spec.issueDate != null) {
MatcherAssert.assertThat(license.issueDate(), equalTo(DateUtils.beginningOfTheDay(spec.issueDate)));
} else {
MatcherAssert.assertThat(license.issueDate(), equalTo(spec.issueDateInMillis));
}
if (spec.expiryDate != null) {
MatcherAssert.assertThat(license.expiryDate(), equalTo(DateUtils.endOfTheDay(spec.expiryDate)));
} else {
MatcherAssert.assertThat(license.expiryDate(), equalTo(spec.expiryDateInMillis));
}
}
public static class LicenseSpec {
public final int version;
public final String feature;
public final String issueDate;
public final long issueDateInMillis;
public final String expiryDate;
public final long expiryDateInMillis;
public final String uid;
public final String type;
public final String subscriptionType;
public final String issuedTo;
public final String issuer;
public final int maxNodes;
public LicenseSpec(String issueDate, String expiryDate) {
this(License.VERSION_CURRENT, UUID.randomUUID().toString(), "feature", issueDate, expiryDate, "trial", "none", "customer",
"elasticsearch", 5);
}
public LicenseSpec(int version, String uid, String feature, long issueDateInMillis, long expiryDateInMillis, String type,
String subscriptionType, String issuedTo, String issuer, int maxNodes) {
this.version = version;
this.feature = feature;
this.issueDateInMillis = issueDateInMillis;
this.issueDate = null;
this.expiryDateInMillis = expiryDateInMillis;
this.expiryDate = null;
this.uid = uid;
this.type = type;
this.subscriptionType = subscriptionType;
this.issuedTo = issuedTo;
this.issuer = issuer;
this.maxNodes = maxNodes;
}
public LicenseSpec(int version, String uid, String feature, String issueDate, String expiryDate, String type,
String subscriptionType, String issuedTo, String issuer, int maxNodes) {
this.version = version;
this.feature = feature;
this.issueDate = issueDate;
this.issueDateInMillis = -1;
this.expiryDate = expiryDate;
this.expiryDateInMillis = -1;
this.uid = uid;
this.type = type;
this.subscriptionType = subscriptionType;
this.issuedTo = issuedTo;
this.issuer = issuer;
this.maxNodes = maxNodes;
}
}
public static Path getTestPriKeyPath() throws Exception { public static Path getTestPriKeyPath() throws Exception {
return getResourcePath("/private.key"); return getResourcePath("/private.key");
} }

View File

@ -11,8 +11,6 @@ import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.TrialLicense;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import java.io.IOException; import java.io.IOException;
@ -21,7 +19,7 @@ import java.util.Base64;
import java.util.Collections; import java.util.Collections;
import java.util.UUID; import java.util.UUID;
import static org.elasticsearch.license.core.CryptUtils.encrypt; import static org.elasticsearch.license.CryptUtils.encrypt;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;

View File

@ -7,28 +7,46 @@ package org.elasticsearch.xpack.monitoring;
import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionResponse; import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.common.component.LifecycleComponent; import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.inject.util.Providers;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.license.LicenseService;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.monitoring.action.MonitoringBulkAction; import org.elasticsearch.xpack.monitoring.action.MonitoringBulkAction;
import org.elasticsearch.xpack.monitoring.action.TransportMonitoringBulkAction; import org.elasticsearch.xpack.monitoring.action.TransportMonitoringBulkAction;
import org.elasticsearch.xpack.monitoring.agent.AgentService; import org.elasticsearch.xpack.monitoring.agent.AgentService;
import org.elasticsearch.xpack.monitoring.agent.collector.CollectorModule; import org.elasticsearch.xpack.monitoring.agent.collector.Collector;
import org.elasticsearch.xpack.monitoring.agent.exporter.ExporterModule; import org.elasticsearch.xpack.monitoring.agent.collector.cluster.ClusterStateCollector;
import org.elasticsearch.xpack.monitoring.agent.collector.cluster.ClusterStatsCollector;
import org.elasticsearch.xpack.monitoring.agent.collector.indices.IndexRecoveryCollector;
import org.elasticsearch.xpack.monitoring.agent.collector.indices.IndexStatsCollector;
import org.elasticsearch.xpack.monitoring.agent.collector.indices.IndicesStatsCollector;
import org.elasticsearch.xpack.monitoring.agent.collector.node.NodeStatsCollector;
import org.elasticsearch.xpack.monitoring.agent.collector.shards.ShardsCollector;
import org.elasticsearch.xpack.monitoring.agent.exporter.Exporter;
import org.elasticsearch.xpack.monitoring.agent.exporter.Exporters;
import org.elasticsearch.xpack.monitoring.agent.exporter.http.HttpExporter;
import org.elasticsearch.xpack.monitoring.agent.exporter.local.LocalExporter;
import org.elasticsearch.xpack.monitoring.cleaner.CleanerService; import org.elasticsearch.xpack.monitoring.cleaner.CleanerService;
import org.elasticsearch.xpack.monitoring.client.MonitoringClientModule;
import org.elasticsearch.xpack.monitoring.rest.action.RestMonitoringBulkAction; import org.elasticsearch.xpack.monitoring.rest.action.RestMonitoringBulkAction;
import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.plugins.ActionPlugin;
import org.elasticsearch.rest.RestHandler; import org.elasticsearch.rest.RestHandler;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.security.InternalClient;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
@ -44,12 +62,16 @@ public class Monitoring implements ActionPlugin {
public static final String NAME = "monitoring"; public static final String NAME = "monitoring";
private final Settings settings; private final Settings settings;
private final Environment env;
private final XPackLicenseState licenseState;
private final boolean enabled; private final boolean enabled;
private final boolean transportClientMode; private final boolean transportClientMode;
private final boolean tribeNode; private final boolean tribeNode;
public Monitoring(Settings settings) { public Monitoring(Settings settings, Environment env, XPackLicenseState licenseState) {
this.settings = settings; this.settings = settings;
this.env = env;
this.licenseState = licenseState;
this.enabled = enabled(settings); this.enabled = enabled(settings);
this.transportClientMode = XPackPlugin.transportClientMode(settings); this.transportClientMode = XPackPlugin.transportClientMode(settings);
this.tribeNode = XPackPlugin.isTribeNode(settings); this.tribeNode = XPackPlugin.isTribeNode(settings);
@ -65,20 +87,41 @@ public class Monitoring implements ActionPlugin {
public Collection<Module> nodeModules() { public Collection<Module> nodeModules() {
List<Module> modules = new ArrayList<>(); List<Module> modules = new ArrayList<>();
modules.add(new MonitoringModule(enabled, transportClientMode)); modules.add(b -> {
modules.add(new ExporterModule(settings)); XPackPlugin.bindFeatureSet(b, MonitoringFeatureSet.class);
if (enabled && transportClientMode == false && tribeNode == false) { if (transportClientMode || enabled == false || tribeNode) {
modules.add(new CollectorModule()); b.bind(Exporters.class).toProvider(Providers.of(null));
modules.add(new MonitoringClientModule());
} }
});
return modules; return modules;
} }
public Collection<Class<? extends LifecycleComponent>> nodeServices() { public Collection<Object> createComponents(InternalClient client, ThreadPool threadPool, ClusterService clusterService,
if (enabled == false || transportClientMode || tribeNode) { LicenseService licenseService) {
if (enabled == false || tribeNode) {
return Collections.emptyList(); return Collections.emptyList();
} }
return Arrays.<Class<? extends LifecycleComponent>>asList(AgentService.class, CleanerService.class);
final ClusterSettings clusterSettings = clusterService.getClusterSettings();
final MonitoringSettings monitoringSettings = new MonitoringSettings(settings, clusterSettings);
final CleanerService cleanerService = new CleanerService(settings, clusterSettings, threadPool, licenseState);
Map<String, Exporter.Factory> exporterFactories = new HashMap<>();
exporterFactories.put(HttpExporter.TYPE, config -> new HttpExporter(config, env));
exporterFactories.put(LocalExporter.TYPE, config -> new LocalExporter(config, client, clusterService, cleanerService));
final Exporters exporters = new Exporters(settings, exporterFactories, clusterService);
Set<Collector> collectors = new HashSet<>();
collectors.add(new IndicesStatsCollector(settings, clusterService, monitoringSettings, licenseState, client));
collectors.add(new IndexStatsCollector(settings, clusterService, monitoringSettings, licenseState, client));
collectors.add(new ClusterStatsCollector(settings, clusterService, monitoringSettings, licenseState, client, licenseService));
collectors.add(new ClusterStateCollector(settings, clusterService, monitoringSettings, licenseState, client));
collectors.add(new ShardsCollector(settings, clusterService, monitoringSettings, licenseState));
collectors.add(new NodeStatsCollector(settings, clusterService, monitoringSettings, licenseState, client));
collectors.add(new IndexRecoveryCollector(settings, clusterService, monitoringSettings, licenseState, client));
final AgentService agentService = new AgentService(settings, clusterSettings, collectors, exporters);
return Arrays.asList(agentService, monitoringSettings, exporters, cleanerService);
} }
@Override @Override

View File

@ -5,9 +5,12 @@
*/ */
package org.elasticsearch.xpack.monitoring; package org.elasticsearch.xpack.monitoring;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
@ -17,10 +20,6 @@ import org.elasticsearch.xpack.XPackFeatureSet;
import org.elasticsearch.xpack.monitoring.agent.exporter.Exporter; import org.elasticsearch.xpack.monitoring.agent.exporter.Exporter;
import org.elasticsearch.xpack.monitoring.agent.exporter.Exporters; import org.elasticsearch.xpack.monitoring.agent.exporter.Exporters;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/** /**
* *
*/ */
@ -31,12 +30,10 @@ public class MonitoringFeatureSet implements XPackFeatureSet {
private final Exporters exporters; private final Exporters exporters;
@Inject @Inject
public MonitoringFeatureSet(Settings settings, @Nullable XPackLicenseState licenseState, @Nullable Exporters exporters, public MonitoringFeatureSet(Settings settings, @Nullable XPackLicenseState licenseState, @Nullable Exporters exporters) {
NamedWriteableRegistry namedWriteableRegistry) {
this.enabled = MonitoringSettings.ENABLED.get(settings); this.enabled = MonitoringSettings.ENABLED.get(settings);
this.licenseState = licenseState; this.licenseState = licenseState;
this.exporters = exporters; this.exporters = exporters;
namedWriteableRegistry.register(Usage.class, Usage.writeableName(Monitoring.NAME), Usage::new);
} }
@Override @Override
@ -71,7 +68,7 @@ public class MonitoringFeatureSet implements XPackFeatureSet {
Map<String, Object> usage = new HashMap<>(); Map<String, Object> usage = new HashMap<>();
for (Exporter exporter : exporters) { for (Exporter exporter : exporters) {
if (exporter.config().enabled()) { if (exporter.config().enabled()) {
String type = exporter.type(); String type = exporter.config().type();
int count = (Integer) usage.getOrDefault(type, 0); int count = (Integer) usage.getOrDefault(type, 0);
usage.put(type, count + 1); usage.put(type, count + 1);
} }
@ -79,7 +76,7 @@ public class MonitoringFeatureSet implements XPackFeatureSet {
return usage; return usage;
} }
static class Usage extends XPackFeatureSet.Usage { public static class Usage extends XPackFeatureSet.Usage {
private static final String ENABLED_EXPORTERS_XFIELD = "enabled_exporters"; private static final String ENABLED_EXPORTERS_XFIELD = "enabled_exporters";

View File

@ -1,34 +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.xpack.monitoring;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.util.Providers;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.monitoring.agent.AgentService;
import org.elasticsearch.xpack.monitoring.cleaner.CleanerService;
public class MonitoringModule extends AbstractModule {
private final boolean enabled;
private final boolean transportClientMode;
public MonitoringModule(boolean enabled, boolean transportClientMode) {
this.enabled = enabled;
this.transportClientMode = transportClientMode;
}
@Override
protected void configure() {
XPackPlugin.bindFeatureSet(binder(), MonitoringFeatureSet.class);
if (enabled && transportClientMode == false) {
bind(MonitoringSettings.class).asEagerSingleton();
bind(AgentService.class).asEagerSingleton();
bind(CleanerService.class).asEagerSingleton();
}
}
}

View File

@ -34,7 +34,6 @@ public class MonitoringSettings extends AbstractComponent {
* The minimum amount of time allowed for the history duration. * The minimum amount of time allowed for the history duration.
*/ */
public static final TimeValue HISTORY_DURATION_MINIMUM = TimeValue.timeValueHours(24); public static final TimeValue HISTORY_DURATION_MINIMUM = TimeValue.timeValueHours(24);
public static final TimeValue MAX_LICENSE_GRACE_PERIOD = TimeValue.timeValueHours(7 * 24);
/** /**
* Determines whether monitoring is enabled/disabled * Determines whether monitoring is enabled/disabled
@ -123,7 +122,7 @@ public class MonitoringSettings extends AbstractComponent {
* Settings/Options per configured exporter * Settings/Options per configured exporter
*/ */
public static final Setting<Settings> EXPORTERS_SETTINGS = public static final Setting<Settings> EXPORTERS_SETTINGS =
groupSetting(collectionKey("exporters."), Property.Dynamic, Property.NodeScope); groupSetting(key("exporters."), Property.Dynamic, Property.NodeScope);
public static List<Setting<?>> getSettings() { public static List<Setting<?>> getSettings() {
return Arrays.asList(INDICES, return Arrays.asList(INDICES,
@ -141,7 +140,7 @@ public class MonitoringSettings extends AbstractComponent {
} }
public static List<String> getSettingsFilter() { public static List<String> getSettingsFilter() {
return Arrays.asList("xpack.monitoring.collection.exporters.*.auth.*", "xpack.monitoring.collection.exporters.*.ssl.*"); return Arrays.asList(key("exporters.*.auth.*"), key("exporters.*.ssl.*"));
} }
@ -153,7 +152,6 @@ public class MonitoringSettings extends AbstractComponent {
private volatile boolean recoveryActiveOnly; private volatile boolean recoveryActiveOnly;
private volatile String[] indices; private volatile String[] indices;
@Inject
public MonitoringSettings(Settings settings, ClusterSettings clusterSettings) { public MonitoringSettings(Settings settings, ClusterSettings clusterSettings) {
super(settings); super(settings);

View File

@ -51,7 +51,6 @@ public class AgentService extends AbstractLifecycleComponent {
private final String[] settingsCollectors; private final String[] settingsCollectors;
private final Exporters exporters; private final Exporters exporters;
@Inject
public AgentService(Settings settings, ClusterSettings clusterSettings, Set<Collector> collectors, Exporters exporters) { public AgentService(Settings settings, ClusterSettings clusterSettings, Set<Collector> collectors, Exporters exporters) {
super(settings); super(settings);
this.samplingIntervalMillis = MonitoringSettings.INTERVAL.get(settings).millis(); this.samplingIntervalMillis = MonitoringSettings.INTERVAL.get(settings).millis();

View File

@ -27,7 +27,6 @@ public abstract class AbstractCollector extends AbstractLifecycleComponent imple
protected final MonitoringSettings monitoringSettings; protected final MonitoringSettings monitoringSettings;
protected final XPackLicenseState licenseState; protected final XPackLicenseState licenseState;
@Inject
public AbstractCollector(Settings settings, String name, ClusterService clusterService, public AbstractCollector(Settings settings, String name, ClusterService clusterService,
MonitoringSettings monitoringSettings, XPackLicenseState licenseState) { MonitoringSettings monitoringSettings, XPackLicenseState licenseState) {
super(settings); super(settings);

View File

@ -1,48 +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.xpack.monitoring.agent.collector;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.multibindings.Multibinder;
import org.elasticsearch.xpack.monitoring.agent.collector.cluster.ClusterStateCollector;
import org.elasticsearch.xpack.monitoring.agent.collector.cluster.ClusterStatsCollector;
import org.elasticsearch.xpack.monitoring.agent.collector.indices.IndexRecoveryCollector;
import org.elasticsearch.xpack.monitoring.agent.collector.indices.IndexStatsCollector;
import org.elasticsearch.xpack.monitoring.agent.collector.indices.IndicesStatsCollector;
import org.elasticsearch.xpack.monitoring.agent.collector.node.NodeStatsCollector;
import org.elasticsearch.xpack.monitoring.agent.collector.shards.ShardsCollector;
import java.util.HashSet;
import java.util.Set;
public class CollectorModule extends AbstractModule {
private final Set<Class<? extends Collector>> collectors = new HashSet<>();
public CollectorModule() {
// Registers default collectors
registerCollector(IndicesStatsCollector.class);
registerCollector(IndexStatsCollector.class);
registerCollector(ClusterStatsCollector.class);
registerCollector(ClusterStateCollector.class);
registerCollector(ShardsCollector.class);
registerCollector(NodeStatsCollector.class);
registerCollector(IndexRecoveryCollector.class);
}
@Override
protected void configure() {
Multibinder<Collector> binder = Multibinder.newSetBinder(binder(), Collector.class);
for (Class<? extends Collector> collector : collectors) {
bind(collector).asEagerSingleton();
binder.addBinding().to(collector);
}
}
public void registerCollector(Class<? extends Collector> collector) {
collectors.add(collector);
}
}

View File

@ -6,7 +6,7 @@
package org.elasticsearch.xpack.monitoring.agent.collector.cluster; package org.elasticsearch.xpack.monitoring.agent.collector.cluster;
import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse; import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse;
import org.elasticsearch.license.core.License; import org.elasticsearch.license.License;
import org.elasticsearch.xpack.monitoring.agent.exporter.MonitoringDoc; import org.elasticsearch.xpack.monitoring.agent.exporter.MonitoringDoc;
public class ClusterInfoMonitoringDoc extends MonitoringDoc { public class ClusterInfoMonitoringDoc extends MonitoringDoc {

View File

@ -5,13 +5,17 @@
*/ */
package org.elasticsearch.xpack.monitoring.agent.collector.cluster; package org.elasticsearch.xpack.monitoring.agent.collector.cluster;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.xpack.monitoring.MonitoringSettings; import org.elasticsearch.xpack.monitoring.MonitoringSettings;
@ -19,11 +23,6 @@ import org.elasticsearch.xpack.monitoring.agent.collector.AbstractCollector;
import org.elasticsearch.xpack.monitoring.agent.exporter.MonitoringDoc; import org.elasticsearch.xpack.monitoring.agent.exporter.MonitoringDoc;
import org.elasticsearch.xpack.security.InternalClient; import org.elasticsearch.xpack.security.InternalClient;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/** /**
* Collector for cluster state. * Collector for cluster state.
* <p> * <p>
@ -36,7 +35,6 @@ public class ClusterStateCollector extends AbstractCollector {
private final Client client; private final Client client;
@Inject
public ClusterStateCollector(Settings settings, ClusterService clusterService, public ClusterStateCollector(Settings settings, ClusterService clusterService,
MonitoringSettings monitoringSettings, XPackLicenseState licenseState, InternalClient client) { MonitoringSettings monitoringSettings, XPackLicenseState licenseState, InternalClient client) {
super(settings, NAME, clusterService, monitoringSettings, licenseState); super(settings, NAME, clusterService, monitoringSettings, licenseState);

View File

@ -5,13 +5,17 @@
*/ */
package org.elasticsearch.xpack.monitoring.agent.collector.cluster; package org.elasticsearch.xpack.monitoring.agent.collector.cluster;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse; import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.LicenseService; import org.elasticsearch.license.LicenseService;
import org.elasticsearch.license.LicenseUtils; import org.elasticsearch.license.LicenseUtils;
@ -21,11 +25,6 @@ import org.elasticsearch.xpack.monitoring.agent.collector.AbstractCollector;
import org.elasticsearch.xpack.monitoring.agent.exporter.MonitoringDoc; import org.elasticsearch.xpack.monitoring.agent.exporter.MonitoringDoc;
import org.elasticsearch.xpack.security.InternalClient; import org.elasticsearch.xpack.security.InternalClient;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/** /**
* Collector for cluster stats. * Collector for cluster stats.
* <p> * <p>
@ -43,7 +42,6 @@ public class ClusterStatsCollector extends AbstractCollector {
private final LicenseService licenseService; private final LicenseService licenseService;
private final Client client; private final Client client;
@Inject
public ClusterStatsCollector(Settings settings, ClusterService clusterService, public ClusterStatsCollector(Settings settings, ClusterService clusterService,
MonitoringSettings monitoringSettings, XPackLicenseState licenseState, InternalClient client, MonitoringSettings monitoringSettings, XPackLicenseState licenseState, InternalClient client,
LicenseService licenseService) { LicenseService licenseService) {

View File

@ -5,12 +5,17 @@
*/ */
package org.elasticsearch.xpack.monitoring.agent.collector.indices; package org.elasticsearch.xpack.monitoring.agent.collector.indices;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.elasticsearch.action.admin.indices.recovery.RecoveryResponse; import org.elasticsearch.action.admin.indices.recovery.RecoveryResponse;
import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.license.XPackLicenseState;
@ -20,12 +25,6 @@ import org.elasticsearch.xpack.monitoring.agent.exporter.MonitoringDoc;
import org.elasticsearch.xpack.security.InternalClient; import org.elasticsearch.xpack.security.InternalClient;
import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.Security;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/** /**
* Collector for the Recovery API. * Collector for the Recovery API.
* <p> * <p>
@ -38,7 +37,6 @@ public class IndexRecoveryCollector extends AbstractCollector {
private final Client client; private final Client client;
@Inject
public IndexRecoveryCollector(Settings settings, ClusterService clusterService, public IndexRecoveryCollector(Settings settings, ClusterService clusterService,
MonitoringSettings monitoringSettings, XPackLicenseState licenseState, InternalClient client) { MonitoringSettings monitoringSettings, XPackLicenseState licenseState, InternalClient client) {
super(settings, NAME, clusterService, monitoringSettings, licenseState); super(settings, NAME, clusterService, monitoringSettings, licenseState);

View File

@ -5,6 +5,12 @@
*/ */
package org.elasticsearch.xpack.monitoring.agent.collector.indices; package org.elasticsearch.xpack.monitoring.agent.collector.indices;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.elasticsearch.action.admin.indices.stats.IndexStats; import org.elasticsearch.action.admin.indices.stats.IndexStats;
import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse; import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.IndicesOptions;
@ -12,7 +18,6 @@ import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.license.XPackLicenseState;
@ -22,12 +27,6 @@ import org.elasticsearch.xpack.monitoring.agent.exporter.MonitoringDoc;
import org.elasticsearch.xpack.security.InternalClient; import org.elasticsearch.xpack.security.InternalClient;
import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.Security;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/** /**
* Collector for indices statistics. * Collector for indices statistics.
* <p> * <p>
@ -40,7 +39,6 @@ public class IndexStatsCollector extends AbstractCollector {
private final Client client; private final Client client;
@Inject
public IndexStatsCollector(Settings settings, ClusterService clusterService, public IndexStatsCollector(Settings settings, ClusterService clusterService,
MonitoringSettings monitoringSettings, XPackLicenseState licenseState, InternalClient client) { MonitoringSettings monitoringSettings, XPackLicenseState licenseState, InternalClient client) {
super(settings, NAME, clusterService, monitoringSettings, licenseState); super(settings, NAME, clusterService, monitoringSettings, licenseState);

View File

@ -5,12 +5,15 @@
*/ */
package org.elasticsearch.xpack.monitoring.agent.collector.indices; package org.elasticsearch.xpack.monitoring.agent.collector.indices;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse; import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.license.XPackLicenseState;
@ -20,10 +23,6 @@ import org.elasticsearch.xpack.monitoring.agent.exporter.MonitoringDoc;
import org.elasticsearch.xpack.security.InternalClient; import org.elasticsearch.xpack.security.InternalClient;
import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.Security;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
/** /**
* Collector for indices statistics. * Collector for indices statistics.
* <p> * <p>
@ -35,7 +34,6 @@ public class IndicesStatsCollector extends AbstractCollector {
private final Client client; private final Client client;
@Inject
public IndicesStatsCollector(Settings settings, ClusterService clusterService, public IndicesStatsCollector(Settings settings, ClusterService clusterService,
MonitoringSettings monitoringSettings, XPackLicenseState licenseState, InternalClient client) { MonitoringSettings monitoringSettings, XPackLicenseState licenseState, InternalClient client) {
super(settings, NAME, clusterService, monitoringSettings, licenseState); super(settings, NAME, clusterService, monitoringSettings, licenseState);

View File

@ -5,6 +5,10 @@
*/ */
package org.elasticsearch.xpack.monitoring.agent.collector.node; package org.elasticsearch.xpack.monitoring.agent.collector.node;
import java.util.Collection;
import java.util.Collections;
import java.util.function.Consumer;
import org.elasticsearch.action.admin.cluster.node.stats.NodeStats; import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsRequest; import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsRequest;
import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse; import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
@ -12,20 +16,14 @@ import org.elasticsearch.action.admin.indices.stats.CommonStatsFlags;
import org.elasticsearch.bootstrap.BootstrapInfo; import org.elasticsearch.bootstrap.BootstrapInfo;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.routing.allocation.decider.DiskThresholdDecider;
import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.NodeEnvironment;
import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.xpack.monitoring.MonitoringSettings; import org.elasticsearch.xpack.monitoring.MonitoringSettings;
import org.elasticsearch.xpack.monitoring.agent.collector.AbstractCollector; import org.elasticsearch.xpack.monitoring.agent.collector.AbstractCollector;
import org.elasticsearch.xpack.monitoring.agent.exporter.MonitoringDoc; import org.elasticsearch.xpack.monitoring.agent.exporter.MonitoringDoc;
import org.elasticsearch.xpack.security.InternalClient; import org.elasticsearch.xpack.security.InternalClient;
import java.util.Collection;
import java.util.Collections;
/** /**
* Collector for nodes statistics. * Collector for nodes statistics.
* <p> * <p>
@ -37,29 +35,11 @@ public class NodeStatsCollector extends AbstractCollector {
public static final String NAME = "node-stats-collector"; public static final String NAME = "node-stats-collector";
private final Client client; private final Client client;
private final NodeEnvironment nodeEnvironment;
private final DiskThresholdDecider diskThresholdDecider;
@Inject
public NodeStatsCollector(Settings settings, ClusterService clusterService, MonitoringSettings monitoringSettings, public NodeStatsCollector(Settings settings, ClusterService clusterService, MonitoringSettings monitoringSettings,
XPackLicenseState licenseState, InternalClient client, XPackLicenseState licenseState, InternalClient client) {
NodeEnvironment nodeEnvironment, DiskThresholdDecider diskThresholdDecider) {
super(settings, NAME, clusterService, monitoringSettings, licenseState); super(settings, NAME, clusterService, monitoringSettings, licenseState);
this.client = client; this.client = client;
this.nodeEnvironment = nodeEnvironment;
this.diskThresholdDecider = diskThresholdDecider;
}
@Override
protected boolean shouldCollect() {
// In some cases, the collector starts to collect nodes stats but the
// NodeEnvironment is not fully initialized (NodePath is null) and can fail.
// This why we need to check for nodeEnvironment.hasNodeFile() here, but only
// for nodes that can hold data. Client nodes can collect nodes stats because
// elasticsearch correctly handles the nodes stats for client nodes.
return super.shouldCollect()
&& (DiscoveryNode.nodeRequiresLocalStorage(settings) == false || nodeEnvironment.hasNodeFile());
} }
@Override @Override
@ -80,12 +60,6 @@ public class NodeStatsCollector extends AbstractCollector {
} }
NodeStats nodeStats = response.getNodes().get(0); NodeStats nodeStats = response.getNodes().get(0);
// Here we are calling directly the DiskThresholdDecider to retrieve the high watermark value
// It would be nicer to use a settings API like documented in #6732
Double diskThresholdWatermarkHigh = (diskThresholdDecider != null) ? 100.0 - diskThresholdDecider.getFreeDiskThresholdHigh() : -1;
boolean diskThresholdDeciderEnabled = (diskThresholdDecider != null) && diskThresholdDecider.isEnabled();
DiscoveryNode sourceNode = localNode(); DiscoveryNode sourceNode = localNode();
NodeStatsMonitoringDoc nodeStatsDoc = new NodeStatsMonitoringDoc(monitoringId(), monitoringVersion()); NodeStatsMonitoringDoc nodeStatsDoc = new NodeStatsMonitoringDoc(monitoringId(), monitoringVersion());
@ -96,8 +70,6 @@ public class NodeStatsCollector extends AbstractCollector {
nodeStatsDoc.setNodeMaster(isLocalNodeMaster()); nodeStatsDoc.setNodeMaster(isLocalNodeMaster());
nodeStatsDoc.setNodeStats(nodeStats); nodeStatsDoc.setNodeStats(nodeStats);
nodeStatsDoc.setMlockall(BootstrapInfo.isMemoryLocked()); nodeStatsDoc.setMlockall(BootstrapInfo.isMemoryLocked());
nodeStatsDoc.setDiskThresholdWaterMarkHigh(diskThresholdWatermarkHigh);
nodeStatsDoc.setDiskThresholdDeciderEnabled(diskThresholdDeciderEnabled);
return Collections.singletonList(nodeStatsDoc); return Collections.singletonList(nodeStatsDoc);
} }

View File

@ -13,10 +13,7 @@ public class NodeStatsMonitoringDoc extends MonitoringDoc {
private String nodeId; private String nodeId;
private boolean nodeMaster; private boolean nodeMaster;
private NodeStats nodeStats; private NodeStats nodeStats;
private boolean mlockall; private boolean mlockall;
private Double diskThresholdWaterMarkHigh;
private boolean diskThresholdDeciderEnabled;
public NodeStatsMonitoringDoc(String monitoringId, String monitoringVersion) { public NodeStatsMonitoringDoc(String monitoringId, String monitoringVersion) {
super(monitoringId, monitoringVersion); super(monitoringId, monitoringVersion);
@ -38,14 +35,6 @@ public class NodeStatsMonitoringDoc extends MonitoringDoc {
this.mlockall = mlockall; this.mlockall = mlockall;
} }
public void setDiskThresholdWaterMarkHigh(Double diskThresholdWaterMarkHigh) {
this.diskThresholdWaterMarkHigh = diskThresholdWaterMarkHigh;
}
public void setDiskThresholdDeciderEnabled(boolean diskThresholdDeciderEnabled) {
this.diskThresholdDeciderEnabled = diskThresholdDeciderEnabled;
}
public String getNodeId() { public String getNodeId() {
return nodeId; return nodeId;
} }
@ -61,13 +50,5 @@ public class NodeStatsMonitoringDoc extends MonitoringDoc {
public boolean isMlockall() { public boolean isMlockall() {
return mlockall; return mlockall;
} }
public Double getDiskThresholdWaterMarkHigh() {
return diskThresholdWaterMarkHigh;
}
public boolean isDiskThresholdDeciderEnabled() {
return diskThresholdDeciderEnabled;
}
} }

View File

@ -5,12 +5,17 @@
*/ */
package org.elasticsearch.xpack.monitoring.agent.collector.shards; package org.elasticsearch.xpack.monitoring.agent.collector.shards;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.routing.RoutingTable; import org.elasticsearch.cluster.routing.RoutingTable;
import org.elasticsearch.cluster.routing.ShardRouting; import org.elasticsearch.cluster.routing.ShardRouting;
import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.regex.Regex; import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.license.XPackLicenseState;
@ -18,12 +23,6 @@ import org.elasticsearch.xpack.monitoring.MonitoringSettings;
import org.elasticsearch.xpack.monitoring.agent.collector.AbstractCollector; import org.elasticsearch.xpack.monitoring.agent.collector.AbstractCollector;
import org.elasticsearch.xpack.monitoring.agent.exporter.MonitoringDoc; import org.elasticsearch.xpack.monitoring.agent.exporter.MonitoringDoc;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/** /**
* Collector for shards. * Collector for shards.
* <p> * <p>
@ -34,7 +33,6 @@ public class ShardsCollector extends AbstractCollector {
public static final String NAME = "shards-collector"; public static final String NAME = "shards-collector";
@Inject
public ShardsCollector(Settings settings, ClusterService clusterService, public ShardsCollector(Settings settings, ClusterService clusterService,
MonitoringSettings monitoringSettings, XPackLicenseState licenseState) { MonitoringSettings monitoringSettings, XPackLicenseState licenseState) {
super(settings, NAME, clusterService, monitoringSettings, licenseState); super(settings, NAME, clusterService, monitoringSettings, licenseState);

View File

@ -19,7 +19,6 @@ public abstract class Exporter implements AutoCloseable {
public static final String INDEX_NAME_TIME_FORMAT_SETTING = "index.name.time_format"; public static final String INDEX_NAME_TIME_FORMAT_SETTING = "index.name.time_format";
public static final String BULK_TIMEOUT_SETTING = "bulk.timeout"; public static final String BULK_TIMEOUT_SETTING = "bulk.timeout";
protected final String type;
protected final Config config; protected final Config config;
protected final ESLogger logger; protected final ESLogger logger;
@ -27,17 +26,12 @@ public abstract class Exporter implements AutoCloseable {
private AtomicBoolean closed = new AtomicBoolean(false); private AtomicBoolean closed = new AtomicBoolean(false);
public Exporter(String type, Config config) { public Exporter(Config config) {
this.type = type;
this.config = config; this.config = config;
this.logger = config.logger(getClass()); this.logger = config.logger(getClass());
this.bulkTimeout = config.settings().getAsTime(BULK_TIMEOUT_SETTING, null); this.bulkTimeout = config.settings().getAsTime(BULK_TIMEOUT_SETTING, null);
} }
public String type() {
return type;
}
public String name() { public String name() {
return config.name; return config.name;
} }
@ -50,6 +44,11 @@ public abstract class Exporter implements AutoCloseable {
return false; return false;
} }
/** Returns true if only one instance of this exporter should be allowed. */
public boolean isSingleton() {
return false;
}
/** /**
* Opens up a new export bulk. May return {@code null} indicating this exporter is not ready * Opens up a new export bulk. May return {@code null} indicating this exporter is not ready
* yet to export the docs * yet to export the docs
@ -76,12 +75,14 @@ public abstract class Exporter implements AutoCloseable {
public static class Config { public static class Config {
private final String name; private final String name;
private final String type;
private final boolean enabled; private final boolean enabled;
private final Settings globalSettings; private final Settings globalSettings;
private final Settings settings; private final Settings settings;
public Config(String name, Settings globalSettings, Settings settings) { public Config(String name, String type, Settings globalSettings, Settings settings) {
this.name = name; this.name = name;
this.type = type;
this.globalSettings = globalSettings; this.globalSettings = globalSettings;
this.settings = settings; this.settings = settings;
this.enabled = settings.getAsBoolean("enabled", true); this.enabled = settings.getAsBoolean("enabled", true);
@ -91,6 +92,10 @@ public abstract class Exporter implements AutoCloseable {
return name; return name;
} }
public String type() {
return type;
}
public boolean enabled() { public boolean enabled() {
return enabled; return enabled;
} }
@ -104,24 +109,10 @@ public abstract class Exporter implements AutoCloseable {
} }
} }
public abstract static class Factory<E extends Exporter> { /** A factory for constructing {@link Exporter} instances.*/
public interface Factory {
private final String type; /** Create an exporter with the given configuration. */
private final boolean singleton; Exporter create(Config config);
public Factory(String type, boolean singleton) {
this.type = type;
this.singleton = singleton;
}
public String type() {
return type;
}
public boolean singleton() {
return singleton;
}
public abstract E create(Config config);
} }
} }

View File

@ -1,49 +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.xpack.monitoring.agent.exporter;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.multibindings.MapBinder;
import org.elasticsearch.common.inject.util.Providers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.monitoring.Monitoring;
import org.elasticsearch.xpack.monitoring.agent.exporter.http.HttpExporter;
import org.elasticsearch.xpack.monitoring.agent.exporter.local.LocalExporter;
import java.util.HashMap;
import java.util.Map;
public class ExporterModule extends AbstractModule {
private final Settings settings;
private final Map<String, Class<? extends Exporter.Factory<? extends Exporter>>> exporterFactories = new HashMap<>();
public ExporterModule(Settings settings) {
this.settings = settings;
registerExporter(HttpExporter.TYPE, HttpExporter.Factory.class);
registerExporter(LocalExporter.TYPE, LocalExporter.Factory.class);
}
@Override
protected void configure() {
if (Monitoring.enabled(settings) && XPackPlugin.transportClientMode(settings) == false
&& XPackPlugin.isTribeNode(settings) == false) {
bind(Exporters.class).asEagerSingleton();
MapBinder<String, Exporter.Factory> factoryBinder = MapBinder.newMapBinder(binder(), String.class, Exporter.Factory.class);
for (Map.Entry<String, Class<? extends Exporter.Factory<? extends Exporter>>> entry : exporterFactories.entrySet()) {
bind(entry.getValue()).asEagerSingleton();
factoryBinder.addBinding(entry.getKey()).to(entry.getValue());
}
} else {
bind(Exporters.class).toProvider(Providers.of(null));
}
}
public void registerExporter(String type, Class<? extends Exporter.Factory<? extends Exporter>> factory) {
exporterFactories.put(type, factory);
}
}

View File

@ -8,9 +8,7 @@ package org.elasticsearch.xpack.monitoring.agent.exporter;
import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.component.AbstractLifecycleComponent; import org.elasticsearch.common.component.AbstractLifecycleComponent;
import org.elasticsearch.common.component.Lifecycle; import org.elasticsearch.common.component.Lifecycle;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException; import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.node.Node; import org.elasticsearch.node.Node;
@ -39,16 +37,15 @@ public class Exporters extends AbstractLifecycleComponent implements Iterable<Ex
private final AtomicReference<Map<String, Exporter>> exporters; private final AtomicReference<Map<String, Exporter>> exporters;
@Inject
public Exporters(Settings settings, Map<String, Exporter.Factory> factories, public Exporters(Settings settings, Map<String, Exporter.Factory> factories,
ClusterService clusterService, ClusterService clusterService) {
ClusterSettings clusterSettings) {
super(settings); super(settings);
this.factories = factories; this.factories = factories;
this.clusterService = clusterService; this.clusterService = clusterService;
this.exporters = new AtomicReference<>(emptyMap()); this.exporters = new AtomicReference<>(emptyMap());
clusterSettings.addSettingsUpdateConsumer(MonitoringSettings.EXPORTERS_SETTINGS, this::setExportersSetting); clusterService.getClusterSettings().addSettingsUpdateConsumer(MonitoringSettings.EXPORTERS_SETTINGS,
this::setExportersSetting);
} }
private void setExportersSetting(Settings exportersSetting) { private void setExportersSetting(Settings exportersSetting) {
@ -135,7 +132,7 @@ public class Exporters extends AbstractLifecycleComponent implements Iterable<Ex
if (factory == null) { if (factory == null) {
throw new SettingsException("unknown exporter type [" + type + "] set for exporter [" + name + "]"); throw new SettingsException("unknown exporter type [" + type + "] set for exporter [" + name + "]");
} }
Exporter.Config config = new Exporter.Config(name, globalSettings, exporterSettings); Exporter.Config config = new Exporter.Config(name, type, globalSettings, exporterSettings);
if (!config.enabled()) { if (!config.enabled()) {
hasDisabled = true; hasDisabled = true;
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
@ -143,8 +140,9 @@ public class Exporters extends AbstractLifecycleComponent implements Iterable<Ex
} }
continue; continue;
} }
if (factory.singleton()) { Exporter exporter = factory.create(config);
// this is a singleton exporter factory, let's make sure we didn't already registered one if (exporter.isSingleton()) {
// this is a singleton exporter, let's make sure we didn't already create one
// (there can only be one instance of a singleton exporter) // (there can only be one instance of a singleton exporter)
if (singletons.contains(type)) { if (singletons.contains(type)) {
throw new SettingsException("multiple [" + type + "] exporters are configured. there can " + throw new SettingsException("multiple [" + type + "] exporters are configured. there can " +
@ -152,7 +150,7 @@ public class Exporters extends AbstractLifecycleComponent implements Iterable<Ex
} }
singletons.add(type); singletons.add(type);
} }
exporters.put(config.name(), factory.create(config)); exporters.put(config.name(), exporter);
} }
// no exporters are configured, lets create a default local one. // no exporters are configured, lets create a default local one.
@ -161,7 +159,8 @@ public class Exporters extends AbstractLifecycleComponent implements Iterable<Ex
// fallback on the default // fallback on the default
// //
if (exporters.isEmpty() && !hasDisabled) { if (exporters.isEmpty() && !hasDisabled) {
Exporter.Config config = new Exporter.Config("default_" + LocalExporter.TYPE, globalSettings, Settings.EMPTY); Exporter.Config config = new Exporter.Config("default_" + LocalExporter.TYPE, LocalExporter.TYPE,
globalSettings, Settings.EMPTY);
exporters.put(config.name(), factories.get(LocalExporter.TYPE).create(config)); exporters.put(config.name(), factories.get(LocalExporter.TYPE).create(config));
} }

View File

@ -111,9 +111,8 @@ public class HttpExporter extends Exporter {
final ConnectionKeepAliveWorker keepAliveWorker; final ConnectionKeepAliveWorker keepAliveWorker;
Thread keepAliveThread; Thread keepAliveThread;
public HttpExporter(Exporter.Config config, Environment env) { public HttpExporter(Config config, Environment env) {
super(config);
super(TYPE, config);
this.env = env; this.env = env;
hosts = config.settings().getAsArray(HOST_SETTING, Strings.EMPTY_ARRAY); hosts = config.settings().getAsArray(HOST_SETTING, Strings.EMPTY_ARRAY);
@ -537,7 +536,7 @@ public class HttpExporter extends Exporter {
try { try {
HttpExporterUtils.parseHostWithPath(host, ""); HttpExporterUtils.parseHostWithPath(host, "");
} catch (URISyntaxException | MalformedURLException e) { } catch (URISyntaxException | MalformedURLException e) {
throw new SettingsException("[xpack.monitoring.collection.exporters] invalid host: [" + host + "]." + throw new SettingsException("[xpack.monitoring.exporters] invalid host: [" + host + "]." +
" error: [" + e.getMessage() + "]"); " error: [" + e.getMessage() + "]");
} }
} }
@ -754,20 +753,4 @@ public class HttpExporter extends Exporter {
} }
} }
} }
public static class Factory extends Exporter.Factory<HttpExporter> {
private final Environment env;
@Inject
public Factory(Environment env) {
super(TYPE, false);
this.env = env;
}
@Override
public HttpExporter create(Config config) {
return new HttpExporter(config, env);
}
}
} }

Some files were not shown because too many files have changed in this diff Show More