Merge branch 'master' into feature/async_rest_client

Original commit: elastic/x-pack-elasticsearch@693e281d0d
This commit is contained in:
javanna 2016-07-19 16:29:50 +02:00 committed by Luca Cavanna
commit ca557af48c
289 changed files with 5667 additions and 3510 deletions

View File

@ -101,6 +101,7 @@ public class License implements ToXContent {
case "gold":
return GOLD;
case "platinum":
case "cloud_internal":
case "internal": // bwc for 1.x subscription_type field
return PLATINUM;
default:
@ -196,12 +197,42 @@ public class License implements ToXContent {
}
/**
* @return the operation mode of the license as computed from the license type
* @return the operation mode of the license as computed from the license type or from
* the license mode file
*/
public OperationMode operationMode() {
synchronized (this) {
if (canReadOperationModeFromFile() && operationModeFileWatcher != null) {
return operationModeFileWatcher.getCurrentOperationMode();
}
}
return operationMode;
}
private boolean canReadOperationModeFromFile() {
return type.equals("cloud_internal");
}
private volatile OperationModeFileWatcher operationModeFileWatcher;
/**
* Sets the operation mode file watcher for the license and initializes the
* file watcher when the license type allows to override operation mode from file
*/
public synchronized void setOperationModeFileWatcher(final OperationModeFileWatcher operationModeFileWatcher) {
this.operationModeFileWatcher = operationModeFileWatcher;
if (canReadOperationModeFromFile()) {
this.operationModeFileWatcher.init();
}
}
/**
* Removes operation mode file watcher, so unused license objects can be gc'ed
*/
public synchronized void removeOperationModeFileWatcher() {
this.operationModeFileWatcher = null;
}
/**
* @return the current license's status
*/

View File

@ -0,0 +1,113 @@
/*
* 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.logging.ESLogger;
import org.elasticsearch.license.core.License.OperationMode;
import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* File based watcher for license {@link OperationMode}
* Watches for changes in <code>licenseModePath</code>, use
* {@link #getCurrentOperationMode()} to access the latest mode
*
* In case of failure to read a valid operation mode from <code>licenseModePath</code>,
* the operation mode will default to PLATINUM
*/
public final class OperationModeFileWatcher extends FileChangesListener {
private final ResourceWatcherService resourceWatcherService;
private final Path licenseModePath;
private final AtomicBoolean initialized = new AtomicBoolean();
private final OperationMode defaultOperationMode = OperationMode.PLATINUM;
private volatile OperationMode currentOperationMode = defaultOperationMode;
private final ESLogger logger;
private final Runnable onChange;
public OperationModeFileWatcher(ResourceWatcherService resourceWatcherService, Path licenseModePath,
ESLogger logger, Runnable onChange) {
this.resourceWatcherService = resourceWatcherService;
this.licenseModePath = licenseModePath;
this.logger = logger;
this.onChange = onChange;
}
public void init() {
if (initialized.compareAndSet(false, true)) {
final FileWatcher watcher = new FileWatcher(licenseModePath);
watcher.addListener(this);
try {
resourceWatcherService.add(watcher, ResourceWatcherService.Frequency.HIGH);
if (Files.exists(licenseModePath)) {
onChange(licenseModePath);
}
} catch (IOException e) {
logger.error("couldn't initialize watching license mode file", e);
}
}
}
/**
* Returns the current operation mode based on license mode file.
* Defaults to {@link OperationMode#PLATINUM}
*/
public OperationMode getCurrentOperationMode() {
return currentOperationMode;
}
@Override
public void onFileInit(Path file) {
onChange(file);
}
@Override
public void onFileCreated(Path file) {
onChange(file);
}
@Override
public void onFileDeleted(Path file) {
onChange(file);
}
@Override
public void onFileChanged(Path file) {
onChange(file);
}
private synchronized void onChange(Path file) {
if (file.equals(licenseModePath)) {
currentOperationMode = defaultOperationMode;
if (Files.exists(licenseModePath)
&& Files.isReadable(licenseModePath)) {
final byte[] content;
try {
content = Files.readAllBytes(licenseModePath);
} catch (IOException e) {
logger.error("couldn't read operation mode from [{}]", e, licenseModePath.toAbsolutePath().toString());
return;
}
String operationMode = new String(content, StandardCharsets.UTF_8);
try {
currentOperationMode = OperationMode.resolve(operationMode);
} catch (IllegalArgumentException e) {
logger.error("invalid operation mode in [{}]", e, licenseModePath.toAbsolutePath().toString());
return;
}
}
onChange.run();
}
}
}

View File

@ -0,0 +1,73 @@
/*
* 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.test.ESTestCase;
import org.elasticsearch.watcher.FileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.junit.Before;
import java.nio.file.Path;
import static org.elasticsearch.license.core.OperationModeFileWatcherTests.writeMode;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
public class LicenseOperationModeUpdateTests extends ESTestCase {
private OperationModeFileWatcher operationModeFileWatcher;
private Path licenseModeFile;
private ResourceWatcherService resourceWatcherService;
@Before
public void init() throws Exception {
licenseModeFile = createTempFile();
resourceWatcherService = mock(ResourceWatcherService.class);
operationModeFileWatcher = new OperationModeFileWatcher(resourceWatcherService, licenseModeFile, logger, () -> {});
}
public void testLicenseOperationModeUpdate() throws Exception {
String type = randomFrom("trial", "basic", "standard", "gold", "platinum");
License license = License.builder()
.uid("id")
.expiryDate(0)
.issueDate(0)
.issuedTo("elasticsearch")
.issuer("issuer")
.type(type)
.maxNodes(1)
.build();
assertThat(license.operationMode(), equalTo(License.OperationMode.resolve(type)));
writeMode("gold", licenseModeFile);
license.setOperationModeFileWatcher(operationModeFileWatcher);
verifyZeroInteractions(resourceWatcherService);
assertThat(license.operationMode(), equalTo(License.OperationMode.resolve(type)));
}
public void testCloudInternalLicenseOperationModeUpdate() throws Exception {
License license = License.builder()
.uid("id")
.expiryDate(0)
.issueDate(0)
.issuedTo("elasticsearch")
.issuer("issuer")
.type("cloud_internal")
.maxNodes(1)
.build();
assertThat(license.operationMode(), equalTo(License.OperationMode.PLATINUM));
writeMode("gold", licenseModeFile);
license.setOperationModeFileWatcher(operationModeFileWatcher);
verify(resourceWatcherService, times(1)).add(any(FileWatcher.class), eq(ResourceWatcherService.Frequency.HIGH));
assertThat(license.operationMode(), equalTo(License.OperationMode.GOLD));
}
}

View File

@ -0,0 +1,114 @@
/*
* 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.settings.Settings;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.junit.After;
import org.junit.Before;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.atomic.AtomicInteger;
import static org.hamcrest.Matchers.equalTo;
public class OperationModeFileWatcherTests extends ESTestCase {
private ResourceWatcherService watcherService;
private TestThreadPool threadPool;
private Path licenseModePath;
private OperationModeFileWatcher operationModeFileWatcher;
private AtomicInteger onChangeCounter;
@Before
public void setup() throws Exception {
threadPool = new TestThreadPool("license mode file watcher tests");
Settings settings = Settings.builder()
.put("resource.reload.interval.high", "10ms")
.build();
watcherService = new ResourceWatcherService(settings,
threadPool);
watcherService.start();
licenseModePath = createTempFile();
onChangeCounter = new AtomicInteger();
operationModeFileWatcher = new OperationModeFileWatcher(watcherService, licenseModePath, logger,
() -> onChangeCounter.incrementAndGet());
}
@After
public void shutdown() throws InterruptedException {
terminate(threadPool);
watcherService.stop();
}
public void testInit() throws Exception {
writeMode("gold");
assertThat(operationModeFileWatcher.getCurrentOperationMode(), equalTo(License.OperationMode.PLATINUM));
operationModeFileWatcher.init();
assertThat(onChangeCounter.get(), equalTo(2));
assertThat(operationModeFileWatcher.getCurrentOperationMode(), equalTo(License.OperationMode.GOLD));
}
public void testUpdateModeFromFile() throws Exception {
Files.delete(licenseModePath);
operationModeFileWatcher.init();
assertThat(operationModeFileWatcher.getCurrentOperationMode(), equalTo(License.OperationMode.PLATINUM));
writeMode("gold");
assertBusy(() -> assertThat(operationModeFileWatcher.getCurrentOperationMode(), equalTo(License.OperationMode.GOLD)));
writeMode("basic");
assertBusy(() -> assertThat(operationModeFileWatcher.getCurrentOperationMode(), equalTo(License.OperationMode.BASIC)));
assertThat(onChangeCounter.get(), equalTo(2));
}
public void testDeleteModeFromFile() throws Exception {
Files.delete(licenseModePath);
operationModeFileWatcher.init();
writeMode("gold");
assertBusy(() -> assertThat(operationModeFileWatcher.getCurrentOperationMode(), equalTo(License.OperationMode.GOLD)));
Files.delete(licenseModePath);
assertBusy(() -> assertThat(operationModeFileWatcher.getCurrentOperationMode(), equalTo(License.OperationMode.PLATINUM)));
assertThat(onChangeCounter.get(), equalTo(2));
}
public void testInvalidModeFromFile() throws Exception {
writeMode("invalid");
operationModeFileWatcher.init();
assertThat(operationModeFileWatcher.getCurrentOperationMode(), equalTo(License.OperationMode.PLATINUM));
operationModeFileWatcher.onFileChanged(licenseModePath);
assertThat(operationModeFileWatcher.getCurrentOperationMode(), equalTo(License.OperationMode.PLATINUM));
}
public void testLicenseModeFileIsDirectory() throws Exception {
licenseModePath = createTempDir();
operationModeFileWatcher.init();
assertThat(operationModeFileWatcher.getCurrentOperationMode(), equalTo(License.OperationMode.PLATINUM));
operationModeFileWatcher.onFileChanged(licenseModePath);
assertThat(operationModeFileWatcher.getCurrentOperationMode(), equalTo(License.OperationMode.PLATINUM));
}
public void testLicenseModeFileCreatedAfterInit() throws Exception {
Files.delete(licenseModePath);
operationModeFileWatcher.init();
assertThat(operationModeFileWatcher.getCurrentOperationMode(), equalTo(License.OperationMode.PLATINUM));
Path tempFile = createTempFile();
writeMode("gold", tempFile);
licenseModePath = tempFile;
assertBusy(() -> assertThat(operationModeFileWatcher.getCurrentOperationMode(), equalTo(License.OperationMode.GOLD)));
}
private void writeMode(String mode) throws IOException {
writeMode(mode, licenseModePath);
}
static void writeMode(String mode, Path file) throws IOException {
Files.write(file, mode.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE);
}
}

View File

@ -14,7 +14,7 @@ project.sourceSets.test.output.dir(outputDir, builtBy: copyXPackPluginProps)
integTest {
cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
plugin ':x-plugins:elasticsearch:x-pack'
setting 'xpack.security.audit.enabled', 'true'
setting 'xpack.security.audit.outputs', 'index'
setting 'logger.level', 'DEBUG'

View File

@ -34,7 +34,7 @@ integTest {
'search/80_date_math_index_names/Missing index with catch'].join(',')
cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
plugin ':x-plugins:elasticsearch:x-pack'
setting 'xpack.watcher.enabled', 'false'
setting 'xpack.monitoring.enabled', 'false'
setupCommand 'setupDummyUser',

View File

@ -14,7 +14,7 @@ import org.elasticsearch.xpack.watcher.condition.script.ScriptCondition;
import org.elasticsearch.xpack.watcher.execution.ManualExecutionContext;
import org.elasticsearch.xpack.watcher.execution.ManualExecutionTests.ExecutionRunner;
import org.elasticsearch.xpack.watcher.history.WatchRecord;
import org.elasticsearch.xpack.watcher.support.Script;
import org.elasticsearch.xpack.watcher.support.WatcherScript;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.transport.actions.delete.DeleteWatchResponse;
import org.elasticsearch.xpack.watcher.transport.actions.get.GetWatchRequest;
@ -65,7 +65,7 @@ public class GroovyManualExecutionIT extends AbstractWatcherIntegrationTestCase
WatchSourceBuilder watchBuilder = watchBuilder()
.trigger(schedule(cron("0 0 0 1 * ? 2099")))
.input(simpleInput("foo", "bar"))
.condition(new ScriptCondition((new Script.Builder.Inline("sleep 100; return true")).build()))
.condition(new ScriptCondition((new WatcherScript.Builder.Inline("sleep 100; return true")).build()))
.addAction("log", loggingAction("foobar"));
Watch watch = watchParser().parse("_id", false, watchBuilder.buildAsBytes(XContentType.JSON));
@ -80,7 +80,7 @@ public class GroovyManualExecutionIT extends AbstractWatcherIntegrationTestCase
WatchSourceBuilder watchBuilder = watchBuilder()
.trigger(schedule(cron("0 0 0 1 * ? 2099")))
.input(simpleInput("foo", "bar"))
.condition(new ScriptCondition((new Script.Builder.Inline("sleep 10000; return true")).build()))
.condition(new ScriptCondition((new WatcherScript.Builder.Inline("sleep 10000; return true")).build()))
.defaultThrottlePeriod(new TimeValue(1, TimeUnit.HOURS))
.addAction("log", loggingAction("foobar"));

View File

@ -8,6 +8,7 @@ package org.elasticsearch.messy.tests;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.groovy.GroovyPlugin;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
@ -16,8 +17,7 @@ import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.watcher.condition.script.ExecutableScriptCondition;
import org.elasticsearch.xpack.watcher.condition.script.ScriptCondition;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.support.Script;
import org.elasticsearch.xpack.common.ScriptServiceProxy;
import org.elasticsearch.xpack.watcher.support.WatcherScript;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.watch.Payload;
import org.junit.AfterClass;
@ -28,7 +28,7 @@ import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import static org.elasticsearch.messy.tests.MessyTestUtils.getScriptServiceProxy;
import static org.elasticsearch.messy.tests.MessyTestUtils.createScriptService;
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.mockExecutionContext;
public class GroovyScriptConditionIT extends AbstractWatcherIntegrationTestCase {
@ -46,7 +46,7 @@ public class GroovyScriptConditionIT extends AbstractWatcherIntegrationTestCase
}
private static ThreadPool THREAD_POOL;
private ScriptServiceProxy scriptService;
private ScriptService scriptService;
@BeforeClass
public static void startThreadPool() {
@ -55,7 +55,7 @@ public class GroovyScriptConditionIT extends AbstractWatcherIntegrationTestCase
@Before
public void init() throws Exception {
scriptService = getScriptServiceProxy(THREAD_POOL);
scriptService = createScriptService(THREAD_POOL);
}
@AfterClass
@ -83,7 +83,7 @@ public class GroovyScriptConditionIT extends AbstractWatcherIntegrationTestCase
SearchResponse unmetResponse = builder.get();
ExecutableScriptCondition condition =
new ExecutableScriptCondition(new ScriptCondition(Script.inline(
new ExecutableScriptCondition(new ScriptCondition(WatcherScript.inline(
String.join(
" ",
"if (ctx.payload.hits.total < 1) return false;",

View File

@ -6,9 +6,6 @@
package org.elasticsearch.messy.tests;
import org.apache.lucene.util.LuceneTestCase;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
@ -19,9 +16,8 @@ import org.elasticsearch.script.ScriptSettings;
import org.elasticsearch.script.groovy.GroovyScriptEngineService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.common.ScriptServiceProxy;
import org.elasticsearch.xpack.watcher.support.WatcherScript;
import org.junit.Ignore;
import org.mockito.Mockito;
import java.util.Arrays;
import java.util.Collections;
@ -29,7 +25,7 @@ import java.util.Collections;
@Ignore // not a test.
@SuppressForbidden(reason = "gradle is broken and tries to run me as a test")
public final class MessyTestUtils {
public static ScriptServiceProxy getScriptServiceProxy(ThreadPool tp) throws Exception {
public static ScriptService createScriptService(ThreadPool tp) throws Exception {
Settings settings = Settings.builder()
.put("script.inline", "true")
.put("script.indexed", "true")
@ -37,10 +33,10 @@ public final class MessyTestUtils {
.build();
GroovyScriptEngineService groovyScriptEngineService = new GroovyScriptEngineService(settings);
ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.singleton(groovyScriptEngineService));
ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Arrays.asList(ScriptServiceProxy.INSTANCE));
ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Arrays.asList(WatcherScript.CTX_PLUGIN));
ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
return ScriptServiceProxy.of(new ScriptService(settings, new Environment(settings),
new ResourceWatcherService(settings, tp), scriptEngineRegistry, scriptContextRegistry, scriptSettings));
return new ScriptService(settings, new Environment(settings), new ResourceWatcherService(settings, tp),
scriptEngineRegistry, scriptContextRegistry, scriptSettings);
}
}

View File

@ -10,6 +10,7 @@ import org.elasticsearch.action.search.ShardSearchFailure;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.Index;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.groovy.GroovyPlugin;
import org.elasticsearch.search.SearchShardTarget;
import org.elasticsearch.search.aggregations.AggregationBuilders;
@ -20,11 +21,10 @@ import org.elasticsearch.search.internal.InternalSearchHits;
import org.elasticsearch.search.internal.InternalSearchResponse;
import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.common.ScriptServiceProxy;
import org.elasticsearch.xpack.watcher.condition.script.ExecutableScriptCondition;
import org.elasticsearch.xpack.watcher.condition.script.ScriptCondition;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.support.Script;
import org.elasticsearch.xpack.watcher.support.WatcherScript;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.watch.Payload;
import org.junit.After;
@ -40,7 +40,7 @@ import static org.mockito.Mockito.when;
*/
public class ScriptConditionSearchIT extends AbstractWatcherIntegrationTestCase {
private ThreadPool tp = null;
private ScriptServiceProxy scriptService;
private ScriptService scriptService;
@Override
protected List<Class<? extends Plugin>> pluginTypes() {
@ -52,7 +52,7 @@ public class ScriptConditionSearchIT extends AbstractWatcherIntegrationTestCase
@Before
public void init() throws Exception {
tp = new TestThreadPool(ThreadPool.Names.SAME);
scriptService = MessyTestUtils.getScriptServiceProxy(tp);
scriptService = MessyTestUtils.createScriptService(tp);
}
@After
@ -73,7 +73,7 @@ public class ScriptConditionSearchIT extends AbstractWatcherIntegrationTestCase
.get();
ExecutableScriptCondition condition = new ExecutableScriptCondition(
new ScriptCondition(Script.inline("ctx.payload.aggregations.rate.buckets[0]?.doc_count >= 5").build()),
new ScriptCondition(WatcherScript.inline("ctx.payload.aggregations.rate.buckets[0]?.doc_count >= 5").build()),
logger, scriptService);
WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response));
@ -92,7 +92,7 @@ public class ScriptConditionSearchIT extends AbstractWatcherIntegrationTestCase
public void testExecuteAccessHits() throws Exception {
ExecutableScriptCondition condition = new ExecutableScriptCondition(new ScriptCondition(
Script.inline("ctx.payload.hits?.hits[0]?._score == 1.0").build()), logger, scriptService);
WatcherScript.inline("ctx.payload.hits?.hits[0]?._score == 1.0").build()), logger, scriptService);
InternalSearchHit hit = new InternalSearchHit(0, "1", new Text("type"), null);
hit.score(1f);
hit.shard(new SearchShardTarget("a", new Index("a", "testUUID"), 0));

View File

@ -15,17 +15,17 @@ import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.GeneralScriptException;
import org.elasticsearch.script.ScriptException;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.search.internal.InternalSearchResponse;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.common.ScriptServiceProxy;
import org.elasticsearch.xpack.watcher.condition.script.ExecutableScriptCondition;
import org.elasticsearch.xpack.watcher.condition.script.ScriptCondition;
import org.elasticsearch.xpack.watcher.condition.script.ScriptConditionFactory;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.support.Script;
import org.elasticsearch.xpack.watcher.support.WatcherScript;
import org.elasticsearch.xpack.watcher.watch.Payload;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
@ -36,7 +36,7 @@ import java.io.IOException;
import static java.util.Collections.singletonMap;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.messy.tests.MessyTestUtils.getScriptServiceProxy;
import static org.elasticsearch.messy.tests.MessyTestUtils.createScriptService;
import static org.elasticsearch.xpack.watcher.support.Exceptions.illegalArgument;
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.mockExecutionContext;
import static org.hamcrest.Matchers.containsString;
@ -57,18 +57,18 @@ public class ScriptConditionTests extends ESTestCase {
}
public void testExecute() throws Exception {
ScriptServiceProxy scriptService = getScriptServiceProxy(tp);
ScriptService scriptService = createScriptService(tp);
ExecutableScriptCondition condition = new ExecutableScriptCondition(
new ScriptCondition(Script.inline("ctx.payload.hits.total > 1").build()), logger, scriptService);
new ScriptCondition(WatcherScript.inline("ctx.payload.hits.total > 1").build()), logger, scriptService);
SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500L, new ShardSearchFailure[0]);
WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response));
assertFalse(condition.execute(ctx).met());
}
public void testExecuteMergedParams() throws Exception {
ScriptServiceProxy scriptService = getScriptServiceProxy(tp);
Script script = Script.inline("ctx.payload.hits.total > threshold")
.lang(Script.DEFAULT_LANG).params(singletonMap("threshold", 1)).build();
ScriptService scriptService = createScriptService(tp);
WatcherScript script = WatcherScript.inline("ctx.payload.hits.total > threshold")
.lang(WatcherScript.DEFAULT_LANG).params(singletonMap("threshold", 1)).build();
ExecutableScriptCondition executable = new ExecutableScriptCondition(new ScriptCondition(script), logger, scriptService);
SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500L, new ShardSearchFailure[0]);
WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response));
@ -76,7 +76,7 @@ public class ScriptConditionTests extends ESTestCase {
}
public void testParserValid() throws Exception {
ScriptConditionFactory factory = new ScriptConditionFactory(Settings.builder().build(), getScriptServiceProxy(tp));
ScriptConditionFactory factory = new ScriptConditionFactory(Settings.builder().build(), createScriptService(tp));
XContentBuilder builder = createConditionContent("ctx.payload.hits.total > 1", null, ScriptType.INLINE);
@ -103,7 +103,7 @@ public class ScriptConditionTests extends ESTestCase {
}
public void testParserInvalid() throws Exception {
ScriptConditionFactory factory = new ScriptConditionFactory(Settings.builder().build(), getScriptServiceProxy(tp));
ScriptConditionFactory factory = new ScriptConditionFactory(Settings.builder().build(), createScriptService(tp));
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject().endObject();
XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
@ -118,7 +118,7 @@ public class ScriptConditionTests extends ESTestCase {
}
public void testScriptConditionParserBadScript() throws Exception {
ScriptConditionFactory conditionParser = new ScriptConditionFactory(Settings.builder().build(), getScriptServiceProxy(tp));
ScriptConditionFactory conditionParser = new ScriptConditionFactory(Settings.builder().build(), createScriptService(tp));
ScriptType scriptType = randomFrom(ScriptType.values());
String script;
switch (scriptType) {
@ -139,7 +139,7 @@ public class ScriptConditionTests extends ESTestCase {
}
public void testScriptConditionParser_badLang() throws Exception {
ScriptConditionFactory conditionParser = new ScriptConditionFactory(Settings.builder().build(), getScriptServiceProxy(tp));
ScriptConditionFactory conditionParser = new ScriptConditionFactory(Settings.builder().build(), createScriptService(tp));
ScriptType scriptType = ScriptType.INLINE;
String script = "return true";
XContentBuilder builder = createConditionContent(script, "not_a_valid_lang", scriptType);
@ -152,9 +152,9 @@ public class ScriptConditionTests extends ESTestCase {
}
public void testScriptConditionThrowException() throws Exception {
ScriptServiceProxy scriptService = getScriptServiceProxy(tp);
ScriptService scriptService = createScriptService(tp);
ExecutableScriptCondition condition = new ExecutableScriptCondition(
new ScriptCondition(Script.inline("null.foo").build()), logger, scriptService);
new ScriptCondition(WatcherScript.inline("null.foo").build()), logger, scriptService);
SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500L, new ShardSearchFailure[0]);
WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response));
ScriptException exception = expectThrows(ScriptException.class, () -> condition.execute(ctx));
@ -162,9 +162,9 @@ public class ScriptConditionTests extends ESTestCase {
}
public void testScriptConditionReturnObjectThrowsException() throws Exception {
ScriptServiceProxy scriptService = getScriptServiceProxy(tp);
ScriptService scriptService = createScriptService(tp);
ExecutableScriptCondition condition = new ExecutableScriptCondition(
new ScriptCondition(Script.inline("return new Object()").build()), logger, scriptService);
new ScriptCondition(WatcherScript.inline("return new Object()").build()), logger, scriptService);
SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500L, new ShardSearchFailure[0]);
WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response));
Exception exception = expectThrows(GeneralScriptException.class, () -> condition.execute(ctx));
@ -173,9 +173,9 @@ public class ScriptConditionTests extends ESTestCase {
}
public void testScriptConditionAccessCtx() throws Exception {
ScriptServiceProxy scriptService = getScriptServiceProxy(tp);
ScriptService scriptService = createScriptService(tp);
ExecutableScriptCondition condition = new ExecutableScriptCondition(
new ScriptCondition(Script.inline("ctx.trigger.scheduled_time.getMillis() < new Date().time ").build()),
new ScriptCondition(WatcherScript.inline("ctx.trigger.scheduled_time.getMillis() < new Date().time ").build()),
logger, scriptService);
SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500L, new ShardSearchFailure[0]);
WatchExecutionContext ctx = mockExecutionContext("_name", new DateTime(DateTimeZone.UTC), new Payload.XContent(response));

View File

@ -13,7 +13,7 @@ import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.groovy.GroovyPlugin;
import org.elasticsearch.xpack.watcher.support.Script;
import org.elasticsearch.xpack.watcher.support.WatcherScript;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.test.WatcherTestUtils;
import org.elasticsearch.xpack.watcher.transport.actions.put.PutWatchResponse;
@ -72,10 +72,10 @@ public class TransformIT extends AbstractWatcherIntegrationTestCase {
}
public void testScriptTransform() throws Exception {
final Script script;
final WatcherScript script;
if (randomBoolean()) {
logger.info("testing script transform with an inline script");
script = Script.inline("return [key3 : ctx.payload.key1 + ctx.payload.key2]").lang("groovy").build();
script = WatcherScript.inline("return [key3 : ctx.payload.key1 + ctx.payload.key2]").lang("groovy").build();
} else if (randomBoolean()) {
logger.info("testing script transform with an indexed script");
client().admin().cluster().preparePutStoredScript()
@ -83,10 +83,10 @@ public class TransformIT extends AbstractWatcherIntegrationTestCase {
.setScriptLang("groovy")
.setSource(new BytesArray("{\"script\" : \"return [key3 : ctx.payload.key1 + ctx.payload.key2]\"}"))
.get();
script = Script.indexed("_id").lang("groovy").build();
script = WatcherScript.indexed("_id").lang("groovy").build();
} else {
logger.info("testing script transform with a file script");
script = Script.file("my-script").lang("groovy").build();
script = WatcherScript.file("my-script").lang("groovy").build();
}
// put a watch that has watch level transform:
@ -182,8 +182,8 @@ public class TransformIT extends AbstractWatcherIntegrationTestCase {
}
public void testChainTransform() throws Exception {
final Script script1 = Script.inline("return [key3 : ctx.payload.key1 + ctx.payload.key2]").lang("groovy").build();
final Script script2 = Script.inline("return [key4 : ctx.payload.key3 + 10]").lang("groovy").build();
final WatcherScript script1 = WatcherScript.inline("return [key3 : ctx.payload.key1 + ctx.payload.key2]").lang("groovy").build();
final WatcherScript script2 = WatcherScript.inline("return [key4 : ctx.payload.key3 + 10]").lang("groovy").build();
// put a watch that has watch level transform:
PutWatchResponse putWatchResponse = watcherClient().preparePutWatch("_id1")
.setSource(watchBuilder()

View File

@ -28,7 +28,6 @@ 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.ScriptServiceProxy;
import org.elasticsearch.xpack.common.text.TextTemplate;
import org.elasticsearch.xpack.watcher.actions.ActionWrapper;
import org.elasticsearch.xpack.watcher.actions.ExecutableActions;
@ -41,7 +40,7 @@ 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.Script;
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;
@ -190,7 +189,7 @@ public class SearchInputIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s");
Script template = Script.inline(TEMPLATE_QUERY).lang("mustache").params(params).build();
WatcherScript template = WatcherScript.inline(TEMPLATE_QUERY).lang("mustache").params(params).build();
SearchRequest request = client().prepareSearch()
.setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
@ -224,7 +223,7 @@ public class SearchInputIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s");
Script template = Script.indexed("test-template").lang("mustache").params(params).build();
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)
@ -252,7 +251,7 @@ public class SearchInputIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s");
Script template = Script.file("test_disk_template").lang("mustache").params(params).build();
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();
@ -347,7 +346,8 @@ public class SearchInputIT extends ESIntegTestCase {
timeValueSeconds(5));
}
private SearchInput.Result executeSearchInput(SearchRequest request, Script template, WatchExecutionContext ctx) throws IOException {
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));
@ -362,15 +362,15 @@ public class SearchInputIT extends ESIntegTestCase {
protected WatcherSearchTemplateService watcherSearchTemplateService() {
String master = internalCluster().getMasterName();
return new WatcherSearchTemplateService(internalCluster().clusterService(master).getSettings(),
ScriptServiceProxy.of(internalCluster().getInstance(ScriptService.class, master)),
internalCluster().getInstance(ScriptService.class, master),
internalCluster().getInstance(IndicesQueriesRegistry.class, master),
internalCluster().getInstance(AggregatorParsers.class, master),
internalCluster().getInstance(Suggesters.class, master)
);
}
protected ScriptServiceProxy scriptService() {
return ScriptServiceProxy.of(internalCluster().getInstance(ScriptService.class));
protected ScriptService scriptService() {
return internalCluster().getInstance(ScriptService.class);
}
private XContentSource toXContentSource(SearchInput.Result result) throws IOException {
@ -387,7 +387,7 @@ public class SearchInputIT extends ESIntegTestCase {
@Override
public ScriptContext.Plugin getCustomScriptContexts() {
return ScriptServiceProxy.INSTANCE;
return WatcherScript.CTX_PLUGIN;
}
}
}

View File

@ -32,7 +32,6 @@ 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.ScriptServiceProxy;
import org.elasticsearch.xpack.common.text.TextTemplate;
import org.elasticsearch.xpack.watcher.actions.ExecutableActions;
import org.elasticsearch.xpack.watcher.condition.always.ExecutableAlwaysCondition;
@ -40,7 +39,7 @@ import org.elasticsearch.xpack.watcher.execution.TriggeredExecutionContext;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput;
import org.elasticsearch.xpack.watcher.input.simple.SimpleInput;
import org.elasticsearch.xpack.watcher.support.Script;
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;
@ -348,7 +347,7 @@ public class SearchTransformIT extends ESIntegTestCase {
}
if (templateName != null) {
assertThat(executable.transform().getRequest().getTemplate(),
equalTo(Script.file("template1").build()));
equalTo(WatcherScript.file("template1").build()));
}
SearchSourceBuilder source = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery());
assertThat(executable.transform().getRequest().getRequest().source(), equalTo(source));
@ -381,7 +380,7 @@ public class SearchTransformIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s");
Script template = Script.inline(templateQuery).lang("mustache").params(params).build();
WatcherScript template = WatcherScript.inline(templateQuery).lang("mustache").params(params).build();
SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchTransform.DEFAULT_SEARCH_TYPE)
.setIndices("test-search-index").request();
@ -415,7 +414,7 @@ public class SearchTransformIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s");
Script template = Script.indexed("test-script").lang("mustache").params(params).build();
WatcherScript template = WatcherScript.indexed("test-script").lang("mustache").params(params).build();
SearchRequest request = client()
.prepareSearch()
@ -441,7 +440,7 @@ public class SearchTransformIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s");
Script template = Script.file("test_disk_template").lang("mustache").params(params).build();
WatcherScript template = WatcherScript.file("test_disk_template").lang("mustache").params(params).build();
SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchTransform.DEFAULT_SEARCH_TYPE)
.setIndices("test-search-index").request();
@ -504,7 +503,7 @@ public class SearchTransformIT extends ESIntegTestCase {
timeValueSeconds(5));
}
private SearchTransform.Result executeSearchTransform(SearchRequest request, Script template, WatchExecutionContext ctx)
private SearchTransform.Result executeSearchTransform(SearchRequest request, WatcherScript template, WatchExecutionContext ctx)
throws IOException {
createIndex("test-search-index");
ensureGreen("test-search-index");
@ -519,15 +518,15 @@ public class SearchTransformIT extends ESIntegTestCase {
protected WatcherSearchTemplateService watcherSearchTemplateService() {
String master = internalCluster().getMasterName();
return new WatcherSearchTemplateService(internalCluster().clusterService(master).getSettings(),
ScriptServiceProxy.of(internalCluster().getInstance(ScriptService.class, master)),
internalCluster().getInstance(ScriptService.class, master),
internalCluster().getInstance(IndicesQueriesRegistry.class, master),
internalCluster().getInstance(AggregatorParsers.class, master),
internalCluster().getInstance(Suggesters.class, master)
);
}
protected ScriptServiceProxy scriptService() {
return ScriptServiceProxy.of(internalCluster().getInstance(ScriptService.class));
protected ScriptService scriptService() {
return internalCluster().getInstance(ScriptService.class);
}
private static Map<String, Object> doc(String date, String value) {
@ -551,7 +550,7 @@ public class SearchTransformIT extends ESIntegTestCase {
@Override
public ScriptContext.Plugin getCustomScriptContexts() {
return ScriptServiceProxy.INSTANCE;
return WatcherScript.CTX_PLUGIN;
}
}
}

View File

@ -7,14 +7,13 @@ package org.elasticsearch.messy.tests;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.Version;
import org.elasticsearch.action.search.SearchPhaseExecutionException;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.indices.TermsLookup;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.Template;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.mustache.MustachePlugin;
import org.elasticsearch.script.mustache.MustacheScriptEngineService;
import org.elasticsearch.script.mustache.TemplateQueryBuilder;
import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
@ -25,7 +24,6 @@ import java.util.ArrayList;
import java.util.Collection;
import static java.util.Collections.singletonMap;
import static org.elasticsearch.script.ScriptService.ScriptType.INLINE;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
@ -109,7 +107,7 @@ public class SecurityCachePermissionIT extends SecurityIntegTestCase {
//Template template = new Template(source, INLINE, MustacheScriptEngineService.NAME, null, singletonMap("name", "token"));
SearchResponse response = client().prepareSearch("data").setTypes("a")
.setQuery(QueryBuilders.templateQuery(source, singletonMap("name", "token")))
.setQuery(new TemplateQueryBuilder(source, ScriptService.ScriptType.INLINE, singletonMap("name", "token")))
.execute().actionGet();
assertThat(response.isTimedOut(), is(false));
assertThat(response.getHits().hits().length, is(1));
@ -119,7 +117,7 @@ public class SecurityCachePermissionIT extends SecurityIntegTestCase {
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER,
new SecuredString("changeme".toCharArray()))))
.prepareSearch("data").setTypes("a")
.setQuery(QueryBuilders.templateQuery(source, singletonMap("name", "token")))
.setQuery(new TemplateQueryBuilder(source, ScriptService.ScriptType.INLINE, singletonMap("name", "token")))
.execute().actionGet());
assertThat(e.toString(), containsString("ElasticsearchSecurityException[action"));
assertThat(e.toString(), containsString("unauthorized"));

View File

@ -7,7 +7,7 @@ dependencies {
integTest {
cluster {
setting 'script.inline', 'true'
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
plugin ':x-plugins:elasticsearch:x-pack'
extraConfigFile 'x-pack/roles.yml', 'roles.yml'
[
test_admin: 'superuser',

View File

@ -14,7 +14,7 @@ project.sourceSets.test.output.dir(outputDir, builtBy: copyXPackPluginProps)
integTest {
cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
plugin ':x-plugins:elasticsearch:x-pack'
setupCommand 'setupDummyUser',
'bin/x-pack/users', 'useradd', 'test_user', '-p', 'changeme', '-r', 'superuser'
setupCommand 'setupTransportClientUser',

View File

@ -13,6 +13,7 @@ import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.transport.MockTransportClient;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.ESIntegTestCase;
@ -115,6 +116,6 @@ public class SecurityTransportClientIT extends ESIntegTestCase {
.put("cluster.name", clusterName)
.build();
return TransportClient.builder().settings(settings).addPlugin(XPackPlugin.class).build().addTransportAddress(publishAddress);
return new MockTransportClient(settings, XPackPlugin.class).addTransportAddress(publishAddress);
}
}

View File

@ -43,7 +43,7 @@ task buildZip(type:Zip, dependsOn: [jar]) {
task integTest(type: org.elasticsearch.gradle.test.RestIntegTestTask, dependsOn: buildZip) {
cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
plugin ':x-plugins:elasticsearch:x-pack'
setting 'xpack.security.authc.realms.custom.order', '0'
setting 'xpack.security.authc.realms.custom.type', 'custom'
setting 'xpack.security.authc.realms.esusers.order', '1'

View File

@ -7,14 +7,27 @@ package org.elasticsearch.example;
import org.elasticsearch.example.realm.CustomAuthenticationFailureHandler;
import org.elasticsearch.example.realm.CustomRealm;
import org.elasticsearch.example.realm.CustomRealmFactory;
import org.elasticsearch.xpack.security.authc.AuthenticationModule;
import org.elasticsearch.xpack.extensions.XPackExtension;
import org.elasticsearch.xpack.security.authc.Realm;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
public class ExampleRealmExtension extends XPackExtension {
static {
// check that the extension's policy works.
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
System.getSecurityManager().checkPrintJobAccess();
return null;
});
}
@Override
public String name() {
return "custom realm example";
@ -26,12 +39,16 @@ public class ExampleRealmExtension extends XPackExtension {
}
public void onModule(AuthenticationModule authenticationModule) {
authenticationModule.addCustomRealm(CustomRealm.TYPE, CustomRealmFactory.class);
authenticationModule.setAuthenticationFailureHandler(CustomAuthenticationFailureHandler.class);
// check that the extension's policy works.
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
System.getSecurityManager().checkPrintJobAccess();
return null;
});
}
@Override
public Map<String, Realm.Factory> getRealms() {
return Collections.singletonMap(CustomRealm.TYPE, CustomRealm::new);
}
@Override
public Collection<String> getRestHeaders() {
return Arrays.asList(CustomRealm.USER_HEADER, CustomRealm.PW_HEADER);
}
}

View File

@ -13,12 +13,12 @@ import org.elasticsearch.xpack.security.authc.RealmConfig;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
public class CustomRealm extends Realm<UsernamePasswordToken> {
public class CustomRealm extends Realm {
public static final String TYPE = "custom";
static final String USER_HEADER = "User";
static final String PW_HEADER = "Password";
public static final String USER_HEADER = "User";
public static final String PW_HEADER = "Password";
static final String KNOWN_USER = "custom_user";
static final String KNOWN_PW = "changeme";
@ -46,7 +46,8 @@ public class CustomRealm extends Realm<UsernamePasswordToken> {
}
@Override
public User authenticate(UsernamePasswordToken token) {
public User authenticate(AuthenticationToken authToken) {
UsernamePasswordToken token = (UsernamePasswordToken)authToken;
final String actualUser = token.principal();
if (KNOWN_USER.equals(actualUser) && SecuredString.constantTimeEquals(token.credentials(), KNOWN_PW)) {
return new User(actualUser, ROLES);

View File

@ -1,30 +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.example.realm;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.xpack.security.authc.Realm;
import org.elasticsearch.xpack.security.authc.RealmConfig;
public class CustomRealmFactory extends Realm.Factory<CustomRealm> {
@Inject
public CustomRealmFactory(RestController controller) {
super(CustomRealm.TYPE, false);
controller.registerRelevantHeaders(CustomRealm.USER_HEADER, CustomRealm.PW_HEADER);
}
@Override
public CustomRealm create(RealmConfig config) {
return new CustomRealm(config);
}
@Override
public CustomRealm createDefault(String name) {
return null;
}
}

View File

@ -20,7 +20,9 @@ import org.elasticsearch.env.Environment;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.XPackTransportClient;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@ -77,7 +79,7 @@ public class CustomRealmIT extends ESIntegTestCase {
.put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER)
.put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW)
.build();
try (TransportClient client = TransportClient.builder().settings(settings).addPlugin(XPackPlugin.class).build()) {
try (TransportClient client = new XPackTransportClient(settings)) {
client.addTransportAddress(publishAddress);
ClusterHealthResponse response = client.admin().cluster().prepareHealth().execute().actionGet();
assertThat(response.isTimedOut(), is(false));
@ -97,7 +99,7 @@ public class CustomRealmIT extends ESIntegTestCase {
.put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER + randomAsciiOfLength(1))
.put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW)
.build();
try (TransportClient client = TransportClient.builder().addPlugin(XPackPlugin.class).settings(settings).build()) {
try (TransportClient client = new XPackTransportClient(settings)) {
client.addTransportAddress(publishAddress);
client.admin().cluster().prepareHealth().execute().actionGet();
fail("authentication failure should have resulted in a NoNodesAvailableException");

View File

@ -7,7 +7,7 @@ dependencies {
integTest {
cluster {
setting 'script.inline', 'true'
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
plugin ':x-plugins:elasticsearch:x-pack'
extraConfigFile 'x-pack/roles.yml', 'roles.yml'
[
test_admin: 'superuser',

View File

@ -118,6 +118,13 @@ public class MigrateToolIT extends MigrateToolTestCase {
String token = basicAuthHeaderValue("bob", new SecuredString("changeme".toCharArray()));
// Create "index1" index and try to search from it as "bob"
client.filterWithHeader(Collections.singletonMap("Authorization", token)).admin().indices().prepareCreate("index1").get();
// Wait for the index to be ready so it doesn't fail if no shards are initialized
client.admin().cluster().health(Requests.clusterHealthRequest("index1")
.timeout(TimeValue.timeValueSeconds(30))
.waitForYellowStatus()
.waitForEvents(Priority.LANGUID)
.waitForRelocatingShards(0))
.actionGet();
SearchResponse searchResp = client.filterWithHeader(Collections.singletonMap("Authorization", token)).prepareSearch("index1").get();
}
}

View File

@ -14,9 +14,8 @@ import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.node.internal.InternalSettingsPreparer;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.xpack.XPackTransportClient;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
@ -25,10 +24,8 @@ import org.junit.BeforeClass;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.file.Path;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomAsciiOfLength;
import static org.hamcrest.Matchers.notNullValue;
/**
@ -45,6 +42,7 @@ import static org.hamcrest.Matchers.notNullValue;
* your test.
*/
@LuceneTestCase.SuppressSysoutChecks(bugUrl = "we log a lot on purpose")
@ESIntegTestCase.SuppressLocalMode
public abstract class MigrateToolTestCase extends LuceneTestCase {
/**
@ -77,13 +75,9 @@ public abstract class MigrateToolTestCase extends LuceneTestCase {
.put("client.transport.ignore_cluster_name", true)
.put("path.home", tempDir)
.put(Security.USER_SETTING.getKey(), "transport_user:changeme")
.put("node.mode", "network") // we require network here!
.build();
TransportClient.Builder transportClientBuilder = TransportClient.builder()
.addPlugin(XPackPlugin.class)
.settings(clientSettings);
TransportClient client = transportClientBuilder.build().addTransportAddresses(transportAddresses);
TransportClient client = new XPackTransportClient(clientSettings).addTransportAddresses(transportAddresses);
logger.info("--> Elasticsearch Java TransportClient started");

View File

@ -15,7 +15,7 @@ integTest {
dependsOn copyGraphRestTests
cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
plugin ':x-plugins:elasticsearch:x-pack'
extraConfigFile 'x-pack/roles.yml', 'roles.yml'
setupCommand 'setupTestAdminUser',
'bin/x-pack/users', 'useradd', 'test_admin', '-p', 'changeme', '-r', 'superuser'

View File

@ -17,7 +17,7 @@ subprojects {
cluster {
systemProperty 'es.logger.level', 'TRACE'
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
plugin ':x-plugins:elasticsearch:x-pack'
setting 'xpack.monitoring.collection.interval', '3s'
extraConfigFile 'x-pack/roles.yml', '../roles.yml'
setupCommand 'setupTestAdminUser',

View File

@ -147,7 +147,7 @@ processTestResources.dependsOn(
ext.pluginsCount = 1 // we install xpack explicitly
project.rootProject.subprojects.findAll { it.path.startsWith(':plugins:') }.each { subproj ->
// need to get a non-decorated project object, so must re-lookup the project by path
integTest.cluster.plugin(subproj.name, project(subproj.path))
integTest.cluster.plugin(subproj.path)
pluginsCount += 1
}
@ -166,7 +166,7 @@ integTest {
setting 'xpack.security.ssl.keystore.path', nodeKeystore.name
setting 'xpack.security.ssl.keystore.password', 'keypass'
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
plugin ':x-plugins:elasticsearch:x-pack'
// copy keystores into config/
extraConfigFile nodeKeystore.name, nodeKeystore

View File

@ -9,11 +9,12 @@ import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.transport.netty.SecurityNettyTransport;
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import org.junit.After;
@ -49,7 +50,6 @@ public class SmokeTestMonitoringWithSecurityIT extends ESIntegTestCase {
private static final String USER = "test_user";
private static final String PASS = "changeme";
private static final String KEYSTORE_PASS = "keypass";
private static final String MONITORING_PATTERN = ".monitoring-*";
@Override
@ -61,9 +61,10 @@ public class SmokeTestMonitoringWithSecurityIT extends ESIntegTestCase {
protected Settings externalClusterClientSettings() {
return Settings.builder()
.put(Security.USER_SETTING.getKey(), USER + ":" + PASS)
.put(SecurityNettyTransport.SSL_SETTING.getKey(), true)
.put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
.put("xpack.security.ssl.keystore.path", clientKeyStore)
.put("xpack.security.ssl.keystore.password", KEYSTORE_PASS)
.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME)
.build();
}

View File

@ -9,13 +9,13 @@ dependencies {
ext.pluginsCount = 1 // we install xpack explicitly
project.rootProject.subprojects.findAll { it.path.startsWith(':plugins:') }.each { subproj ->
// need to get a non-decorated project object, so must re-lookup the project by path
integTest.cluster.plugin(subproj.name, project(subproj.path))
integTest.cluster.plugin(subproj.path)
pluginsCount += 1
}
integTest {
cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
plugin ':x-plugins:elasticsearch:x-pack'
setupCommand 'setupDummyUser',
'bin/x-pack/users', 'useradd', 'test_user', '-p', 'changeme', '-r', 'superuser'

View File

@ -7,7 +7,7 @@ dependencies {
integTest {
cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
plugin ':x-plugins:elasticsearch:x-pack'
setting 'script.inline', 'true'
setting 'xpack.security.enabled', 'false'
setting 'xpack.monitoring.enabled', 'false'

View File

@ -7,7 +7,7 @@ dependencies {
integTest {
cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
plugin ':x-plugins:elasticsearch:x-pack'
setting 'xpack.security.enabled', 'false'
setting 'xpack.monitoring.enabled', 'false'
setting 'http.port', '9400'

View File

@ -6,37 +6,31 @@
package org.elasticsearch.smoketest;
import com.fasterxml.jackson.core.io.JsonStringEncoder;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.env.Environment;
import org.elasticsearch.script.ScriptContextRegistry;
import org.elasticsearch.script.ScriptEngineRegistry;
import org.elasticsearch.script.ScriptEngineService;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptSettings;
import org.elasticsearch.script.mustache.MustacheScriptEngineService;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.common.ScriptServiceProxy;
import org.elasticsearch.xpack.common.text.DefaultTextTemplateEngine;
import org.elasticsearch.xpack.common.text.TextTemplate;
import org.elasticsearch.xpack.common.text.TextTemplateEngine;
import org.elasticsearch.xpack.watcher.support.WatcherScript;
import org.junit.Before;
import org.mockito.Mockito;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
@ -50,7 +44,7 @@ public class WatcherTemplateTests extends ESTestCase {
Settings setting = Settings.builder().put(ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING, true).build();
Environment environment = Mockito.mock(Environment.class);
ResourceWatcherService resourceWatcherService = Mockito.mock(ResourceWatcherService.class);
ScriptContextRegistry registry = new ScriptContextRegistry(Collections.singletonList(ScriptServiceProxy.INSTANCE));
ScriptContextRegistry registry = new ScriptContextRegistry(Collections.singletonList(WatcherScript.CTX_PLUGIN));
ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(
Collections.singleton(new MustacheScriptEngineService(setting))
@ -58,7 +52,7 @@ public class WatcherTemplateTests extends ESTestCase {
ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, registry);
ScriptService scriptService = new ScriptService(setting, environment, resourceWatcherService, scriptEngineRegistry,
registry, scriptSettings);
engine = new DefaultTextTemplateEngine(Settings.EMPTY, ScriptServiceProxy.of(scriptService));
engine = new DefaultTextTemplateEngine(Settings.EMPTY, scriptService);
}
public void testEscaping() throws Exception {

View File

@ -7,7 +7,7 @@ dependencies {
integTest {
cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
plugin ':x-plugins:elasticsearch:x-pack'
setting 'script.inline', 'true'
setting 'xpack.security.enabled', 'false'
setting 'xpack.monitoring.enabled', 'false'

View File

@ -19,7 +19,7 @@ integTest {
'getting_started/10_monitor_cluster_health/Getting started - Monitor cluster health'].join(',')
cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
plugin ':x-plugins:elasticsearch:x-pack'
extraConfigFile 'x-pack/roles.yml', 'roles.yml'
setupCommand 'setupTestAdminUser',
'bin/x-pack/users', 'useradd', 'test_admin', '-p', 'changeme', '-r', 'superuser'

View File

@ -0,0 +1,14 @@
apply plugin: 'elasticsearch.rest-test'
dependencies {
testCompile project(path: ':x-plugins:elasticsearch:x-pack', configuration: 'runtime')
}
integTest {
cluster {
plugin ':x-plugins:elasticsearch:x-pack'
setting 'xpack.security.enabled', 'false'
setting 'xpack.monitoring.enabled', 'false'
setting 'http.port', '9400'
}
}

View File

@ -0,0 +1,42 @@
/*
* 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.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.parser.RestTestParseException;
import org.junit.After;
import org.junit.Before;
import java.io.IOException;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
/** Runs rest tests against external cluster */
public class WatcherGettingStartedIT extends ESRestTestCase {
public WatcherGettingStartedIT(@Name("yaml") RestTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException {
return ESRestTestCase.createParameters(0, 1);
}
@Before
public void startWatcher() throws Exception {
getAdminExecutionContext().callApi("xpack.watcher.start", emptyMap(), emptyList(), emptyMap());
}
@After
public void stopWatcher() throws Exception {
getAdminExecutionContext().callApi("xpack.watcher.stop", emptyMap(), emptyList(), emptyMap());
}
}

View File

@ -1,3 +1,6 @@
# This test has been moved out of the regular tests as it requires Elasticsearch to run on port 9400
# That is a no-go for the clients testing, who could start Elasticsearch on arbitrary ports
#
---
setup:
- do:

View File

@ -27,8 +27,9 @@ dependencies {
testCompile project(':x-plugins:elasticsearch:license:licensor')
// security deps
compile project(path: ':modules:transport-netty3', configuration: 'runtime')
compile 'dk.brics.automaton:automaton:1.11-8'
compile 'com.unboundid:unboundid-ldapsdk:2.3.8'
compile 'com.unboundid:unboundid-ldapsdk:3.1.1'
compile 'org.bouncycastle:bcprov-jdk15on:1.54'
compile 'org.bouncycastle:bcpkix-jdk15on:1.54'
testCompile 'com.google.jimfs:jimfs:1.1'

View File

@ -9,6 +9,7 @@ import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.inject.util.Providers;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.ActionPlugin;
@ -43,15 +44,12 @@ public class Graph extends Plugin implements ActionPlugin {
}
public Collection<Module> createGuiceModules() {
return Collections.singletonList(new GraphModule(enabled, transportClientMode));
}
@Override
public Collection<Class<? extends LifecycleComponent>> getGuiceServiceClasses() {
if (enabled == false|| transportClientMode) {
return Collections.emptyList();
}
return Collections.singletonList(GraphLicensee.class);
return Collections.singletonList(b -> {
XPackPlugin.bindFeatureSet(b, GraphFeatureSet.class);
if (transportClientMode) {
b.bind(GraphLicensee.class).toProvider(Providers.of(null));
}
});
}
@Override

View File

@ -6,21 +6,17 @@
package org.elasticsearch.xpack.graph;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.core.License.OperationMode;
import org.elasticsearch.license.plugin.core.AbstractLicenseeComponent;
import org.elasticsearch.license.plugin.core.LicenseState;
import org.elasticsearch.license.plugin.core.LicenseeRegistry;
public class GraphLicensee extends AbstractLicenseeComponent<GraphLicensee> {
public class GraphLicensee extends AbstractLicenseeComponent {
public static final String ID = Graph.NAME;
@Inject
public GraphLicensee(Settings settings, LicenseeRegistry clientService) {
super(settings, ID, clientService);
public GraphLicensee(Settings settings) {
super(settings, ID);
}
@Override
@ -31,17 +27,15 @@ public class GraphLicensee extends AbstractLicenseeComponent<GraphLicensee> {
}
@Override
public String[] acknowledgmentMessages(License currentLicense, License newLicense) {
switch (newLicense.operationMode()) {
public String[] acknowledgmentMessages(OperationMode currentMode, OperationMode newMode) {
switch (newMode) {
case BASIC:
case STANDARD:
case GOLD:
if (currentLicense != null) {
switch (currentLicense.operationMode()) {
case TRIAL:
case PLATINUM:
return new String[] { "Graph will be disabled" };
}
switch (currentMode) {
case TRIAL:
case PLATINUM:
return new String[] { "Graph will be disabled" };
}
break;
}

View File

@ -1,35 +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.graph;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.util.Providers;
import org.elasticsearch.xpack.XPackPlugin;
/**
*
*/
public class GraphModule extends AbstractModule {
private final boolean enabled;
private final boolean transportClientNode;
public GraphModule(boolean enabled, boolean transportClientNode) {
this.enabled = enabled;
this.transportClientNode = transportClientNode;
}
@Override
protected void configure() {
XPackPlugin.bindFeatureSet(binder(), GraphFeatureSet.class);
if (enabled && transportClientNode == false) {
bind(GraphLicensee.class).asEagerSingleton();
} else {
bind(GraphLicensee.class).toProvider(Providers.of(null));
}
}
}

View File

@ -14,114 +14,81 @@ import static org.hamcrest.Matchers.is;
public class LicenseTests extends AbstractLicenseeTestCase {
private SimpleLicenseeRegistry licenseeRegistry = new SimpleLicenseeRegistry();
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY);
public void testPlatinumTrialLicenseCanDoEverything() throws Exception {
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
setOperationMode(graphLicensee, randomTrialOrPlatinumMode());
assertLicensePlatinumTrialBehaviour(graphLicensee);
}
public void testBasicLicenseIsDisabled() throws Exception {
licenseeRegistry.setOperationMode(OperationMode.BASIC);
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
setOperationMode(graphLicensee, OperationMode.BASIC);
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
}
public void testStandardLicenseIsDisabled() throws Exception {
licenseeRegistry.setOperationMode(OperationMode.STANDARD);
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
setOperationMode(graphLicensee, OperationMode.STANDARD);
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
}
public void testNoLicenseDoesNotWork() {
licenseeRegistry.setOperationMode(OperationMode.BASIC);
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
licenseeRegistry.disable();
setOperationMode(graphLicensee, OperationMode.BASIC);
disable(graphLicensee);
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
}
public void testExpiredPlatinumTrialLicenseIsRestricted() throws Exception {
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
licenseeRegistry.disable();
setOperationMode(graphLicensee, randomTrialOrPlatinumMode());
disable(graphLicensee);
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
}
public void testUpgradingFromBasicLicenseWorks() {
licenseeRegistry.setOperationMode(OperationMode.BASIC);
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
setOperationMode(graphLicensee, OperationMode.BASIC);
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
setOperationMode(graphLicensee, randomTrialOrPlatinumMode());
assertLicensePlatinumTrialBehaviour(graphLicensee);
}
public void testDowngradingToBasicLicenseWorks() {
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
setOperationMode(graphLicensee, randomTrialOrPlatinumMode());
assertLicensePlatinumTrialBehaviour(graphLicensee);
licenseeRegistry.setOperationMode(OperationMode.BASIC);
setOperationMode(graphLicensee, OperationMode.BASIC);
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
}
public void testUpgradingFromStandardLicenseWorks() {
licenseeRegistry.setOperationMode(OperationMode.STANDARD);
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
setOperationMode(graphLicensee, OperationMode.STANDARD);
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
setOperationMode(graphLicensee, randomTrialOrPlatinumMode());
assertLicensePlatinumTrialBehaviour(graphLicensee);
}
public void testDowngradingToStandardLicenseWorks() {
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
setOperationMode(graphLicensee, randomTrialOrPlatinumMode());
assertLicensePlatinumTrialBehaviour(graphLicensee);
licenseeRegistry.setOperationMode(OperationMode.STANDARD);
setOperationMode(graphLicensee, OperationMode.STANDARD);
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
}
public void testDowngradingToGoldLicenseWorks() {
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
setOperationMode(graphLicensee, randomTrialOrPlatinumMode());
assertLicensePlatinumTrialBehaviour(graphLicensee);
licenseeRegistry.setOperationMode(OperationMode.GOLD);
setOperationMode(graphLicensee, OperationMode.GOLD);
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
}
public void testUpgradingExpiredLicenseWorks() {
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
licenseeRegistry.disable();
setOperationMode(graphLicensee, randomTrialOrPlatinumMode());
disable(graphLicensee);
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
setOperationMode(graphLicensee, randomTrialOrPlatinumMode());
assertLicensePlatinumTrialBehaviour(graphLicensee);
}

View File

@ -8,11 +8,11 @@ package org.elasticsearch.license.plugin;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseAction;
import org.elasticsearch.license.plugin.action.delete.TransportDeleteLicenseAction;
import org.elasticsearch.license.plugin.action.get.GetLicenseAction;
@ -26,6 +26,13 @@ import org.elasticsearch.license.plugin.rest.RestGetLicenseAction;
import org.elasticsearch.license.plugin.rest.RestPutLicenseAction;
import org.elasticsearch.plugins.ActionPlugin;
import org.elasticsearch.rest.RestHandler;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.graph.GraphLicensee;
import org.elasticsearch.xpack.monitoring.MonitoringLicensee;
import org.elasticsearch.xpack.security.SecurityLicenseState;
import org.elasticsearch.xpack.security.SecurityLicensee;
import org.elasticsearch.xpack.support.clock.Clock;
import org.elasticsearch.xpack.watcher.WatcherLicensee;
import java.util.Arrays;
import java.util.Collection;
@ -40,19 +47,24 @@ import static org.elasticsearch.xpack.XPackPlugin.transportClientMode;
public class Licensing implements ActionPlugin {
public static final String NAME = "license";
private final boolean isTransportClient;
protected final Settings settings;
protected final boolean isTransportClient;
private final boolean isTribeNode;
static {
MetaData.registerPrototype(LicensesMetaData.TYPE, LicensesMetaData.PROTO);
}
@Inject
public Licensing(Settings settings) {
this.settings = settings;
isTransportClient = transportClientMode(settings);
isTribeNode = isTribeNode(settings);
}
public Collection<Module> nodeModules() {
return Collections.emptyList();
}
@Override
public List<ActionHandler<? extends ActionRequest<?>, ? extends ActionResponse>> getActions() {
if (isTribeNode) {
@ -73,18 +85,18 @@ public class Licensing implements ActionPlugin {
RestDeleteLicenseAction.class);
}
public Collection<Class<? extends LifecycleComponent>> nodeServices() {
if (isTransportClient == false && isTribeNode == false) {
return Collections.<Class<? extends LifecycleComponent>>singletonList(LicensesService.class);
}
return Collections.emptyList();
}
public Collection<Object> createComponents(ClusterService clusterService, Clock clock, Environment environment,
ResourceWatcherService resourceWatcherService,
SecurityLicenseState securityLicenseState) {
SecurityLicensee securityLicensee = new SecurityLicensee(settings, securityLicenseState);
WatcherLicensee watcherLicensee = new WatcherLicensee(settings);
MonitoringLicensee monitoringLicensee = new MonitoringLicensee(settings);
GraphLicensee graphLicensee = new GraphLicensee(settings);
LicensesService licensesService = new LicensesService(settings, clusterService, clock,
environment, resourceWatcherService,
Arrays.asList(securityLicensee, watcherLicensee, monitoringLicensee, graphLicensee));
public Collection<Module> nodeModules() {
if (isTransportClient == false && isTribeNode == false) {
return Collections.<Module>singletonList(new LicensingModule());
}
return Collections.emptyList();
return Arrays.asList(licensesService, securityLicenseState, securityLicensee, watcherLicensee, monitoringLicensee, graphLicensee);
}
public List<Setting<?>> getSettings() {

View File

@ -1,24 +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.plugin;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.license.core.LicenseVerifier;
import org.elasticsearch.license.plugin.core.LicenseeRegistry;
import org.elasticsearch.license.plugin.core.LicensesManagerService;
import org.elasticsearch.license.plugin.core.LicensesService;
public class LicensingModule extends AbstractModule {
@Override
protected void configure() {
bind(LicenseVerifier.class).asEagerSingleton();
bind(LicensesService.class).asEagerSingleton();
bind(LicenseeRegistry.class).to(LicensesService.class);
bind(LicensesManagerService.class).to(LicensesService.class);
}
}

View File

@ -9,28 +9,28 @@ import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.master.TransportMasterNodeReadAction;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.block.ClusterBlockException;
import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.plugin.core.LicensesManagerService;
import org.elasticsearch.license.plugin.core.LicensesService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
public class TransportGetLicenseAction extends TransportMasterNodeReadAction<GetLicenseRequest, GetLicenseResponse> {
private final LicensesManagerService licensesManagerService;
private final LicensesService licensesService;
@Inject
public TransportGetLicenseAction(Settings settings, TransportService transportService, ClusterService clusterService,
LicensesManagerService licensesManagerService, ThreadPool threadPool, ActionFilters actionFilters,
LicensesService licensesService, ThreadPool threadPool, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver) {
super(settings, GetLicenseAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver,
GetLicenseRequest::new);
this.licensesManagerService = licensesManagerService;
this.licensesService = licensesService;
}
@Override
@ -51,6 +51,6 @@ public class TransportGetLicenseAction extends TransportMasterNodeReadAction<Get
@Override
protected void masterOperation(final GetLicenseRequest request, ClusterState state, final ActionListener<GetLicenseResponse>
listener) throws ElasticsearchException {
listener.onResponse(new GetLicenseResponse(licensesManagerService.getLicense()));
listener.onResponse(new GetLicenseResponse(licensesService.getLicense()));
}
}

View File

@ -5,6 +5,7 @@
*/
package org.elasticsearch.license.plugin.core;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.component.AbstractLifecycleComponent;
import org.elasticsearch.common.settings.Settings;
@ -14,33 +15,17 @@ import java.util.concurrent.CopyOnWriteArrayList;
/**
* A supporting base class for injectable Licensee components.
*/
public abstract class AbstractLicenseeComponent<T extends AbstractLicenseeComponent<T>> extends AbstractLifecycleComponent
implements Licensee {
public abstract class AbstractLicenseeComponent extends AbstractComponent implements Licensee {
private final String id;
private final LicenseeRegistry clientService;
private final List<Listener> listeners = new CopyOnWriteArrayList<>();
// we initialize the licensee state to enabled with trial operation mode
protected volatile Status status = Status.ENABLED;
protected AbstractLicenseeComponent(Settings settings, String id, LicenseeRegistry clientService) {
protected AbstractLicenseeComponent(Settings settings, String id) {
super(settings);
this.id = id;
this.clientService = clientService;
}
@Override
protected void doStart() {
clientService.register(this);
}
@Override
protected void doStop() {
}
@Override
protected void doClose() {
}
@Override

View File

@ -8,8 +8,6 @@ package org.elasticsearch.license.plugin.core;
import org.elasticsearch.license.core.License;
import org.elasticsearch.xpack.scheduler.SchedulerEngine;
import static org.elasticsearch.license.plugin.core.LicensesService.GRACE_PERIOD_DURATION;
import static org.elasticsearch.license.plugin.core.LicensesService.getLicenseState;
public class LicenseSchedule implements SchedulerEngine.Schedule {
@ -22,12 +20,12 @@ public class LicenseSchedule implements SchedulerEngine.Schedule {
@Override
public long nextScheduledTimeAfter(long startTime, long time) {
long nextScheduledTime = -1;
switch (getLicenseState(license, time)) {
switch (LicenseState.resolve(license, time)) {
case ENABLED:
nextScheduledTime = license.expiryDate();
break;
case GRACE_PERIOD:
nextScheduledTime = license.expiryDate() + GRACE_PERIOD_DURATION.getMillis();
nextScheduledTime = license.expiryDate() + LicenseState.GRACE_PERIOD_DURATION.getMillis();
break;
case DISABLED:
if (license.issueDate() > time) {
@ -42,4 +40,4 @@ public class LicenseSchedule implements SchedulerEngine.Schedule {
}
return nextScheduledTime;
}
}
}

View File

@ -5,6 +5,11 @@
*/
package org.elasticsearch.license.plugin.core;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.License;
import static org.elasticsearch.license.plugin.core.LicensesService.days;
/**
* States of a registered licensee
* based on the current license
@ -38,5 +43,26 @@ public enum LicenseState {
* changes to {@link #ENABLED}, otherwise
* remains unchanged
*/
DISABLED
DISABLED;
/**
* Duration of grace period after a license has expired
*/
public static final TimeValue GRACE_PERIOD_DURATION = days(7);
public static LicenseState resolve(final License license, long time) {
if (license == null) {
return DISABLED;
}
if (license.issueDate() > time) {
return DISABLED;
}
if (license.expiryDate() > time) {
return ENABLED;
}
if ((license.expiryDate() + GRACE_PERIOD_DURATION.getMillis()) > time) {
return GRACE_PERIOD;
}
return DISABLED;
}
}

View File

@ -5,10 +5,10 @@
*/
package org.elasticsearch.license.plugin.core;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.core.License.OperationMode;
import java.util.Locale;
import java.util.Objects;
public interface Licensee {
@ -26,11 +26,10 @@ public interface Licensee {
/**
* Messages to be returned when
* installing <code>newLicense</code>
* when <code>currentLicense</code> is
* active
* changing from current operation mode
* to new operation mode
*/
String[] acknowledgmentMessages(License currentLicense, License newLicense);
String[] acknowledgmentMessages(OperationMode currentMode, OperationMode newMode);
/**
* Notifies when a new license is activated
@ -85,6 +84,20 @@ public interface Licensee {
return licenseState;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Status status = (Status) o;
return Objects.equals(mode, status.mode) && Objects.equals(licenseState, status.licenseState);
}
@Override
public int hashCode() {
return Objects.hash(mode, licenseState);
}
@Override
public String toString() {
switch (licenseState) {

View File

@ -1,14 +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.plugin.core;
public interface LicenseeRegistry {
/**
* Registers a licensee for license notifications
*/
void register(Licensee licensee);
}

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.
*/
package org.elasticsearch.license.plugin.core;
import org.elasticsearch.license.core.License;
import java.util.List;
public interface LicensesManagerService {
/**
* @return current {@link LicenseState}
*/
LicenseState licenseState();
/**
* @return the currently active license, or {@code null} if no license is currently installed
*/
License getLicense();
}

View File

@ -15,29 +15,24 @@ import org.elasticsearch.cluster.ClusterStateListener;
import org.elasticsearch.cluster.ClusterStateUpdateTask;
import org.elasticsearch.cluster.ack.ClusterStateUpdateResponse;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.component.AbstractLifecycleComponent;
import org.elasticsearch.common.component.Lifecycle;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.joda.Joda;
import org.elasticsearch.common.logging.LoggerMessageFormat;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.env.Environment;
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.license.plugin.action.delete.DeleteLicenseRequest;
import org.elasticsearch.license.plugin.action.put.PutLicenseRequest;
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.EmptyTransportResponseHandler;
import org.elasticsearch.transport.TransportChannel;
import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.transport.TransportRequestHandler;
import org.elasticsearch.transport.TransportResponse;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.scheduler.SchedulerEngine;
import org.elasticsearch.xpack.support.clock.Clock;
@ -48,42 +43,31 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
/**
* Service responsible for managing {@link LicensesMetaData}
* Interfaces through which this is exposed are:
* - LicensesManagerService - responsible for managing signed and one-time-trial licenses
* - LicensesClientService - responsible for listener registration of consumer plugin(s)
* <p>
* Registration Scheme:
* <p>
* A consumer plugin is registered with {@link LicenseeRegistry#register(Licensee)}
* This method can be called at any time during the life-cycle of the consumer plugin.
* If the listener can not be registered immediately, it is queued up and registered on the first clusterChanged event with
* no {@link org.elasticsearch.gateway.GatewayService#STATE_NOT_RECOVERED_BLOCK} block
* Upon successful registration, the listeners are notified appropriately using the notification scheme
* <p>
* Notification Scheme:
* <p>
* All registered listeners are notified of the current license upon registration or when a new license is installed in the cluster state.
* When a new license is notified as enabled to the registered listener, a notification is scheduled at the time of license expiry.
* Registered listeners are notified using {@link #onUpdate(LicensesMetaData)}
*/
public class LicensesService extends AbstractLifecycleComponent implements ClusterStateListener, LicensesManagerService,
LicenseeRegistry, SchedulerEngine.Listener {
public class LicensesService extends AbstractLifecycleComponent implements ClusterStateListener, SchedulerEngine.Listener {
public static final String REGISTER_TRIAL_LICENSE_ACTION_NAME = "internal:plugin/license/cluster/register_trial_license";
// pkg private for tests
static final TimeValue TRIAL_LICENSE_DURATION = TimeValue.timeValueHours(30 * 24);
private final ClusterService clusterService;
private final TransportService transportService;
/**
* Currently active consumers to notify to
*/
private final List<InternalLicensee> registeredLicensees = new CopyOnWriteArrayList<>();
private final List<InternalLicensee> registeredLicensees;
/**
* Currently active license
@ -92,46 +76,39 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
private SchedulerEngine scheduler;
private final Clock clock;
/**
* File watcher for operation mode changes
*/
private final OperationModeFileWatcher operationModeFileWatcher;
/**
* Callbacks to notify relative to license expiry
*/
private List<ExpirationCallback> expirationCallbacks = new ArrayList<>();
/**
* Duration of generated trial license
*/
private TimeValue trialLicenseDuration = TimeValue.timeValueHours(30 * 24);
/**
* Max number of nodes licensed by generated trial license
*/
private int trialLicenseMaxNodes = 1000;
/**
* Duration of grace period after a license has expired
*/
public static final TimeValue GRACE_PERIOD_DURATION = days(7);
private static final String LICENSE_JOB = "licenseJob";
public static final String LICENSE_JOB = "licenseJob";
private static final FormatDateTimeFormatter DATE_FORMATTER = Joda.forPattern("EEEE, MMMMM dd, yyyy", Locale.ROOT);
private static final String ACKNOWLEDGEMENT_HEADER = "This license update requires acknowledgement. To acknowledge the license, " +
"please read the following messages and update the license again, this time with the \"acknowledge=true\" parameter:";
@Inject
public LicensesService(Settings settings, ClusterService clusterService, TransportService transportService, Clock clock) {
public LicensesService(Settings settings, ClusterService clusterService, Clock clock, Environment env,
ResourceWatcherService resourceWatcherService, List<Licensee> registeredLicensees) {
super(settings);
this.clusterService = clusterService;
this.transportService = transportService;
if (DiscoveryNode.isMasterNode(settings)) {
transportService.registerRequestHandler(REGISTER_TRIAL_LICENSE_ACTION_NAME, TransportRequest.Empty::new,
ThreadPool.Names.SAME, new RegisterTrialLicenseRequestHandler());
}
populateExpirationCallbacks();
this.clock = clock;
this.scheduler = new SchedulerEngine(clock);
this.registeredLicensees = registeredLicensees.stream().map(InternalLicensee::new).collect(Collectors.toList());
this.operationModeFileWatcher = new OperationModeFileWatcher(resourceWatcherService,
XPackPlugin.resolveConfigFile(env, "license_mode"), logger, () -> notifyLicensees(getLicense()));
this.scheduler.register(this);
populateExpirationCallbacks();
}
private void populateExpirationCallbacks() {
@ -256,7 +233,8 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
"override the current license?"});
}
for (InternalLicensee licensee : registeredLicensees) {
String[] listenerAcknowledgeMessages = licensee.acknowledgmentMessages(currentLicense, newLicense);
String[] listenerAcknowledgeMessages = licensee.acknowledgmentMessages(
currentLicense.operationMode(), newLicense.operationMode());
if (listenerAcknowledgeMessages.length > 0) {
acknowledgeMessages.put(licensee.id(), listenerAcknowledgeMessages);
}
@ -332,17 +310,14 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
});
}
@Override
public LicenseState licenseState() {
if (registeredLicensees.size() > 0) {
return registeredLicensees.get(0).currentLicenseState;
} else {
final License license = getLicense(clusterService.state().metaData().custom(LicensesMetaData.TYPE));
return getLicenseState(license, clock.millis());
public Licensee.Status licenseeStatus() {
final License license = getLicense();
if (license == null) {
return Licensee.Status.MISSING;
}
return new Licensee.Status(license.operationMode(), LicenseState.resolve(license, clock.millis()));
}
@Override
public License getLicense() {
final License license = getLicense(clusterService.state().metaData().custom(LicensesMetaData.TYPE));
return license == LicensesMetaData.LICENSE_TOMBSTONE ? null : license;
@ -354,7 +329,7 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
* has no signed/trial license
*/
private void registerTrialLicense() {
clusterService.submitStateUpdateTask("generate trial license for [" + trialLicenseDuration + "]", new ClusterStateUpdateTask() {
clusterService.submitStateUpdateTask("generate trial license for [" + TRIAL_LICENSE_DURATION + "]", new ClusterStateUpdateTask() {
@Override
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
LicensesMetaData licensesMetaData = newState.metaData().custom(LicensesMetaData.TYPE);
@ -376,7 +351,7 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
.issuedTo(clusterService.getClusterName().value())
.maxNodes(trialLicenseMaxNodes)
.issueDate(issueDate)
.expiryDate(issueDate + trialLicenseDuration.getMillis());
.expiryDate(issueDate + TRIAL_LICENSE_DURATION.getMillis());
License trialLicense = TrialLicense.create(specBuilder);
mdBuilder.putCustom(LicensesMetaData.TYPE, new LicensesMetaData(trialLicense));
return ClusterState.builder(currentState).metaData(mdBuilder).build();
@ -396,6 +371,7 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
protected void doStart() throws ElasticsearchException {
clusterService.add(this);
scheduler.start(Collections.emptyList());
registeredLicensees.forEach(x -> initLicensee(x.licensee));
}
@Override
@ -404,14 +380,12 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
scheduler.stop();
// clear all handlers
registeredLicensees.clear();
// clear current license
currentLicense.set(null);
}
@Override
protected void doClose() throws ElasticsearchException {
transportService.removeHandler(REGISTER_TRIAL_LICENSE_ACTION_NAME);
}
/**
@ -440,9 +414,10 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
}
// auto-generate license if no licenses ever existed
// this will trigger a subsequent cluster changed event
if (prevLicensesMetaData == null
&& (currentLicensesMetaData == null || currentLicensesMetaData.getLicense() == null)) {
requestTrialLicense(currentClusterState);
if (currentClusterState.getNodes().isLocalNodeElectedMaster() &&
prevLicensesMetaData == null &&
(currentLicensesMetaData == null || currentLicensesMetaData.getLicense() == null)) {
registerTrialLicense();
}
} else if (logger.isDebugEnabled()) {
logger.debug("skipped license notifications reason: [{}]", GatewayService.STATE_NOT_RECOVERED_BLOCK);
@ -458,45 +433,22 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
}
if (license != null) {
logger.debug("notifying [{}] listeners", registeredLicensees.size());
switch (getLicenseState(license, clock.millis())) {
final LicenseState licenseState = LicenseState.resolve(license, clock.millis());
Licensee.Status status = new Licensee.Status(license.operationMode(), licenseState);
for (InternalLicensee licensee : registeredLicensees) {
licensee.onChange(status);
}
switch (status.getLicenseState()) {
case ENABLED:
for (InternalLicensee licensee : registeredLicensees) {
licensee.onChange(license, LicenseState.ENABLED);
}
logger.debug("license [{}] - valid", license.uid());
break;
logger.debug("license [{}] - valid", license.uid()); break;
case GRACE_PERIOD:
for (InternalLicensee licensee : registeredLicensees) {
licensee.onChange(license, LicenseState.GRACE_PERIOD);
}
logger.warn("license [{}] - grace", license.uid());
break;
logger.warn("license [{}] - grace", license.uid()); break;
case DISABLED:
for (InternalLicensee licensee : registeredLicensees) {
licensee.onChange(license, LicenseState.DISABLED);
}
logger.warn("license [{}] - expired", license.uid());
break;
logger.warn("license [{}] - expired", license.uid()); break;
}
}
}
static LicenseState getLicenseState(final License license, long time) {
if (license == null) {
return LicenseState.DISABLED;
}
if (license.issueDate() > time) {
return LicenseState.DISABLED;
}
if (license.expiryDate() > time) {
return LicenseState.ENABLED;
}
if ((license.expiryDate() + GRACE_PERIOD_DURATION.getMillis()) > time) {
return LicenseState.GRACE_PERIOD;
}
return LicenseState.DISABLED;
}
/**
* Notifies registered licensees of license state change and/or new active license
* based on the license in <code>currentLicensesMetaData</code>.
@ -508,58 +460,49 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
// license can be null if the trial license is yet to be auto-generated
// in this case, it is a no-op
if (license != null) {
notifyLicensees(license);
if (license.equals(currentLicense.get()) == false) {
final License previousLicense = currentLicense.get();
if (license.equals(previousLicense) == false) {
currentLicense.set(license);
license.setOperationModeFileWatcher(operationModeFileWatcher);
scheduler.add(new SchedulerEngine.Job(LICENSE_JOB, new LicenseSchedule(license)));
for (ExpirationCallback expirationCallback : expirationCallbacks) {
scheduler.add(new SchedulerEngine.Job(expirationCallback.getId(),
(startTime, now) ->
expirationCallback.nextScheduledTimeForExpiry(license.expiryDate(), startTime, now)));
}
if (previousLicense != null) {
// remove operationModeFileWatcher to gc the old license object
previousLicense.removeOperationModeFileWatcher();
}
}
notifyLicensees(license);
}
}
@Override
public void register(Licensee licensee) {
for (final InternalLicensee existingLicensee : registeredLicensees) {
if (existingLicensee.id().equals(licensee.id())) {
throw new IllegalStateException("listener: [" + licensee.id() + "] has been already registered");
}
}
logger.debug("registering licensee [{}]", licensee.id());
registeredLicensees.add(new InternalLicensee(licensee));
private void initLicensee(Licensee licensee) {
logger.debug("initializing licensee [{}]", licensee.id());
final ClusterState clusterState = clusterService.state();
if (clusterService.lifecycleState() == Lifecycle.State.STARTED
&& clusterState.blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK) == false
&& clusterState.nodes().getMasterNode() != null) {
final LicensesMetaData currentMetaData = clusterState.metaData().custom(LicensesMetaData.TYPE);
if (currentMetaData == null || currentMetaData.getLicense() == null) {
if (clusterState.getNodes().isLocalNodeElectedMaster() &&
(currentMetaData == null || currentMetaData.getLicense() == null)) {
// triggers a cluster changed event
// eventually notifying the current licensee
requestTrialLicense(clusterState);
} else if (lifecycleState() == Lifecycle.State.STARTED) {
registerTrialLicense();
} else {
notifyLicensees(currentMetaData.getLicense());
}
}
}
private void requestTrialLicense(final ClusterState currentState) {
DiscoveryNode masterNode = currentState.nodes().getMasterNode();
if (masterNode == null) {
throw new IllegalStateException("master not available when registering auto-generated license");
}
transportService.sendRequest(masterNode,
REGISTER_TRIAL_LICENSE_ACTION_NAME, TransportRequest.Empty.INSTANCE, EmptyTransportResponseHandler.INSTANCE_SAME);
}
License getLicense(final LicensesMetaData metaData) {
if (metaData != null) {
License license = metaData.getLicense();
if (license == LicensesMetaData.LICENSE_TOMBSTONE) {
return license;
} else {
} else if (license != null) {
boolean autoGeneratedLicense = License.isAutoGeneratedLicense(license.signature());
if ((autoGeneratedLicense && TrialLicense.verify(license))
|| (!autoGeneratedLicense && LicenseVerifier.verifyLicense(license))) {
@ -574,9 +517,9 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
* Stores acknowledgement, expiration and license notification callbacks
* for a registered listener
*/
private class InternalLicensee {
volatile License currentLicense = null;
volatile LicenseState currentLicenseState = LicenseState.DISABLED;
private final class InternalLicensee {
volatile Licensee.Status currentStatus = Licensee.Status.MISSING;
private final Licensee licensee;
private InternalLicensee(Licensee licensee) {
@ -585,7 +528,7 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
@Override
public String toString() {
return "(listener: " + licensee.id() + ", state: " + currentLicenseState.name() + ")";
return "(listener: " + licensee.id() + ", state: " + currentStatus + ")";
}
public String id() {
@ -596,43 +539,21 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
return licensee.expirationMessages();
}
public String[] acknowledgmentMessages(License currentLicense, License newLicense) {
return licensee.acknowledgmentMessages(currentLicense, newLicense);
public String[] acknowledgmentMessages(License.OperationMode currentMode, License.OperationMode newMode) {
return licensee.acknowledgmentMessages(currentMode, newMode);
}
public void onChange(License license, LicenseState state) {
synchronized (this) {
if (currentLicense == null // not yet initialized
|| !currentLicense.equals(license) // current license has changed
|| currentLicenseState != state) { // same license but state has changed
logger.debug("licensee [{}] notified", licensee.id());
licensee.onChange(new Licensee.Status(license.operationMode(), state));
currentLicense = license;
currentLicenseState = state;
}
public synchronized void onChange(final Licensee.Status status) {
if (currentStatus == null // not yet initialized
|| !currentStatus.equals(status)) { // current license has changed
logger.debug("licensee [{}] notified", licensee.id());
licensee.onChange(status);
currentStatus = status;
}
}
public void onRemove() {
synchronized (this) {
if (currentLicense != null || currentLicenseState != LicenseState.DISABLED) {
currentLicense = null;
currentLicenseState = LicenseState.DISABLED;
licensee.onChange(Licensee.Status.MISSING);
}
}
}
}
/**
* Request handler for trial license generation to master
*/
private class RegisterTrialLicenseRequestHandler implements TransportRequestHandler<TransportRequest.Empty> {
@Override
public void messageReceived(TransportRequest.Empty empty, TransportChannel channel) throws Exception {
registerTrialLicense();
channel.sendResponse(TransportResponse.Empty.INSTANCE);
onChange(Licensee.Status.MISSING);
}
}
}

View File

@ -5,29 +5,39 @@
*/
package org.elasticsearch.license.plugin.rest;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseAction;
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseRequest;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.action.support.AcknowledgedRestListener;
import org.elasticsearch.xpack.XPackClient;
import org.elasticsearch.xpack.rest.XPackRestHandler;
import static org.elasticsearch.rest.RestRequest.Method.DELETE;
public class RestDeleteLicenseAction extends BaseRestHandler {
public class RestDeleteLicenseAction extends XPackRestHandler {
@Inject
public RestDeleteLicenseAction(Settings settings, RestController controller) {
super(settings);
controller.registerHandler(DELETE, "/_xpack/license", this);
// @deprecated Remove deprecations in 6.0
controller.registerWithDeprecatedHandler(DELETE, URI_BASE + "/license", this,
DELETE, "/_license", deprecationLogger);
// Remove _licenses support entirely in 6.0
controller.registerAsDeprecatedHandler(DELETE, "/_licenses", this,
"[DELETE /_licenses] is deprecated! Use " +
"[DELETE /_xpack/license] instead.",
deprecationLogger);
}
@Override
public void handleRequest(final RestRequest request, final RestChannel channel, final NodeClient client) {
client.admin().cluster().execute(DeleteLicenseAction.INSTANCE, new DeleteLicenseRequest(), new AcknowledgedRestListener<>(channel));
public void handleRequest(final RestRequest request, final RestChannel channel, final XPackClient client) {
client.es().admin().cluster().execute(DeleteLicenseAction.INSTANCE,
new DeleteLicenseRequest(),
new AcknowledgedRestListener<>(channel));
}
}

View File

@ -5,7 +5,6 @@
*/
package org.elasticsearch.license.plugin.rest;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent;
@ -14,13 +13,14 @@ import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.action.get.GetLicenseAction;
import org.elasticsearch.license.plugin.action.get.GetLicenseRequest;
import org.elasticsearch.license.plugin.action.get.GetLicenseResponse;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.BytesRestResponse;
import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.xpack.XPackClient;
import org.elasticsearch.xpack.rest.XPackRestHandler;
import java.util.HashMap;
import java.util.Map;
@ -29,12 +29,20 @@ import static org.elasticsearch.rest.RestRequest.Method.GET;
import static org.elasticsearch.rest.RestStatus.NOT_FOUND;
import static org.elasticsearch.rest.RestStatus.OK;
public class RestGetLicenseAction extends BaseRestHandler {
public class RestGetLicenseAction extends XPackRestHandler {
@Inject
public RestGetLicenseAction(Settings settings, RestController controller) {
super(settings);
controller.registerHandler(GET, "/_xpack/license", this);
// @deprecated Remove deprecations in 6.0
controller.registerWithDeprecatedHandler(GET, URI_BASE + "/license", this,
GET, "/_license", deprecationLogger);
// Remove _licenses support entirely in 6.0
controller.registerAsDeprecatedHandler(GET, "/_licenses", this,
"[GET /_licenses] is deprecated! Use " +
"[GET /_xpack/license] instead.",
deprecationLogger);
}
/**
@ -44,14 +52,14 @@ public class RestGetLicenseAction extends BaseRestHandler {
* The licenses are sorted by latest issue_date
*/
@Override
public void handleRequest(final RestRequest request, final RestChannel channel, final NodeClient client) {
public void handleRequest(final RestRequest request, final RestChannel channel, final XPackClient client) {
final Map<String, String> overrideParams = new HashMap<>(2);
overrideParams.put(License.REST_VIEW_MODE, "true");
overrideParams.put(License.LICENSE_VERSION_MODE, String.valueOf(License.VERSION_CURRENT));
final ToXContent.Params params = new ToXContent.DelegatingMapParams(overrideParams, request);
GetLicenseRequest getLicenseRequest = new GetLicenseRequest();
getLicenseRequest.local(request.paramAsBoolean("local", getLicenseRequest.local()));
client.admin().cluster().execute(GetLicenseAction.INSTANCE, getLicenseRequest,
client.es().admin().cluster().execute(GetLicenseAction.INSTANCE, getLicenseRequest,
new RestBuilderListener<GetLicenseResponse>(channel) {
@Override
public RestResponse buildResponse(GetLicenseResponse response, XContentBuilder builder) throws Exception {

View File

@ -5,7 +5,6 @@
*/
package org.elasticsearch.license.plugin.rest;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent;
@ -13,7 +12,6 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.license.plugin.action.put.PutLicenseAction;
import org.elasticsearch.license.plugin.action.put.PutLicenseRequest;
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.BytesRestResponse;
import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController;
@ -21,25 +19,40 @@ import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.xpack.XPackClient;
import org.elasticsearch.xpack.rest.XPackRestHandler;
import static org.elasticsearch.rest.RestRequest.Method.POST;
import static org.elasticsearch.rest.RestRequest.Method.PUT;
public class RestPutLicenseAction extends BaseRestHandler {
public class RestPutLicenseAction extends XPackRestHandler {
@Inject
public RestPutLicenseAction(Settings settings, RestController controller) {
super(settings);
controller.registerHandler(PUT, "/_xpack/license", this);
controller.registerHandler(POST, "/_xpack/license", this);
// @deprecated Remove deprecations in 6.0
controller.registerWithDeprecatedHandler(POST, URI_BASE + "/license", this,
POST, "/_license", deprecationLogger);
controller.registerWithDeprecatedHandler(PUT, URI_BASE + "/license", this,
PUT, "/_license", deprecationLogger);
// Remove _licenses support entirely in 6.0
controller.registerAsDeprecatedHandler(POST, "/_licenses", this,
"[POST /_licenses] is deprecated! Use " +
"[POST /_xpack/license] instead.",
deprecationLogger);
controller.registerAsDeprecatedHandler(PUT, "/_licenses", this,
"[PUT /_licenses] is deprecated! Use " +
"[PUT /_xpack/license] instead.",
deprecationLogger);
}
@Override
public void handleRequest(final RestRequest request, final RestChannel channel, final NodeClient client) {
public void handleRequest(final RestRequest request, final RestChannel channel, final XPackClient client) {
PutLicenseRequest putLicenseRequest = new PutLicenseRequest();
putLicenseRequest.license(request.content().utf8ToString());
putLicenseRequest.acknowledge(request.paramAsBoolean("acknowledge", false));
client.admin().cluster().execute(PutLicenseAction.INSTANCE, putLicenseRequest,
client.es().admin().cluster().execute(PutLicenseAction.INSTANCE, putLicenseRequest,
new RestBuilderListener<PutLicenseResponse>(channel) {
@Override
public RestResponse buildResponse(PutLicenseResponse response, XContentBuilder builder) throws Exception {

View File

@ -5,36 +5,27 @@
*/
package org.elasticsearch.license.plugin;
import org.elasticsearch.client.ClusterAdminClient;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.env.Environment;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseAction;
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseRequestBuilder;
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseResponse;
import org.elasticsearch.license.plugin.action.get.GetLicenseAction;
import org.elasticsearch.license.plugin.action.get.GetLicenseRequestBuilder;
import org.elasticsearch.license.plugin.action.get.GetLicenseResponse;
import org.elasticsearch.license.plugin.action.put.PutLicenseAction;
import org.elasticsearch.license.plugin.action.put.PutLicenseRequestBuilder;
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
import org.elasticsearch.license.plugin.core.LicenseState;
import org.elasticsearch.license.plugin.core.LicensesMetaData;
import org.elasticsearch.license.plugin.core.LicensesService;
import org.elasticsearch.license.plugin.core.LicensesStatus;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.xpack.MockNetty3Plugin;
import org.elasticsearch.xpack.XPackPlugin;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import static org.elasticsearch.license.plugin.TestUtils.generateSignedLicense;
import static org.elasticsearch.test.ESIntegTestCase.Scope.TEST;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
@ClusterScope(scope = TEST, numDataNodes = 0, numClientNodes = 0, maxNumDataNodes = 0, transportClientRatio = 0)
@ -54,12 +45,13 @@ public class LicensesServiceClusterTests extends AbstractLicensesIntegrationTest
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put("node.data", true)
.put("resource.reload.interval.high", "500ms") // for license mode file watcher
.put(NetworkModule.HTTP_ENABLED.getKey(), true);
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Collections.singletonList(XPackPlugin.class);
return Arrays.asList(XPackPlugin.class, MockNetty3Plugin.class);
}
@Override
@ -78,37 +70,54 @@ public class LicensesServiceClusterTests extends AbstractLicensesIntegrationTest
ensureGreen();
logger.info("--> put signed license");
License license = generateAndPutLicenses();
getAndCheckLicense(license);
LicensingClient licensingClient = new LicensingClient(client());
License license = generateSignedLicense(TimeValue.timeValueMinutes(1));
putLicense(license);
assertThat(licensingClient.prepareGetLicense().get().license(), equalTo(license));
assertOperationMode(license.operationMode());
logger.info("--> restart all nodes");
internalCluster().fullRestart();
ensureYellow();
licensingClient = new LicensingClient(client());
logger.info("--> get and check signed license");
getAndCheckLicense(license);
assertThat(licensingClient.prepareGetLicense().get().license(), equalTo(license));
logger.info("--> remove licenses");
removeLicense();
assertNoLicense();
licensingClient.prepareDeleteLicense().get();
assertOperationMode(License.OperationMode.MISSING);
logger.info("--> restart all nodes");
internalCluster().fullRestart();
licensingClient = new LicensingClient(client());
ensureYellow();
assertNoLicense();
assertThat(licensingClient.prepareGetLicense().get().license(), nullValue());
assertOperationMode(License.OperationMode.MISSING);
wipeAllLicenses();
}
public void testCloudInternalLicense() throws Exception {
wipeAllLicenses();
private void assertLicenseState(LicenseState state) throws InterruptedException {
boolean success = awaitBusy(() -> {
for (LicensesService service : internalCluster().getDataNodeInstances(LicensesService.class)) {
if (service.licenseState() == state) {
return true;
}
}
return false;
});
assertTrue(success);
int numNodes = randomIntBetween(1, 5);
logger.info("--> starting {} node(s)", numNodes);
for (int i = 0; i < numNodes; i++) {
internalCluster().startNode();
}
ensureGreen();
logger.info("--> put signed license");
LicensingClient licensingClient = new LicensingClient(client());
License license = generateSignedLicense("cloud_internal", License.VERSION_CURRENT, System.currentTimeMillis(),
TimeValue.timeValueMinutes(1));
putLicense(license);
assertThat(licensingClient.prepareGetLicense().get().license(), equalTo(license));
assertOperationMode(License.OperationMode.PLATINUM);
writeCloudInternalMode("gold");
assertOperationMode(License.OperationMode.GOLD);
writeCloudInternalMode("basic");
assertOperationMode(License.OperationMode.BASIC);
}
public void testClusterRestartWhileEnabled() throws Exception {
@ -142,7 +151,7 @@ public class LicensesServiceClusterTests extends AbstractLicensesIntegrationTest
internalCluster().startNode();
ensureGreen();
assertLicenseState(LicenseState.ENABLED);
putLicense(TestUtils.generateExpiredLicense(System.currentTimeMillis() - LicensesService.GRACE_PERIOD_DURATION.getMillis()));
putLicense(TestUtils.generateExpiredLicense(System.currentTimeMillis() - LicenseState.GRACE_PERIOD_DURATION.getMillis()));
assertLicenseState(LicenseState.DISABLED);
logger.info("--> restart node");
internalCluster().fullRestart();
@ -159,43 +168,36 @@ public class LicensesServiceClusterTests extends AbstractLicensesIntegrationTest
assertLicenseState(LicenseState.ENABLED);
}
private void removeLicense() throws Exception {
ClusterAdminClient cluster = internalCluster().client().admin().cluster();
ensureGreen();
License putLicenses = generateSignedLicense(TimeValue.timeValueMinutes(1));
PutLicenseRequestBuilder putLicenseRequestBuilder = new PutLicenseRequestBuilder(cluster, PutLicenseAction.INSTANCE);
putLicenseRequestBuilder.setLicense(putLicenses);
DeleteLicenseResponse response = new DeleteLicenseRequestBuilder(cluster, DeleteLicenseAction.INSTANCE).get();
assertThat(response.isAcknowledged(), equalTo(true));
private void assertLicenseState(LicenseState state) throws InterruptedException {
boolean success = awaitBusy(() -> {
for (LicensesService service : internalCluster().getDataNodeInstances(LicensesService.class)) {
if (service.licenseeStatus().getLicenseState() == state) {
return true;
}
}
return false;
});
assertTrue(success);
}
private License generateAndPutLicenses() throws Exception {
ClusterAdminClient cluster = internalCluster().client().admin().cluster();
ensureGreen();
License putLicenses = generateSignedLicense(TimeValue.timeValueMinutes(1));
PutLicenseRequestBuilder putLicenseRequestBuilder = new PutLicenseRequestBuilder(cluster, PutLicenseAction.INSTANCE);
putLicenseRequestBuilder.setLicense(putLicenses);
final PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.get();
assertThat(putLicenseResponse.isAcknowledged(), equalTo(true));
assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID));
return putLicenses;
private void assertOperationMode(License.OperationMode operationMode) throws InterruptedException {
boolean success = awaitBusy(() -> {
for (LicensesService service : internalCluster().getDataNodeInstances(LicensesService.class)) {
if (service.licenseeStatus().getMode() == operationMode) {
return true;
}
}
return false;
});
assertTrue(success);
}
private void assertNoLicense() {
ClusterAdminClient cluster = internalCluster().client().admin().cluster();
final GetLicenseResponse response = new GetLicenseRequestBuilder(cluster, GetLicenseAction.INSTANCE).get();
assertThat(response.license(), nullValue());
LicensesMetaData licensesMetaData = clusterService().state().metaData().custom(LicensesMetaData.TYPE);
assertThat(licensesMetaData, notNullValue());
assertThat(licensesMetaData.getLicense(), equalTo(LicensesMetaData.LICENSE_TOMBSTONE));
private void writeCloudInternalMode(String mode) throws Exception {
for (Environment environment : internalCluster().getDataOrMasterNodeInstances(Environment.class)) {
Path licenseModePath = XPackPlugin.resolveConfigFile(environment, "license_mode");
Files.createDirectories(licenseModePath.getParent());
Files.write(licenseModePath, mode.getBytes(StandardCharsets.UTF_8));
}
}
private void getAndCheckLicense(License license) {
ClusterAdminClient cluster = internalCluster().client().admin().cluster();
final GetLicenseResponse response = new GetLicenseRequestBuilder(cluster, GetLicenseAction.INSTANCE).get();
assertThat(response.license(), equalTo(license));
LicensesMetaData licensesMetaData = clusterService().state().metaData().custom(LicensesMetaData.TYPE);
assertThat(licensesMetaData, notNullValue());
assertThat(licensesMetaData.getLicense(), not(LicensesMetaData.LICENSE_TOMBSTONE));
}
}

View File

@ -6,9 +6,6 @@
package org.elasticsearch.license.plugin;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.block.ClusterBlock;
import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.joda.DateMathParser;
@ -29,10 +26,8 @@ import org.elasticsearch.license.plugin.core.LicensesService;
import org.elasticsearch.license.plugin.core.LicensesStatus;
import org.junit.Assert;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList;
@ -92,8 +87,11 @@ public class TestUtils {
}
public static License generateSignedLicense(String type, long issueDate, TimeValue expiryDuration) throws Exception {
return generateSignedLicense(type, randomIntBetween(License.VERSION_START, License.VERSION_CURRENT), issueDate, expiryDuration);
}
public static License generateSignedLicense(String type, int version, long issueDate, TimeValue expiryDuration) throws Exception {
long issue = (issueDate != -1L) ? issueDate : System.currentTimeMillis() - TimeValue.timeValueHours(2).getMillis();
int version = randomIntBetween(License.VERSION_START, License.VERSION_CURRENT);
final String licenseType;
if (version < License.VERSION_NO_FEATURE_TYPE) {
licenseType = randomFrom("subscription", "internal", "development");
@ -117,17 +115,26 @@ public class TestUtils {
return signer.sign(builder.build());
}
public static License generateExpiredLicense() throws Exception {
return generateExpiredLicense(System.currentTimeMillis() - TimeValue.timeValueHours(randomIntBetween(1, 10)).getMillis());
public static License generateExpiredLicense(long expiryDate) throws Exception {
return generateExpiredLicense(randomFrom("basic", "silver", "dev", "gold", "platinum"), expiryDate);
}
public static License generateExpiredLicense(long expiryDate) throws Exception {
public static License generateExpiredLicense() throws Exception {
return generateExpiredLicense(randomFrom("basic", "silver", "dev", "gold", "platinum"));
}
public static License generateExpiredLicense(String type) throws Exception {
return generateExpiredLicense(type,
System.currentTimeMillis() - TimeValue.timeValueHours(randomIntBetween(1, 10)).getMillis());
}
public static License generateExpiredLicense(String type, long expiryDate) throws Exception {
final License.Builder builder = License.builder()
.uid(UUID.randomUUID().toString())
.version(License.VERSION_CURRENT)
.expiryDate(expiryDate)
.issueDate(expiryDate - TimeValue.timeValueMinutes(10).getMillis())
.type(randomFrom("basic", "silver", "dev", "gold", "platinum"))
.type(type)
.issuedTo("customer")
.issuer("elasticsearch")
.maxNodes(5);
@ -139,23 +146,9 @@ public class TestUtils {
return PathUtils.get(TestUtils.class.getResource(resource).toURI());
}
public static void awaitNoBlock(final Client client) throws InterruptedException {
boolean success = awaitBusy(() -> {
Set<ClusterBlock> clusterBlocks = client.admin().cluster().prepareState().setLocal(true).execute().actionGet()
.getState().blocks().global(ClusterBlockLevel.METADATA_WRITE);
return clusterBlocks.isEmpty();
});
assertThat("awaiting no block for too long", success, equalTo(true));
}
public static void awaitNoPendingTasks(final Client client) throws InterruptedException {
boolean success = awaitBusy(() -> client.admin().cluster().preparePendingClusterTasks().get().getPendingTasks().isEmpty());
assertThat("awaiting no pending tasks for too long", success, equalTo(true));
}
public static void registerAndAckSignedLicenses(final LicensesService licensesService, License license,
final LicensesStatus expectedStatus) {
PutLicenseRequest putLicenseRequest = new PutLicenseRequest().license(license);
PutLicenseRequest putLicenseRequest = new PutLicenseRequest().license(license).acknowledge(true);
final CountDownLatch latch = new CountDownLatch(1);
final AtomicReference<LicensesStatus> status = new AtomicReference<>();
licensesService.registerLicense(putLicenseRequest, new ActionListener<PutLicenseResponse>() {
@ -183,7 +176,7 @@ public class TestUtils {
public final String id;
public final List<Licensee.Status> statuses = new CopyOnWriteArrayList<>();
public final AtomicInteger expirationMessagesCalled = new AtomicInteger(0);
public final List<Tuple<License, License>> acknowledgementRequested = new CopyOnWriteArrayList<>();
public final List<Tuple<License.OperationMode, License.OperationMode>> acknowledgementRequested = new CopyOnWriteArrayList<>();
private String[] acknowledgmentMessages = new String[0];
@ -207,8 +200,8 @@ public class TestUtils {
}
@Override
public String[] acknowledgmentMessages(License currentLicense, License newLicense) {
acknowledgementRequested.add(new Tuple<>(currentLicense, newLicense));
public String[] acknowledgmentMessages(License.OperationMode currentMode, License.OperationMode newMode) {
acknowledgementRequested.add(new Tuple<>(currentMode, newMode));
return acknowledgmentMessages;
}
@ -218,4 +211,4 @@ public class TestUtils {
statuses.add(status);
}
}
}
}

View File

@ -5,7 +5,10 @@
*/
package org.elasticsearch.license.plugin.core;
import java.util.Arrays;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.block.ClusterBlocks;
import org.elasticsearch.cluster.metadata.MetaData;
@ -15,13 +18,16 @@ import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.component.Lifecycle;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.LocalTransportAddress;
import org.elasticsearch.env.Environment;
import org.elasticsearch.license.core.License;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.xpack.scheduler.SchedulerEngine;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.support.clock.ClockMock;
import org.junit.After;
import org.junit.Before;
import java.nio.file.Path;
import static java.util.Collections.emptyMap;
import static java.util.Collections.emptySet;
import static org.mockito.Mockito.mock;
@ -31,29 +37,43 @@ public abstract class AbstractLicenseServiceTestCase extends ESTestCase {
protected LicensesService licensesService;
protected ClusterService clusterService;
protected TransportService transportService;
protected ResourceWatcherService resourceWatcherService;
protected ClockMock clock;
protected DiscoveryNodes discoveryNodes;
protected Environment environment;
@Before
public void init() throws Exception {
clusterService = mock(ClusterService.class);
transportService = mock(TransportService.class);
clock = new ClockMock();
licensesService = new LicensesService(Settings.EMPTY, clusterService, transportService, clock);
discoveryNodes = mock(DiscoveryNodes.class);
resourceWatcherService = mock(ResourceWatcherService.class);
environment = mock(Environment.class);
}
protected void setInitialState(License license) {
protected void setInitialState(License license, Licensee... licensees) {
Path tempDir = createTempDir();
when(environment.configFile()).thenReturn(tempDir);
licensesService = new LicensesService(Settings.EMPTY, clusterService, clock, environment,
resourceWatcherService, Arrays.asList(licensees));
ClusterState state = mock(ClusterState.class);
final ClusterBlocks noBlock = ClusterBlocks.builder().build();
when(state.blocks()).thenReturn(noBlock);
MetaData metaData = mock(MetaData.class);
when(metaData.custom(LicensesMetaData.TYPE)).thenReturn(new LicensesMetaData(license));
when(state.metaData()).thenReturn(metaData);
final DiscoveryNodes discoveryNodes = mock(DiscoveryNodes.class);
final DiscoveryNode mockNode = new DiscoveryNode("b", LocalTransportAddress.buildUnique(), emptyMap(), emptySet(), Version.CURRENT);
when(discoveryNodes.getMasterNode()).thenReturn(mockNode);
when(discoveryNodes.isLocalNodeElectedMaster()).thenReturn(false);
when(state.nodes()).thenReturn(discoveryNodes);
when(state.getNodes()).thenReturn(discoveryNodes); // it is really ridiculous we have nodes() and getNodes()...
when(clusterService.state()).thenReturn(state);
when(clusterService.lifecycleState()).thenReturn(Lifecycle.State.STARTED);
when(clusterService.getClusterName()).thenReturn(new ClusterName("a"));
}
}
@After
public void after() {
licensesService.stop();
}
}

View File

@ -39,17 +39,8 @@ public abstract class AbstractLicenseeTestCase extends ESTestCase {
* @param licensee The licensee to test
*/
public static void assertEmptyAck(OperationMode fromMode, OperationMode toMode, Licensee licensee) {
License fromLicense = mock(License.class);
when(fromLicense.operationMode()).thenReturn(fromMode);
License toLicense = mock(License.class);
when(toLicense.operationMode()).thenReturn(toMode);
if (randomBoolean()) {
fromLicense = null;
}
// test it
String[] messages = licensee.acknowledgmentMessages(fromLicense, toLicense);
String[] messages = licensee.acknowledgmentMessages(fromMode, toMode);
assertThat(fromToMessage(fromMode, toMode), messages.length, equalTo(0));
}
@ -77,12 +68,7 @@ public abstract class AbstractLicenseeTestCase extends ESTestCase {
* @param licensee The licensee to test
*/
public static String[] ackLicenseChange(OperationMode fromMode, OperationMode toMode, Licensee licensee) {
License fromLicense = mock(License.class);
when(fromLicense.operationMode()).thenReturn(fromMode);
License toLicense = mock(License.class);
when(toLicense.operationMode()).thenReturn(toMode);
return licensee.acknowledgmentMessages(fromLicense, toLicense);
return licensee.acknowledgmentMessages(fromMode, toMode);
}
/**
@ -169,35 +155,18 @@ public abstract class AbstractLicenseeTestCase extends ESTestCase {
return String.format(Locale.ROOT, "From [%s] to [%s]", fromMode, toMode);
}
public static class SimpleLicenseeRegistry extends AbstractComponent implements LicenseeRegistry {
private final List<Licensee> licensees = new ArrayList<>();
private OperationMode operationMode;
private OperationMode operationMode;
public SimpleLicenseeRegistry() {
super(Settings.EMPTY);
}
public void setOperationMode(Licensee licensee, OperationMode operationMode) {
this.operationMode = operationMode;
enable(licensee);
}
@Override
public void register(Licensee licensee) {
licensees.add(licensee);
enable();
}
public void disable(Licensee licensee) {
licensee.onChange(new Licensee.Status(operationMode, LicenseState.DISABLED));
}
public void enable() {
for (Licensee licensee : licensees) {
licensee.onChange(new Licensee.Status(operationMode, randomEnabledOrGracePeriodState()));
}
}
public void disable() {
for (Licensee licensee : licensees) {
licensee.onChange(new Licensee.Status(operationMode, LicenseState.DISABLED));
}
}
public void setOperationMode(License.OperationMode operationMode) {
this.operationMode = operationMode;
enable();
}
public void enable(Licensee licensee) {
licensee.onChange(new Licensee.Status(operationMode, randomEnabledOrGracePeriodState()));
}
}

View File

@ -9,6 +9,7 @@ import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterChangedEvent;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.ClusterStateUpdateTask;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodes;
@ -16,18 +17,17 @@ import org.elasticsearch.common.transport.LocalTransportAddress;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.TestUtils;
import org.elasticsearch.transport.EmptyTransportResponseHandler;
import org.elasticsearch.transport.TransportRequest;
import org.junit.After;
import org.junit.Before;
import org.mockito.ArgumentCaptor;
import static java.util.Collections.emptyMap;
import static java.util.Collections.emptySet;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class LicenseClusterChangeTests extends AbstractLicenseServiceTestCase {
@ -35,10 +35,9 @@ public class LicenseClusterChangeTests extends AbstractLicenseServiceTestCase {
@Before
public void setup() {
setInitialState(null);
licensesService.start();
licensee = new TestUtils.AssertingLicensee("LicenseClusterChangeTests", logger);
licensesService.register(licensee);
setInitialState(null, licensee);
licensesService.start();
}
@After
@ -70,11 +69,16 @@ public class LicenseClusterChangeTests extends AbstractLicenseServiceTestCase {
DiscoveryNode master = new DiscoveryNode("b", LocalTransportAddress.buildUnique(), emptyMap(), emptySet(), Version.CURRENT);
ClusterState oldState = ClusterState.builder(new ClusterName("a"))
.nodes(DiscoveryNodes.builder().masterNodeId(master.getId()).put(master)).build();
ClusterState newState = ClusterState.builder(oldState).build();
when(discoveryNodes.isLocalNodeElectedMaster()).thenReturn(true);
ClusterState newState = ClusterState.builder(oldState).nodes(discoveryNodes).build();
licensesService.clusterChanged(new ClusterChangedEvent("simulated", newState, oldState));
verify(transportService, times(2))
.sendRequest(any(DiscoveryNode.class),
eq(LicensesService.REGISTER_TRIAL_LICENSE_ACTION_NAME),
any(TransportRequest.Empty.class), any(EmptyTransportResponseHandler.class));
ArgumentCaptor<ClusterStateUpdateTask> stateUpdater = ArgumentCaptor.forClass(ClusterStateUpdateTask.class);
verify(clusterService, times(1)).submitStateUpdateTask(any(), stateUpdater.capture());
ClusterState stateWithLicense = stateUpdater.getValue().execute(newState);
LicensesMetaData licenseMetaData = stateWithLicense.metaData().custom(LicensesMetaData.TYPE);
assertNotNull(licenseMetaData);
assertNotNull(licenseMetaData.getLicense());
assertEquals(clock.millis() + LicensesService.TRIAL_LICENSE_DURATION.millis(), licenseMetaData.getLicense().expiryDate());
}
}

View File

@ -5,43 +5,45 @@
*/
package org.elasticsearch.license.plugin.core;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.ClusterStateUpdateTask;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.plugin.TestUtils;
import org.elasticsearch.transport.EmptyTransportResponseHandler;
import org.elasticsearch.transport.TransportRequest;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import static org.elasticsearch.mock.orig.Mockito.times;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class LicenseRegistrationTests extends AbstractLicenseServiceTestCase {
public void testTrialLicenseRequestOnEmptyLicenseState() throws Exception {
setInitialState(null);
TestUtils.AssertingLicensee licensee = new TestUtils.AssertingLicensee(
"testTrialLicenseRequestOnEmptyLicenseState", logger);
"testTrialLicenseRequestOnEmptyLicenseState", logger);
setInitialState(null, licensee);
when(discoveryNodes.isLocalNodeElectedMaster()).thenReturn(true);
licensesService.start();
licensesService.register(licensee);
verify(transportService, times(1))
.sendRequest(any(DiscoveryNode.class),
eq(LicensesService.REGISTER_TRIAL_LICENSE_ACTION_NAME),
any(TransportRequest.Empty.class), any(EmptyTransportResponseHandler.class));
assertThat(licensee.statuses.size(), equalTo(0));
licensesService.stop();
ClusterState state = ClusterState.builder(new ClusterName("a")).build();
ArgumentCaptor<ClusterStateUpdateTask> stateUpdater = ArgumentCaptor.forClass(ClusterStateUpdateTask.class);
verify(clusterService, Mockito.times(1)).submitStateUpdateTask(any(), stateUpdater.capture());
ClusterState stateWithLicense = stateUpdater.getValue().execute(state);
LicensesMetaData licenseMetaData = stateWithLicense.metaData().custom(LicensesMetaData.TYPE);
assertNotNull(licenseMetaData);
assertNotNull(licenseMetaData.getLicense());
assertEquals(clock.millis() + LicensesService.TRIAL_LICENSE_DURATION.millis(), licenseMetaData.getLicense().expiryDate());
}
public void testNotificationOnRegistration() throws Exception {
setInitialState(TestUtils.generateSignedLicense(TimeValue.timeValueHours(2)));
TestUtils.AssertingLicensee licensee = new TestUtils.AssertingLicensee(
"testNotificationOnRegistration", logger);
setInitialState(TestUtils.generateSignedLicense(TimeValue.timeValueHours(2)), licensee);
licensesService.start();
licensesService.register(licensee);
assertThat(licensee.statuses.size(), equalTo(1));
final LicenseState licenseState = licensee.statuses.get(0).getLicenseState();
assertTrue(licenseState == LicenseState.ENABLED);
licensesService.stop();
}
}

View File

@ -32,13 +32,13 @@ public class LicenseScheduleTests extends ESTestCase {
public void testGraceLicenseSchedule() throws Exception {
long triggeredTime = license.expiryDate() + between(1,
((int) LicensesService.GRACE_PERIOD_DURATION.getMillis()));
((int) LicenseState.GRACE_PERIOD_DURATION.getMillis()));
assertThat(schedule.nextScheduledTimeAfter(license.issueDate(), triggeredTime),
equalTo(license.expiryDate() + LicensesService.GRACE_PERIOD_DURATION.getMillis()));
equalTo(license.expiryDate() + LicenseState.GRACE_PERIOD_DURATION.getMillis()));
}
public void testExpiredLicenseSchedule() throws Exception {
long triggeredTime = license.expiryDate() + LicensesService.GRACE_PERIOD_DURATION.getMillis() +
long triggeredTime = license.expiryDate() + LicenseState.GRACE_PERIOD_DURATION.getMillis() +
randomIntBetween(1, 1000);
assertThat(schedule.nextScheduledTimeAfter(license.issueDate(), triggeredTime),
equalTo(-1L));
@ -49,4 +49,4 @@ public class LicenseScheduleTests extends ESTestCase {
assertThat(schedule.nextScheduledTimeAfter(triggeredTime, triggeredTime),
equalTo(license.issueDate()));
}
}
}

View File

@ -5,6 +5,10 @@
*/
package org.elasticsearch.license.plugin.core;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.cluster.ClusterStateUpdateTask;
import org.elasticsearch.common.unit.TimeValue;
@ -13,10 +17,6 @@ import org.elasticsearch.license.plugin.TestUtils;
import org.elasticsearch.license.plugin.action.put.PutLicenseRequest;
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.elasticsearch.license.plugin.TestUtils.generateSignedLicense;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
@ -27,13 +27,13 @@ import static org.mockito.Mockito.verify;
public class LicensesAcknowledgementTests extends AbstractLicenseServiceTestCase {
public void testAcknowledgment() throws Exception {
setInitialState(TestUtils.generateSignedLicense("trial", TimeValue.timeValueHours(2)));
licensesService.start();
String id = "testAcknowledgment";
String[] acknowledgeMessages = new String[] {"message"};
TestUtils.AssertingLicensee licensee = new TestUtils.AssertingLicensee(id, logger);
setInitialState(TestUtils.generateSignedLicense("trial", TimeValue.timeValueHours(2)), licensee);
licensesService.start();
licensee.setAcknowledgementMessages(acknowledgeMessages);
licensesService.register(licensee);
// try installing a signed license
License signedLicense = generateSignedLicense(TimeValue.timeValueHours(10));
PutLicenseRequest putLicenseRequest = new PutLicenseRequest().license(signedLicense);
@ -41,7 +41,7 @@ public class LicensesAcknowledgementTests extends AbstractLicenseServiceTestCase
licensesService.registerLicense(putLicenseRequest, new AssertingLicensesUpdateResponse(false, LicensesStatus.VALID,
Collections.singletonMap(id, acknowledgeMessages)));
assertThat(licensee.acknowledgementRequested.size(), equalTo(1));
assertThat(licensee.acknowledgementRequested.get(0).v2(), equalTo(signedLicense));
assertThat(licensee.acknowledgementRequested.get(0).v2(), equalTo(signedLicense.operationMode()));
assertThat(licensesService.getLicense(), not(signedLicense));
// try installing a signed license with acknowledgement
@ -52,13 +52,10 @@ public class LicensesAcknowledgementTests extends AbstractLicenseServiceTestCase
Collections.<String, String[]>emptyMap()));
verify(clusterService, times(1)).submitStateUpdateTask(any(String.class), any(ClusterStateUpdateTask.class));
assertThat(licensee.acknowledgementRequested.size(), equalTo(1));
assertThat(licensee.acknowledgementRequested.get(0).v2(), equalTo(signedLicense));
licensesService.stop();
assertThat(licensee.acknowledgementRequested.get(0).v2(), equalTo(signedLicense.operationMode()));
}
public void testAcknowledgementMultipleLicensee() throws Exception {
setInitialState(TestUtils.generateSignedLicense("trial", TimeValue.timeValueHours(2)));
licensesService.start();
String id1 = "testAcknowledgementMultipleLicensee_1";
String[] acknowledgeMessages1 = new String[] {"testAcknowledgementMultipleLicensee_1"};
String id2 = "testAcknowledgementMultipleLicensee_2";
@ -67,8 +64,8 @@ public class LicensesAcknowledgementTests extends AbstractLicenseServiceTestCase
licensee1.setAcknowledgementMessages(acknowledgeMessages1);
TestUtils.AssertingLicensee licensee2 = new TestUtils.AssertingLicensee(id2, logger);
licensee2.setAcknowledgementMessages(acknowledgeMessages2);
licensesService.register(licensee1);
licensesService.register(licensee2);
setInitialState(TestUtils.generateSignedLicense("trial", TimeValue.timeValueHours(2)), licensee1, licensee2);
licensesService.start();
// try installing a signed license
License signedLicense = generateSignedLicense(TimeValue.timeValueHours(10));
PutLicenseRequest putLicenseRequest = new PutLicenseRequest().license(signedLicense);
@ -80,9 +77,9 @@ public class LicensesAcknowledgementTests extends AbstractLicenseServiceTestCase
expectedMessages));
verify(clusterService, times(0)).submitStateUpdateTask(any(String.class), any(ClusterStateUpdateTask.class));
assertThat(licensee2.acknowledgementRequested.size(), equalTo(1));
assertThat(licensee2.acknowledgementRequested.get(0).v2(), equalTo(signedLicense));
assertThat(licensee2.acknowledgementRequested.get(0).v2(), equalTo(signedLicense.operationMode()));
assertThat(licensee1.acknowledgementRequested.size(), equalTo(1));
assertThat(licensee1.acknowledgementRequested.get(0).v2(), equalTo(signedLicense));
assertThat(licensee1.acknowledgementRequested.get(0).v2(), equalTo(signedLicense.operationMode()));
assertThat(licensesService.getLicense(), not(signedLicense));
// try installing a signed license with acknowledgement
@ -93,7 +90,6 @@ public class LicensesAcknowledgementTests extends AbstractLicenseServiceTestCase
licensesService.registerLicense(putLicenseRequest, new AssertingLicensesUpdateResponse(true, LicensesStatus.VALID,
Collections.<String, String[]>emptyMap()));
verify(clusterService, times(1)).submitStateUpdateTask(any(String.class), any(ClusterStateUpdateTask.class));
licensesService.stop();
}
private static class AssertingLicensesUpdateResponse implements ActionListener<PutLicenseResponse> {
@ -125,4 +121,4 @@ public class LicensesAcknowledgementTests extends AbstractLicenseServiceTestCase
public void onFailure(Exception throwable) {
}
}
}
}

View File

@ -5,27 +5,27 @@
*/
package org.elasticsearch.license.plugin.core;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.cluster.ack.ClusterStateUpdateResponse;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.xpack.graph.Graph;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.TestUtils;
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseRequest;
import org.elasticsearch.xpack.monitoring.Monitoring;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.test.ESSingleNodeTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.graph.Graph;
import org.elasticsearch.xpack.monitoring.Monitoring;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.watcher.Watcher;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.elasticsearch.license.plugin.TestUtils.generateSignedLicense;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
@ -116,9 +116,6 @@ public class LicensesManagerServiceTests extends ESSingleNodeTestCase {
LicensesService licensesService = getInstanceFromNode(LicensesService.class);
ClusterService clusterService = getInstanceFromNode(ClusterService.class);
// generate a trial license for one feature
licensesService.register(new TestUtils.AssertingLicensee("", logger));
// generate signed licenses
License license = generateSignedLicense(TimeValue.timeValueHours(1));
TestUtils.registerAndAckSignedLicenses(licensesService, license, LicensesStatus.VALID);
@ -131,53 +128,6 @@ public class LicensesManagerServiceTests extends ESSingleNodeTestCase {
assertThat(licensesMetaData.getLicense(), equalTo(LicensesMetaData.LICENSE_TOMBSTONE));
}
public void testRemoveLicensesAndLicenseeNotification() throws Exception {
LicensesService licensesService = getInstanceFromNode(LicensesService.class);
licensesService.start();
ClusterService clusterService = getInstanceFromNode(ClusterService.class);
// generate a trial license for one feature
TestUtils.AssertingLicensee licensee = new TestUtils.AssertingLicensee("", logger);
licensesService.register(licensee);
// we should get a trial license to begin with
assertBusy(new Runnable() {
@Override
public void run() {
assertThat(licensee.statuses, hasSize(1));
assertThat(licensee.statuses.get(0).getMode(), is(License.OperationMode.TRIAL));
assertThat(licensee.statuses.get(0).getLicenseState(), is(LicenseState.ENABLED));
}
});
// generate signed licenses
License license = generateSignedLicense("gold", TimeValue.timeValueHours(1));
TestUtils.registerAndAckSignedLicenses(licensesService, license, LicensesStatus.VALID);
assertBusy(new Runnable() {
@Override
public void run() {
assertThat(licensee.statuses, hasSize(2));
assertThat(licensee.statuses.get(1).getMode(), not(License.OperationMode.TRIAL));
assertThat(licensee.statuses.get(1).getLicenseState(), is(LicenseState.ENABLED));
}
});
// remove signed licenses
removeAndAckSignedLicenses(licensesService);
assertBusy(new Runnable() {
@Override
public void run() {
assertThat(licensee.statuses, hasSize(3));
}
});
LicensesMetaData licensesMetaData = clusterService.state().metaData().custom(LicensesMetaData.TYPE);
assertThat(licensesMetaData.getLicense(), is(LicensesMetaData.LICENSE_TOMBSTONE));
assertThat(licensee.statuses, hasSize(3));
assertThat(licensee.statuses.get(2).getLicenseState(), is(LicenseState.DISABLED));
assertThat(licensee.statuses.get(2).getMode(), is(License.OperationMode.MISSING));
}
private void removeAndAckSignedLicenses(final LicensesService licensesService) {
final CountDownLatch latch = new CountDownLatch(1);
final AtomicBoolean success = new AtomicBoolean(false);

View File

@ -5,6 +5,8 @@
*/
package org.elasticsearch.license.plugin.core;
import java.util.List;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.TestUtils;
@ -12,21 +14,20 @@ import org.elasticsearch.license.plugin.TestUtils.AssertingLicensee;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import java.util.List;
import static org.hamcrest.Matchers.equalTo;
public class LicensesNotificationTests extends AbstractLicenseServiceTestCase {
public void testLicenseNotification() throws Exception {
final License license = TestUtils.generateSignedLicense(TimeValue.timeValueHours(48));
setInitialState(license);
licensesService.start();
int nLicensee = randomIntBetween(1, 3);
AssertingLicensee[] assertingLicensees = new AssertingLicensee[nLicensee];
for (int i = 0; i < assertingLicensees.length; i++) {
assertingLicensees[i] = new AssertingLicensee("testLicenseNotification" + i, logger);
licensesService.register(assertingLicensees[i]);
}
setInitialState(license, assertingLicensees);
licensesService.start();
for (int i = 0; i < assertingLicensees.length; i++) {
assertLicenseStates(assertingLicensees[i], LicenseState.ENABLED);
}
clock.fastForward(TimeValue.timeValueMillis(license.expiryDate() - clock.millis()));
@ -36,7 +37,7 @@ public class LicensesNotificationTests extends AbstractLicenseServiceTestCase {
assertLicenseStates(assertingLicensee, LicenseState.ENABLED, LicenseState.GRACE_PERIOD);
}
clock.fastForward(TimeValue.timeValueMillis((license.expiryDate() +
LicensesService.GRACE_PERIOD_DURATION.getMillis()) - clock.millis()));
LicenseState.GRACE_PERIOD_DURATION.getMillis()) - clock.millis()));
licensesService.onUpdate(licensesMetaData);
for (AssertingLicensee assertingLicensee : assertingLicensees) {
assertLicenseStates(assertingLicensee, LicenseState.ENABLED, LicenseState.GRACE_PERIOD, LicenseState.DISABLED);
@ -44,12 +45,12 @@ public class LicensesNotificationTests extends AbstractLicenseServiceTestCase {
clock.setTime(new DateTime(DateTimeZone.UTC));
final License newLicense = TestUtils.generateSignedLicense(TimeValue.timeValueHours(2));
clock.fastForward(TimeValue.timeValueHours(1));
licensesService.onUpdate(new LicensesMetaData(newLicense));
LicensesMetaData licensesMetaData1 = new LicensesMetaData(newLicense);
licensesService.onUpdate(licensesMetaData1);
for (AssertingLicensee assertingLicensee : assertingLicensees) {
assertLicenseStates(assertingLicensee, LicenseState.ENABLED, LicenseState.GRACE_PERIOD, LicenseState.DISABLED,
LicenseState.ENABLED);
}
licensesService.stop();
}
private void assertLicenseStates(AssertingLicensee licensee, LicenseState... states) {
@ -88,4 +89,4 @@ public class LicensesNotificationTests extends AbstractLicenseServiceTestCase {
sb.append("]");
return sb.toString();
}
}
}

View File

@ -19,6 +19,7 @@ import org.elasticsearch.common.UUIDs;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.discovery.DiscoveryModule;
import org.elasticsearch.discovery.zen.ping.unicast.UnicastZenPing;
import org.elasticsearch.xpack.monitoring.Monitoring;
import org.elasticsearch.node.Node;
@ -59,7 +60,8 @@ public abstract class TribeTransportTestCase extends ESIntegTestCase {
protected final Settings nodeSettings(int nodeOrdinal) {
final Settings.Builder builder = Settings.builder()
.put(NetworkModule.HTTP_ENABLED.getKey(), false)
.put(Node.NODE_LOCAL_SETTING.getKey(), true);
.put("transport.type", "local")
.put(DiscoveryModule.DISCOVERY_TYPE_SETTING.getKey(), "local");
List<String> enabledFeatures = enabledFeatures();
for (String feature : ALL_FEATURES) {
builder.put(XPackPlugin.featureEnabledSetting(feature), enabledFeatures.contains(feature));
@ -99,7 +101,7 @@ public abstract class TribeTransportTestCase extends ESIntegTestCase {
return TribeTransportTestCase.this.transportClientPlugins();
}
};
final InternalTestCluster cluster2 = new InternalTestCluster(InternalTestCluster.configuredNodeMode(),
final InternalTestCluster cluster2 = new InternalTestCluster(
randomLong(), createTempDir(), true, 2, 2,
UUIDs.randomBase64UUID(random()), nodeConfigurationSource, 1, false, "tribe_node2",
getMockPlugins(), getClientWrapper());
@ -131,12 +133,17 @@ public abstract class TribeTransportTestCase extends ESIntegTestCase {
Settings merged = Settings.builder()
.put("tribe.t1.cluster.name", internalCluster().getClusterName())
.put("tribe.t2.cluster.name", cluster2.getClusterName())
.put("tribe.t1.transport.type", "local")
.put("tribe.t2.transport.type", "local")
.put("tribe.t1.discovery.type", "local")
.put("tribe.t2.discovery.type", "local")
.put("tribe.blocks.write", false)
.put(tribe1Defaults.build())
.put(tribe2Defaults.build())
.put(NetworkModule.HTTP_ENABLED.getKey(), false)
.put(internalCluster().getDefaultSettings())
.put("node.name", "tribe_node") // make sure we can identify threads from this node
.put(Node.NODE_LOCAL_SETTING.getKey(), true)
.put("transport.type", "local")
.build();
final Node tribeNode = new Node(merged).start();

View File

@ -78,9 +78,7 @@ public class Monitoring implements ActionPlugin {
if (enabled == false || transportClientMode || tribeNode) {
return Collections.emptyList();
}
return Arrays.<Class<? extends LifecycleComponent>>asList(MonitoringLicensee.class,
AgentService.class,
CleanerService.class);
return Arrays.<Class<? extends LifecycleComponent>>asList(AgentService.class, CleanerService.class);
}
@Override

View File

@ -6,15 +6,11 @@
package org.elasticsearch.xpack.monitoring;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.LoggerMessageFormat;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.core.License.OperationMode;
import org.elasticsearch.license.plugin.core.AbstractLicenseeComponent;
import org.elasticsearch.license.plugin.core.LicenseState;
import org.elasticsearch.license.plugin.core.Licensee;
import org.elasticsearch.license.plugin.core.LicenseeRegistry;
/**
* {@code MonitoringLicensee} determines whether certain features of Monitoring are enabled or disabled.
@ -25,11 +21,10 @@ import org.elasticsearch.license.plugin.core.LicenseeRegistry;
* <li>Cleaning up (deleting) older indices.</li>
* </ul>
*/
public class MonitoringLicensee extends AbstractLicenseeComponent<MonitoringLicensee> implements Licensee {
public class MonitoringLicensee extends AbstractLicenseeComponent {
@Inject
public MonitoringLicensee(Settings settings, LicenseeRegistry clientService) {
super(settings, Monitoring.NAME, clientService);
public MonitoringLicensee(Settings settings) {
super(settings, Monitoring.NAME);
}
/**
@ -47,27 +42,25 @@ public class MonitoringLicensee extends AbstractLicenseeComponent<MonitoringLice
}
@Override
public String[] acknowledgmentMessages(License currentLicense, License newLicense) {
switch (newLicense.operationMode()) {
public String[] acknowledgmentMessages(OperationMode currentMode, OperationMode newMode) {
switch (newMode) {
case BASIC:
if (currentLicense != null) {
switch (currentLicense.operationMode()) {
case TRIAL:
case STANDARD:
case GOLD:
case PLATINUM:
return new String[] {
LoggerMessageFormat.format(
"Multi-cluster support is disabled for clusters with [{}] license. If you are\n" +
"running multiple clusters, users won't be able to access the clusters with\n" +
"[{}] licenses from within a single X-Pack Kibana instance. You will have to deploy a\n" +
"separate and dedicated X-pack Kibana instance for each [{}] cluster you wish to monitor.",
newLicense.type(), newLicense.type(), newLicense.type()),
LoggerMessageFormat.format(
"Automatic index cleanup is locked to {} days for clusters with [{}] license.",
MonitoringSettings.HISTORY_DURATION.getDefault(Settings.EMPTY).days(), newLicense.type())
};
}
switch (currentMode) {
case TRIAL:
case STANDARD:
case GOLD:
case PLATINUM:
return new String[] {
LoggerMessageFormat.format(
"Multi-cluster support is disabled for clusters with [{}] license. If you are\n" +
"running multiple clusters, users won't be able to access the clusters with\n" +
"[{}] licenses from within a single X-Pack Kibana instance. You will have to deploy a\n" +
"separate and dedicated X-pack Kibana instance for each [{}] cluster you wish to monitor.",
newMode, newMode, newMode),
LoggerMessageFormat.format(
"Automatic index cleanup is locked to {} days for clusters with [{}] license.",
MonitoringSettings.HISTORY_DURATION.getDefault(Settings.EMPTY).days(), newMode)
};
}
break;
}

View File

@ -26,11 +26,10 @@ public class MonitoringModule extends AbstractModule {
XPackPlugin.bindFeatureSet(binder(), MonitoringFeatureSet.class);
if (enabled && transportClientMode == false) {
bind(MonitoringLicensee.class).asEagerSingleton();
bind(MonitoringSettings.class).asEagerSingleton();
bind(AgentService.class).asEagerSingleton();
bind(CleanerService.class).asEagerSingleton();
} else {
} else if (transportClientMode) {
bind(MonitoringLicensee.class).toProvider(Providers.of(null));
}
}

View File

@ -14,7 +14,7 @@ import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.plugin.core.LicenseUtils;
import org.elasticsearch.license.plugin.core.LicensesManagerService;
import org.elasticsearch.license.plugin.core.LicensesService;
import org.elasticsearch.xpack.monitoring.MonitoringLicensee;
import org.elasticsearch.xpack.monitoring.MonitoringSettings;
import org.elasticsearch.xpack.monitoring.agent.collector.AbstractCollector;
@ -40,16 +40,16 @@ public class ClusterStatsCollector extends AbstractCollector {
public static final String NAME = "cluster-stats-collector";
private final LicensesManagerService licensesManagerService;
private final LicensesService licensesService;
private final Client client;
@Inject
public ClusterStatsCollector(Settings settings, ClusterService clusterService,
MonitoringSettings monitoringSettings, MonitoringLicensee licensee, InternalClient client,
LicensesManagerService licensesManagerService) {
LicensesService licensesService) {
super(settings, NAME, clusterService, monitoringSettings, licensee);
this.client = client;
this.licensesManagerService = licensesManagerService;
this.licensesService = licensesService;
}
@Override
@ -85,7 +85,7 @@ public class ClusterStatsCollector extends AbstractCollector {
clusterInfoDoc.setSourceNode(sourceNode);
clusterInfoDoc.setClusterName(clusterService.getClusterName().value());
clusterInfoDoc.setVersion(Version.CURRENT.toString());
clusterInfoDoc.setLicense(licensesManagerService.getLicense());
clusterInfoDoc.setLicense(licensesService.getLicense());
clusterInfoDoc.setClusterStats(clusterStats);
results.add(clusterInfoDoc);

View File

@ -68,6 +68,8 @@ public class IndexStatsCollector extends AbstractCollector {
.setSegments(true)
.setStore(true)
.setRefresh(true)
.setQueryCache(true)
.setRequestCache(true)
.get(monitoringSettings.indexStatsTimeout());
long timestamp = System.currentTimeMillis();

View File

@ -26,12 +26,22 @@ public class IndexStatsResolver extends MonitoringIndexNameResolver.Timestamped<
"index_stats.index",
"index_stats.primaries.docs.count",
"index_stats.primaries.fielddata.memory_size_in_bytes",
"index_stats.primaries.fielddata.evictions",
"index_stats.primaries.indexing.index_total",
"index_stats.primaries.indexing.index_time_in_millis",
"index_stats.primaries.indexing.throttle_time_in_millis",
"index_stats.primaries.merges.total_size_in_bytes",
"index_stats.primaries.query_cache.memory_size_in_bytes",
"index_stats.primaries.query_cache.evictions",
"index_stats.primaries.query_cache.hit_count",
"index_stats.primaries.query_cache.miss_count",
"index_stats.primaries.request_cache.memory_size_in_bytes",
"index_stats.primaries.request_cache.evictions",
"index_stats.primaries.request_cache.hit_count",
"index_stats.primaries.request_cache.miss_count",
"index_stats.primaries.search.query_total",
"index_stats.primaries.search.query_time_in_millis",
"index_stats.primaries.segments.count",
"index_stats.primaries.segments.memory_in_bytes",
"index_stats.primaries.segments.terms_memory_in_bytes",
"index_stats.primaries.segments.stored_fields_memory_in_bytes",
@ -47,12 +57,22 @@ public class IndexStatsResolver extends MonitoringIndexNameResolver.Timestamped<
"index_stats.primaries.refresh.total_time_in_millis",
"index_stats.total.docs.count",
"index_stats.total.fielddata.memory_size_in_bytes",
"index_stats.total.fielddata.evictions",
"index_stats.total.indexing.index_total",
"index_stats.total.indexing.index_time_in_millis",
"index_stats.total.indexing.throttle_time_in_millis",
"index_stats.total.merges.total_size_in_bytes",
"index_stats.total.query_cache.memory_size_in_bytes",
"index_stats.total.query_cache.evictions",
"index_stats.total.query_cache.hit_count",
"index_stats.total.query_cache.miss_count",
"index_stats.total.request_cache.memory_size_in_bytes",
"index_stats.total.request_cache.evictions",
"index_stats.total.request_cache.hit_count",
"index_stats.total.request_cache.miss_count",
"index_stats.total.search.query_total",
"index_stats.total.search.query_time_in_millis",
"index_stats.total.segments.count",
"index_stats.total.segments.memory_in_bytes",
"index_stats.total.segments.terms_memory_in_bytes",
"index_stats.total.segments.stored_fields_memory_in_bytes",

View File

@ -32,11 +32,21 @@ public class NodeStatsResolver extends MonitoringIndexNameResolver.Timestamped<N
"node_stats.disk_threshold_watermark_high",
// Node Stats
"node_stats.indices.docs.count",
"node_stats.indices.fielddata.memory_size_in_bytes",
"node_stats.indices.fielddata.evictions",
"node_stats.indices.store.size_in_bytes",
"node_stats.indices.store.throttle_time_in_millis",
"node_stats.indices.indexing.throttle_time_in_millis",
"node_stats.indices.indexing.index_total",
"node_stats.indices.indexing.index_time_in_millis",
"node_stats.indices.query_cache.memory_size_in_bytes",
"node_stats.indices.query_cache.evictions",
"node_stats.indices.query_cache.hit_count",
"node_stats.indices.query_cache.miss_count",
"node_stats.indices.request_cache.memory_size_in_bytes",
"node_stats.indices.request_cache.evictions",
"node_stats.indices.request_cache.hit_count",
"node_stats.indices.request_cache.miss_count",
"node_stats.indices.search.query_total",
"node_stats.indices.search.query_time_in_millis",
"node_stats.indices.segments.count",

View File

@ -109,6 +109,9 @@
"properties": {
"memory_size_in_bytes": {
"type": "long"
},
"evictions": {
"type": "long"
}
}
},
@ -142,6 +145,38 @@
}
}
},
"query_cache": {
"properties": {
"memory_size_in_bytes": {
"type": "long"
},
"evictions": {
"type": "long"
},
"hit_count": {
"type": "long"
},
"miss_count": {
"type": "long"
}
}
},
"request_cache": {
"properties": {
"memory_size_in_bytes": {
"type": "long"
},
"evictions": {
"type": "long"
},
"hit_count": {
"type": "long"
},
"miss_count": {
"type": "long"
}
}
},
"search": {
"properties": {
"query_total": {
@ -154,6 +189,9 @@
},
"segments": {
"properties": {
"count": {
"type": "integer"
},
"memory_in_bytes": {
"type": "long"
},
@ -205,6 +243,9 @@
"properties": {
"memory_size_in_bytes": {
"type": "long"
},
"evictions": {
"type": "long"
}
}
},
@ -238,6 +279,38 @@
}
}
},
"query_cache": {
"properties": {
"memory_size_in_bytes": {
"type": "long"
},
"evictions": {
"type": "long"
},
"hit_count": {
"type": "long"
},
"miss_count": {
"type": "long"
}
}
},
"request_cache": {
"properties": {
"memory_size_in_bytes": {
"type": "long"
},
"evictions": {
"type": "long"
},
"hit_count": {
"type": "long"
},
"miss_count": {
"type": "long"
}
}
},
"search": {
"properties": {
"query_total": {
@ -250,6 +323,9 @@
},
"segments": {
"properties": {
"count": {
"type": "integer"
},
"memory_in_bytes": {
"type": "long"
},
@ -374,6 +450,16 @@
}
}
},
"fielddata" : {
"properties": {
"memory_size_in_bytes": {
"type": "long"
},
"evictions": {
"type": "long"
}
}
},
"indexing": {
"properties": {
"index_time_in_millis": {
@ -387,6 +473,38 @@
}
}
},
"query_cache": {
"properties": {
"memory_size_in_bytes": {
"type": "long"
},
"evictions": {
"type": "long"
},
"hit_count": {
"type": "long"
},
"miss_count": {
"type": "long"
}
}
},
"request_cache": {
"properties": {
"memory_size_in_bytes": {
"type": "long"
},
"evictions": {
"type": "long"
},
"hit_count": {
"type": "long"
},
"miss_count": {
"type": "long"
}
}
},
"search": {
"properties": {
"query_time_in_millis": {
@ -400,7 +518,7 @@
"segments": {
"properties": {
"count": {
"type": "long"
"type": "integer"
},
"memory_in_bytes": {
"type": "long"

View File

@ -5,43 +5,45 @@
*/
package org.elasticsearch.xpack.monitoring.agent.collector;
import com.carrotsearch.randomizedtesting.RandomizedTest;
import com.carrotsearch.randomizedtesting.SysGlobals;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.cluster.block.ClusterBlocks;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.Licensing;
import org.elasticsearch.license.plugin.core.LicenseState;
import org.elasticsearch.license.plugin.core.Licensee;
import org.elasticsearch.license.plugin.core.LicenseeRegistry;
import org.elasticsearch.license.plugin.core.LicensesManagerService;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.rest.RestHandler;
import org.elasticsearch.xpack.security.InternalClient;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.monitoring.MonitoringSettings;
import org.elasticsearch.xpack.monitoring.test.MonitoringIntegTestCase;
import org.junit.Before;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import com.carrotsearch.randomizedtesting.RandomizedTest;
import com.carrotsearch.randomizedtesting.SysGlobals;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.cluster.block.ClusterBlocks;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.env.Environment;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.Licensing;
import org.elasticsearch.license.plugin.core.LicenseState;
import org.elasticsearch.license.plugin.core.Licensee;
import org.elasticsearch.license.plugin.core.LicensesService;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.rest.RestHandler;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.graph.GraphLicensee;
import org.elasticsearch.xpack.monitoring.MonitoringLicensee;
import org.elasticsearch.xpack.monitoring.MonitoringSettings;
import org.elasticsearch.xpack.monitoring.test.MonitoringIntegTestCase;
import org.elasticsearch.xpack.security.InternalClient;
import org.elasticsearch.xpack.security.SecurityLicenseState;
import org.elasticsearch.xpack.support.clock.Clock;
import org.elasticsearch.xpack.watcher.WatcherLicensee;
import org.junit.Before;
import static java.util.Collections.emptyList;
import static org.elasticsearch.common.unit.TimeValue.timeValueMinutes;
@ -57,7 +59,6 @@ public abstract class AbstractCollectorTestCase extends MonitoringIntegTestCase
protected Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(NetworkModule.HTTP_ENABLED.getKey(), false)
.put(MonitoringSettings.INTERVAL.getKey(), "-1")
.build();
}
@ -111,7 +112,7 @@ public abstract class AbstractCollectorTestCase extends MonitoringIntegTestCase
for (LicenseServiceForCollectors service : internalCluster().getInstances(LicenseServiceForCollectors.class)) {
service.onChange(license.operationMode(), LicenseState.ENABLED);
}
for (LicensesManagerServiceForCollectors service : internalCluster().getInstances(LicensesManagerServiceForCollectors.class)) {
for (LicenseServiceForCollectors service : internalCluster().getInstances(LicenseServiceForCollectors.class)) {
service.update(license);
}
}
@ -124,7 +125,7 @@ public abstract class AbstractCollectorTestCase extends MonitoringIntegTestCase
for (LicenseServiceForCollectors service : internalCluster().getInstances(LicenseServiceForCollectors.class)) {
service.onChange(license.operationMode(), LicenseState.GRACE_PERIOD);
}
for (LicensesManagerServiceForCollectors service : internalCluster().getInstances(LicensesManagerServiceForCollectors.class)) {
for (LicenseServiceForCollectors service : internalCluster().getInstances(LicenseServiceForCollectors.class)) {
service.update(license);
}
}
@ -137,7 +138,7 @@ public abstract class AbstractCollectorTestCase extends MonitoringIntegTestCase
for (LicenseServiceForCollectors service : internalCluster().getInstances(LicenseServiceForCollectors.class)) {
service.onChange(license.operationMode(), LicenseState.DISABLED);
}
for (LicensesManagerServiceForCollectors service : internalCluster().getInstances(LicensesManagerServiceForCollectors.class)) {
for (LicenseServiceForCollectors service : internalCluster().getInstances(LicenseServiceForCollectors.class)) {
service.update(license);
}
}
@ -150,7 +151,7 @@ public abstract class AbstractCollectorTestCase extends MonitoringIntegTestCase
for (LicenseServiceForCollectors service : internalCluster().getInstances(LicenseServiceForCollectors.class)) {
service.onChange(license.operationMode(), LicenseState.DISABLED);
}
for (LicensesManagerServiceForCollectors service : internalCluster().getInstances(LicensesManagerServiceForCollectors.class)) {
for (LicenseServiceForCollectors service : internalCluster().getInstances(LicenseServiceForCollectors.class)) {
service.update(license);
}
}
@ -191,16 +192,19 @@ public abstract class AbstractCollectorTestCase extends MonitoringIntegTestCase
@Override
public Collection<Module> nodeModules() {
return Collections.<Module>singletonList(new AbstractModule() {
return Collections.singletonList(b -> b.bind(LicensesService.class).to(LicenseServiceForCollectors.class));
}
@Override
protected void configure() {
bind(LicenseServiceForCollectors.class).asEagerSingleton();
bind(LicenseeRegistry.class).to(LicenseServiceForCollectors.class);
bind(LicensesManagerServiceForCollectors.class).asEagerSingleton();
bind(LicensesManagerService.class).to(LicensesManagerServiceForCollectors.class);
}
});
@Override
public Collection<Object> createComponents(ClusterService clusterService, Clock clock, Environment environment,
ResourceWatcherService resourceWatcherService,
SecurityLicenseState securityLicenseState) {
WatcherLicensee watcherLicensee = new WatcherLicensee(settings);
MonitoringLicensee monitoringLicensee = new MonitoringLicensee(settings);
GraphLicensee graphLicensee = new GraphLicensee(settings);
LicensesService licensesService = new LicenseServiceForCollectors(settings, environment,
resourceWatcherService, Arrays.asList(watcherLicensee, monitoringLicensee, graphLicensee));
return Arrays.asList(licensesService, watcherLicensee, monitoringLicensee, graphLicensee);
}
@Override
@ -212,11 +216,6 @@ public abstract class AbstractCollectorTestCase extends MonitoringIntegTestCase
public List<Class<? extends RestHandler>> getRestHandlers() {
return emptyList();
}
@Override
public Collection<Class<? extends LifecycleComponent>> nodeServices() {
return Collections.emptyList();
}
}
public static class InternalXPackPlugin extends XPackPlugin {
@ -227,18 +226,16 @@ public abstract class AbstractCollectorTestCase extends MonitoringIntegTestCase
}
}
public static class LicenseServiceForCollectors extends AbstractComponent implements LicenseeRegistry {
public static class LicenseServiceForCollectors extends LicensesService {
private final List<Licensee> licensees = new ArrayList<>();
private final List<Licensee> licensees;
private volatile License license;
@Inject
public LicenseServiceForCollectors(Settings settings) {
super(settings);
}
@Override
public void register(Licensee licensee) {
licensees.add(licensee);
public LicenseServiceForCollectors(Settings settings, Environment env,
ResourceWatcherService resourceWatcherService, List<Licensee> licensees) {
super(settings, null, null, env, resourceWatcherService, licensees);
this.licensees = licensees;
}
public void onChange(License.OperationMode operationMode, LicenseState state) {
@ -246,14 +243,9 @@ public abstract class AbstractCollectorTestCase extends MonitoringIntegTestCase
licensee.onChange(new Licensee.Status(operationMode, state));
}
}
}
public static class LicensesManagerServiceForCollectors implements LicensesManagerService {
private volatile License license;
@Override
public LicenseState licenseState() {
public Licensee.Status licenseeStatus() {
return null;
}
@ -265,5 +257,11 @@ public abstract class AbstractCollectorTestCase extends MonitoringIntegTestCase
public synchronized void update(License license) {
this.license = license;
}
@Override
protected void doStart() {}
@Override
protected void doStop() {}
}
}

View File

@ -5,11 +5,13 @@
*/
package org.elasticsearch.xpack.monitoring.agent.collector.cluster;
import java.util.Collection;
import org.apache.lucene.util.LuceneTestCase.BadApple;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.plugin.core.LicensesManagerService;
import org.elasticsearch.license.plugin.core.LicensesService;
import org.elasticsearch.xpack.monitoring.MonitoredSystem;
import org.elasticsearch.xpack.monitoring.MonitoringLicensee;
import org.elasticsearch.xpack.monitoring.MonitoringSettings;
@ -17,8 +19,6 @@ import org.elasticsearch.xpack.monitoring.agent.collector.AbstractCollector;
import org.elasticsearch.xpack.monitoring.agent.collector.AbstractCollectorTestCase;
import org.elasticsearch.xpack.monitoring.agent.exporter.MonitoringDoc;
import java.util.Collection;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasSize;
@ -133,7 +133,7 @@ public class ClusterStatsCollectorTests extends AbstractCollectorTestCase {
internalCluster().getInstance(MonitoringSettings.class, nodeId),
internalCluster().getInstance(MonitoringLicensee.class, nodeId),
securedClient(nodeId),
internalCluster().getInstance(LicensesManagerService.class, nodeId));
internalCluster().getInstance(LicensesService.class, nodeId));
}
private void assertCanCollect(AbstractCollector collector, Class<?>... classes) {

View File

@ -16,6 +16,7 @@ import org.elasticsearch.common.transport.LocalTransportAddress;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.cache.query.QueryCacheStats;
import org.elasticsearch.index.cache.request.RequestCacheStats;
import org.elasticsearch.index.engine.SegmentsStats;
import org.elasticsearch.index.fielddata.FieldDataStats;
import org.elasticsearch.index.merge.MergeStats;
@ -86,6 +87,7 @@ public class IndexStatsResolverTests extends MonitoringIndexNameResolverTestCase
CommonStats stats = new CommonStats();
stats.fieldData = new FieldDataStats();
stats.queryCache = new QueryCacheStats();
stats.requestCache = new RequestCacheStats();
stats.docs = new DocsStats();
stats.store = new StoreStats();
stats.indexing = new IndexingStats();

View File

@ -18,6 +18,7 @@ import org.elasticsearch.common.transport.LocalTransportAddress;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.cache.query.QueryCacheStats;
import org.elasticsearch.index.cache.request.RequestCacheStats;
import org.elasticsearch.index.engine.SegmentsStats;
import org.elasticsearch.index.fielddata.FieldDataStats;
import org.elasticsearch.index.search.stats.SearchStats;
@ -113,6 +114,7 @@ public class NodeStatsResolverTests extends MonitoringIndexNameResolverTestCase<
CommonStats stats = new CommonStats();
stats.fieldData = new FieldDataStats();
stats.queryCache = new QueryCacheStats();
stats.requestCache = new RequestCacheStats();
stats.docs = new DocsStats();
stats.store = new StoreStats();
stats.indexing = new IndexingStats();

View File

@ -10,12 +10,16 @@ import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.xpack.MockNetty3Plugin;
import org.elasticsearch.xpack.monitoring.MonitoringSettings;
import org.elasticsearch.xpack.monitoring.agent.AgentService;
import org.elasticsearch.xpack.monitoring.test.MonitoringIntegTestCase;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
@ -44,6 +48,13 @@ public class MonitoringSettingsTests extends MonitoringIntegTestCase {
.build();
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
ArrayList<Class<? extends Plugin>> plugins = new ArrayList<>(super.nodePlugins());
plugins.add(MockNetty3Plugin.class); // for http
return plugins;
}
private Settings monitoringSettings() {
return Settings.builder()
.put(MonitoringSettings.INTERVAL.getKey(), interval)

View File

@ -7,24 +7,28 @@ package org.elasticsearch.xpack.monitoring.license;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.Licensing;
import org.elasticsearch.license.plugin.core.AbstractLicenseeComponent;
import org.elasticsearch.license.plugin.core.LicenseState;
import org.elasticsearch.license.plugin.core.Licensee;
import org.elasticsearch.license.plugin.core.LicenseeRegistry;
import org.elasticsearch.license.plugin.core.LicensesManagerService;
import org.elasticsearch.license.plugin.core.LicensesService;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.rest.RestHandler;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.graph.GraphLicensee;
import org.elasticsearch.xpack.monitoring.MonitoringLicensee;
import org.elasticsearch.xpack.monitoring.test.MonitoringIntegTestCase;
import org.elasticsearch.xpack.security.SecurityLicenseState;
import org.elasticsearch.xpack.support.clock.Clock;
import org.elasticsearch.xpack.watcher.WatcherLicensee;
import java.io.IOException;
import java.util.ArrayList;
@ -92,7 +96,19 @@ public class LicenseIntegrationTests extends MonitoringIntegTestCase {
@Override
public Collection<Module> nodeModules() {
return Collections.<Module>singletonList(new InternalLicenseModule());
return Collections.singletonList(b -> b.bind(LicensesService.class).to(MockLicenseService.class));
}
@Override
public Collection<Object> createComponents(ClusterService clusterService, Clock clock, Environment environment,
ResourceWatcherService resourceWatcherService,
SecurityLicenseState securityLicenseState) {
WatcherLicensee watcherLicensee = new WatcherLicensee(settings);
MonitoringLicensee monitoringLicensee = new MonitoringLicensee(settings);
GraphLicensee graphLicensee = new GraphLicensee(settings);
LicensesService licensesService = new MockLicenseService(settings, environment, resourceWatcherService,
Arrays.asList(watcherLicensee, monitoringLicensee, graphLicensee));
return Arrays.asList(licensesService, watcherLicensee, monitoringLicensee, graphLicensee);
}
@Override
@ -104,36 +120,17 @@ public class LicenseIntegrationTests extends MonitoringIntegTestCase {
public List<Class<? extends RestHandler>> getRestHandlers() {
return emptyList();
}
@Override
public Collection<Class<? extends LifecycleComponent>> nodeServices() {
return Collections.emptyList();
}
}
public static class InternalLicenseModule extends AbstractModule {
@Override
protected void configure() {
bind(MockLicenseService.class).asEagerSingleton();
bind(LicenseeRegistry.class).to(MockLicenseService.class);
bind(LicensesManagerService.class).to(MockLicenseService.class);
}
}
public static class MockLicenseService extends LicensesService {
public static class MockLicenseService extends AbstractComponent implements LicenseeRegistry, LicensesManagerService {
private final List<Licensee> licensees = new ArrayList<>();
private final List<Licensee> licensees;
@Inject
public MockLicenseService(Settings settings) {
super(settings);
enable();
}
@Override
public void register(Licensee licensee) {
licensees.add(licensee);
public MockLicenseService(Settings settings, Environment environment,
ResourceWatcherService resourceWatcherService, List<Licensee> licensees) {
super(settings, null, null, environment, resourceWatcherService, licensees);
this.licensees = licensees;
enable();
}
@ -151,7 +148,7 @@ public class LicenseIntegrationTests extends MonitoringIntegTestCase {
}
@Override
public LicenseState licenseState() {
public Licensee.Status licenseeStatus() {
return null;
}
@ -159,6 +156,12 @@ public class LicenseIntegrationTests extends MonitoringIntegTestCase {
public License getLicense() {
return null;
}
@Override
protected void doStart() {}
@Override
protected void doStop() {}
}
public static class InternalXPackPlugin extends XPackPlugin {

View File

@ -10,7 +10,6 @@ import org.elasticsearch.license.core.License.OperationMode;
import org.elasticsearch.license.plugin.core.AbstractLicenseeTestCase;
import org.elasticsearch.license.plugin.core.LicenseState;
import org.elasticsearch.license.plugin.core.Licensee.Status;
import org.elasticsearch.license.plugin.core.LicenseeRegistry;
import org.elasticsearch.xpack.monitoring.MonitoringLicensee;
import java.util.function.Predicate;
@ -18,7 +17,6 @@ import java.util.function.Predicate;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
/**
@ -27,8 +25,7 @@ import static org.mockito.Mockito.when;
* If you change the behavior of these tests, then it means that licensing changes for Monitoring!
*/
public class MonitoringLicenseeTests extends AbstractLicenseeTestCase {
private final LicenseeRegistry registry = mock(LicenseeRegistry.class);
private final MonitoringLicensee licensee = new MonitoringLicensee(Settings.EMPTY, registry);
private final MonitoringLicensee licensee = new MonitoringLicensee(Settings.EMPTY);
public void testAcknowledgementMessagesToAnyFromFreeIsNoOp() {
assertEmptyAck(OperationMode.BASIC, randomMode(), licensee);
@ -93,7 +90,6 @@ public class MonitoringLicenseeTests extends AbstractLicenseeTestCase {
assertThat(predicate.test(licensee), equalTo(expected));
verify(status).getLicenseState();
verifyNoMoreInteractions(registry);
}
/**
@ -112,6 +108,5 @@ public class MonitoringLicenseeTests extends AbstractLicenseeTestCase {
assertThat(predicate.test(licensee), equalTo(expected));
verify(status).getMode();
verifyNoMoreInteractions(registry);
}
}

View File

@ -26,7 +26,6 @@ public class MonitoringInternalClientTests extends MonitoringIntegTestCase {
protected Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(NetworkModule.HTTP_ENABLED.getKey(), false)
.put(MonitoringSettings.INTERVAL.getKey(), "-1")
.build();
}

View File

@ -11,10 +11,14 @@ import org.elasticsearch.client.Response;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.xpack.MockNetty3Plugin;
import org.elasticsearch.xpack.monitoring.MonitoringSettings;
import org.elasticsearch.xpack.monitoring.test.MonitoringIntegTestCase;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import static org.elasticsearch.common.xcontent.support.XContentMapValues.extractValue;
@ -41,6 +45,13 @@ public class MonitoringSettingsFilterTests extends MonitoringIntegTestCase {
.build();
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
ArrayList<Class<? extends Plugin>> plugins = new ArrayList<>(super.nodePlugins());
plugins.add(MockNetty3Plugin.class); // for http
return plugins;
}
public void testGetSettingsFiltered() throws Exception {
Header[] headers;
if (securityEnabled) {

View File

@ -10,6 +10,7 @@ setup:
cluster.health:
index: ".monitoring-data-*"
wait_for_active_shards: 1
timeout: 60s
---
"Bulk indexing of monitoring data":

View File

@ -0,0 +1,104 @@
#!/bin/bash
# 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.
SCRIPT="$0"
# SCRIPT may be an arbitrarily deep series of symlinks. Loop until we have the concrete path.
while [ -h "$SCRIPT" ] ; do
ls=`ls -ld "$SCRIPT"`
# Drop everything prior to ->
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
SCRIPT="$link"
else
SCRIPT=`dirname "$SCRIPT"`/"$link"
fi
done
# determine elasticsearch home
ES_HOME=`dirname "$SCRIPT"`/../..
# make ELASTICSEARCH_HOME absolute
ES_HOME=`cd "$ES_HOME"; pwd`
# If an include wasn't specified in the environment, then search for one...
if [ "x$ES_INCLUDE" = "x" ]; then
# Locations (in order) to use when searching for an include file.
for include in /usr/share/elasticsearch/elasticsearch.in.sh \
/usr/local/share/elasticsearch/elasticsearch.in.sh \
/opt/elasticsearch/elasticsearch.in.sh \
~/.elasticsearch.in.sh \
"`dirname "$0"`"/../elasticsearch.in.sh \
"$ES_HOME/bin/elasticsearch.in.sh"; do
if [ -r "$include" ]; then
. "$include"
break
fi
done
# ...otherwise, source the specified include.
elif [ -r "$ES_INCLUDE" ]; then
. "$ES_INCLUDE"
fi
if [ -x "$JAVA_HOME/bin/java" ]; then
JAVA="$JAVA_HOME/bin/java"
else
JAVA=`which java`
fi
if [ ! -x "$JAVA" ]; then
echo "Could not find any executable java binary. Please install java in your PATH or set JAVA_HOME"
exit 1
fi
if [ -z "$ES_CLASSPATH" ]; then
echo "You must set the ES_CLASSPATH var" >&2
exit 1
fi
if [ -z "$CONF_DIR" ]; then
# Try to read package config files
if [ -f "/etc/sysconfig/elasticsearch" ]; then
CONF_DIR=/etc/elasticsearch
. "/etc/sysconfig/elasticsearch"
elif [ -f "/etc/default/elasticsearch" ]; then
CONF_DIR=/etc/elasticsearch
. "/etc/default/elasticsearch"
fi
fi
export HOSTNAME=`hostname -s`
# include x-pack jars in classpath
ES_CLASSPATH="$ES_CLASSPATH:$ES_HOME/plugins/x-pack/*"
# don't let JAVA_TOOL_OPTIONS slip in (e.g. crazy agents in ubuntu)
# works around https://bugs.launchpad.net/ubuntu/+source/jayatana/+bug/1441487
if [ "x$JAVA_TOOL_OPTIONS" != "x" ]; then
echo "Warning: Ignoring JAVA_TOOL_OPTIONS=$JAVA_TOOL_OPTIONS"
echo "Please pass JVM parameters via ES_JAVA_OPTS instead"
unset JAVA_TOOL_OPTIONS
fi
# CONF_FILE setting was removed
if [ ! -z "$CONF_FILE" ]; then
echo "CONF_FILE setting is no longer supported. elasticsearch.yml must be placed in the config directory and cannot be renamed."
exit 1
fi
declare -a args=("$@")
if [ -e "$CONF_DIR" ]; then
args=("${args[@]}" -Edefault.path.conf="$CONF_DIR")
fi
cd "$ES_HOME" > /dev/null
"$JAVA" $ES_JAVA_OPTS -cp "$ES_CLASSPATH" -Des.path.home="$ES_HOME" org.elasticsearch.xpack.security.ssl.CertificateTool "${args[@]}"
status=$?
cd - > /dev/null
exit $status

Binary file not shown.

View File

@ -59,15 +59,17 @@ if [ -z "$ES_CLASSPATH" ]; then
exit 1
fi
# Try to read package config files
if [ -f "/etc/sysconfig/elasticsearch" ]; then
CONF_DIR=/etc/elasticsearch
if [ -z "$CONF_DIR" ]; then
# Try to read package config files
if [ -f "/etc/sysconfig/elasticsearch" ]; then
CONF_DIR=/etc/elasticsearch
. "/etc/sysconfig/elasticsearch"
elif [ -f "/etc/default/elasticsearch" ]; then
CONF_DIR=/etc/elasticsearch
. "/etc/sysconfig/elasticsearch"
elif [ -f "/etc/default/elasticsearch" ]; then
CONF_DIR=/etc/elasticsearch
. "/etc/default/elasticsearch"
. "/etc/default/elasticsearch"
fi
fi
export HOSTNAME=`hostname -s`

View File

@ -59,15 +59,17 @@ if [ -z "$ES_CLASSPATH" ]; then
exit 1
fi
# Try to read package config files
if [ -f "/etc/sysconfig/elasticsearch" ]; then
CONF_DIR=/etc/elasticsearch
if [ -z "$CONF_DIR" ]; then
# Try to read package config files
if [ -f "/etc/sysconfig/elasticsearch" ]; then
CONF_DIR=/etc/elasticsearch
. "/etc/sysconfig/elasticsearch"
elif [ -f "/etc/default/elasticsearch" ]; then
CONF_DIR=/etc/elasticsearch
. "/etc/sysconfig/elasticsearch"
elif [ -f "/etc/default/elasticsearch" ]; then
CONF_DIR=/etc/elasticsearch
. "/etc/default/elasticsearch"
. "/etc/default/elasticsearch"
fi
fi
export HOSTNAME=`hostname -s`

View File

@ -59,15 +59,17 @@ if [ -z "$ES_CLASSPATH" ]; then
exit 1
fi
# Try to read package config files
if [ -f "/etc/sysconfig/elasticsearch" ]; then
CONF_DIR=/etc/elasticsearch
if [ -z "$CONF_DIR" ]; then
# Try to read package config files
if [ -f "/etc/sysconfig/elasticsearch" ]; then
CONF_DIR=/etc/elasticsearch
. "/etc/sysconfig/elasticsearch"
elif [ -f "/etc/default/elasticsearch" ]; then
CONF_DIR=/etc/elasticsearch
. "/etc/sysconfig/elasticsearch"
elif [ -f "/etc/default/elasticsearch" ]; then
CONF_DIR=/etc/elasticsearch
. "/etc/default/elasticsearch"
. "/etc/default/elasticsearch"
fi
fi
export HOSTNAME=`hostname -s`

View File

@ -5,6 +5,8 @@
*/
package org.elasticsearch.xpack.security;
import java.io.IOException;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.Action;
import org.elasticsearch.action.ActionListener;
@ -13,60 +15,57 @@ import org.elasticsearch.action.ActionRequestBuilder;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.FilterClient;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.user.XPackUser;
import org.elasticsearch.node.Node;
import org.elasticsearch.threadpool.ThreadPool;
import java.io.IOException;
import org.elasticsearch.xpack.security.authc.Authentication;
import org.elasticsearch.xpack.security.authc.InternalAuthenticationService;
import org.elasticsearch.xpack.security.crypto.CryptoService;
import org.elasticsearch.xpack.security.user.XPackUser;
/**
* A special filter client for internal node communication which adds the internal xpack user to the headers.
* An optionally secured client for internal node communication.
*
* When secured, the XPack user is added to the execution context before each action is executed.
*/
public interface InternalClient extends Client {
public class InternalClient extends FilterClient {
private final CryptoService cryptoService;
private final boolean signUserHeader;
private final String nodeName;
/**
* An insecured internal client, baseically simply delegates to the normal ES client
* without doing anything extra.
* Constructs an InternalClient.
* If {@code cryptoService} is non-null, the client is secure. Otherwise this client is a passthrough.
*/
class Insecure extends FilterClient implements InternalClient {
@Inject
public Insecure(Settings settings, ThreadPool threadPool, Client in) {
super(settings, threadPool, in);
}
public InternalClient(Settings settings, ThreadPool threadPool, Client in, CryptoService cryptoService) {
super(settings, threadPool, in);
this.cryptoService = cryptoService;
this.signUserHeader = InternalAuthenticationService.SIGN_USER_HEADER.get(settings);
this.nodeName = Node.NODE_NAME_SETTING.get(settings);
}
/**
* A secured internal client that binds the internal XPack user to the current
* execution context, before the action is executed.
*/
class Secure extends FilterClient implements InternalClient {
@Override
protected <Request extends ActionRequest<Request>, Response extends ActionResponse, RequestBuilder extends
ActionRequestBuilder<Request, Response, RequestBuilder>> void doExecute(
Action<Request, Response, RequestBuilder> action, Request request, ActionListener<Response> listener) {
private final AuthenticationService authcService;
@Inject
public Secure(Settings settings, ThreadPool threadPool, Client in, AuthenticationService authcService) {
super(settings, threadPool, in);
this.authcService = authcService;
if (cryptoService == null) {
super.doExecute(action, request, listener);
return;
}
@Override
protected <Request extends ActionRequest<Request>, Response extends ActionResponse, RequestBuilder extends
ActionRequestBuilder<Request, Response, RequestBuilder>> void doExecute(
Action<Request, Response, RequestBuilder> action, Request request, ActionListener<Response> listener) {
try (ThreadContext.StoredContext ctx = threadPool().getThreadContext().stashContext()) {
try {
authcService.attachUserIfMissing(XPackUser.INSTANCE);
} catch (IOException ioe) {
throw new ElasticsearchException("failed to attach internal user to request", ioe);
}
super.doExecute(action, request, listener);
try (ThreadContext.StoredContext ctx = threadPool().getThreadContext().stashContext()) {
try {
Authentication authentication = new Authentication(XPackUser.INSTANCE,
new Authentication.RealmRef("__attach", "__attach", nodeName), null);
authentication.writeToContextIfMissing(threadPool().getThreadContext(), cryptoService, signUserHeader);
} catch (IOException ioe) {
throw new ElasticsearchException("failed to attach internal user to request", ioe);
}
super.doExecute(action, request, listener);
}
}
}

View File

@ -10,14 +10,20 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.action.support.ActionFilter;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.Booleans;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.component.LifecycleComponent;
@ -34,9 +40,14 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
import org.elasticsearch.index.IndexModule;
import org.elasticsearch.ingest.Processor;
import org.elasticsearch.plugins.ActionPlugin;
import org.elasticsearch.plugins.IngestPlugin;
import org.elasticsearch.rest.RestHandler;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.extensions.XPackExtension;
import org.elasticsearch.xpack.security.action.SecurityActionModule;
import org.elasticsearch.xpack.security.action.filter.SecurityActionFilter;
import org.elasticsearch.xpack.security.action.realm.ClearRealmCacheAction;
@ -59,19 +70,28 @@ import org.elasticsearch.xpack.security.action.user.TransportChangePasswordActio
import org.elasticsearch.xpack.security.action.user.TransportDeleteUserAction;
import org.elasticsearch.xpack.security.action.user.TransportGetUsersAction;
import org.elasticsearch.xpack.security.action.user.TransportPutUserAction;
import org.elasticsearch.xpack.security.audit.AuditTrailModule;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail;
import org.elasticsearch.xpack.security.audit.index.IndexNameResolver;
import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail;
import org.elasticsearch.xpack.security.authc.AuthenticationModule;
import org.elasticsearch.xpack.security.authc.InternalAuthenticationService;
import org.elasticsearch.xpack.security.authc.Realm;
import org.elasticsearch.xpack.security.authc.Realms;
import org.elasticsearch.xpack.security.authc.activedirectory.ActiveDirectoryRealm;
import org.elasticsearch.xpack.security.authc.esnative.NativeRealm;
import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore;
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm;
import org.elasticsearch.xpack.security.authc.file.FileRealm;
import org.elasticsearch.xpack.security.authc.ldap.LdapRealm;
import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
import org.elasticsearch.xpack.security.authc.pki.PkiRealm;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.authz.AuthorizationModule;
import org.elasticsearch.xpack.security.authz.InternalAuthorizationService;
import org.elasticsearch.xpack.security.authz.accesscontrol.SetSecurityUserProcessor;
import org.elasticsearch.xpack.security.authz.accesscontrol.OptOutQueryCache;
import org.elasticsearch.xpack.security.authz.accesscontrol.SecurityIndexSearcherWrapper;
import org.elasticsearch.xpack.security.authz.store.FileRolesStore;
@ -88,15 +108,16 @@ import org.elasticsearch.xpack.security.rest.action.user.RestChangePasswordActio
import org.elasticsearch.xpack.security.rest.action.user.RestDeleteUserAction;
import org.elasticsearch.xpack.security.rest.action.user.RestGetUsersAction;
import org.elasticsearch.xpack.security.rest.action.user.RestPutUserAction;
import org.elasticsearch.xpack.security.ssl.ClientSSLService;
import org.elasticsearch.xpack.security.ssl.SSLConfiguration;
import org.elasticsearch.xpack.security.ssl.SSLModule;
import org.elasticsearch.xpack.security.ssl.ServerSSLService;
import org.elasticsearch.xpack.security.support.OptionalSettings;
import org.elasticsearch.xpack.security.transport.SecurityClientTransportService;
import org.elasticsearch.xpack.security.transport.SecurityServerTransportService;
import org.elasticsearch.xpack.security.transport.SecurityTransportModule;
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
import org.elasticsearch.xpack.security.transport.netty.SecurityNettyHttpServerTransport;
import org.elasticsearch.xpack.security.transport.netty.SecurityNettyTransport;
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport;
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
import org.elasticsearch.xpack.security.user.AnonymousUser;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
@ -107,7 +128,7 @@ import static java.util.Collections.singletonList;
/**
*
*/
public class Security implements ActionPlugin {
public class Security implements ActionPlugin, IngestPlugin {
private static final ESLogger logger = Loggers.getLogger(XPackPlugin.class);
@ -115,14 +136,24 @@ public class Security implements ActionPlugin {
public static final String DLS_FLS_FEATURE = "security.dls_fls";
public static final Setting<Optional<String>> USER_SETTING = OptionalSettings.createString(setting("user"), Property.NodeScope);
public static final Setting<Boolean> AUDIT_ENABLED_SETTING =
Setting.boolSetting(featureEnabledSetting("audit"), false, Property.NodeScope);
public static final Setting<List<String>> AUDIT_OUTPUTS_SETTING =
Setting.listSetting(setting("audit.outputs"),
s -> s.getAsMap().containsKey(setting("audit.outputs")) ?
Collections.emptyList() : Collections.singletonList(LoggingAuditTrail.NAME),
Function.identity(), Property.NodeScope);
private final Settings settings;
private final Environment env;
private final boolean enabled;
private final boolean transportClientMode;
private SecurityLicenseState securityLicenseState;
private final SecurityLicenseState securityLicenseState;
private final CryptoService cryptoService;
public Security(Settings settings, Environment env) throws IOException {
this.settings = settings;
this.env = env;
this.transportClientMode = XPackPlugin.transportClientMode(settings);
this.enabled = XPackPlugin.featureEnabled(settings, NAME, true);
if (enabled && transportClientMode == false) {
@ -131,6 +162,19 @@ public class Security implements ActionPlugin {
} else {
cryptoService = null;
}
securityLicenseState = new SecurityLicenseState();
}
public CryptoService getCryptoService() {
return cryptoService;
}
public SecurityLicenseState getSecurityLicenseState() {
return securityLicenseState;
}
public boolean isEnabled() {
return enabled;
}
public Collection<Module> nodeModules() {
@ -140,18 +184,31 @@ public class Security implements ActionPlugin {
if (enabled == false) {
return modules;
}
modules.add(new SecurityModule(settings, securityLicenseState));
modules.add(new SecurityModule(settings));
modules.add(new SecurityTransportModule(settings));
modules.add(new SSLModule(settings));
modules.add(b -> {
// for transport client we still must inject these ssl classes with guice
b.bind(ServerSSLService.class).toProvider(Providers.<ServerSSLService>of(null));
b.bind(ClientSSLService.class).toInstance(
new ClientSSLService(settings, null, new SSLConfiguration.Global(settings), null));
});
return modules;
}
modules.add(new AuthenticationModule(settings));
modules.add(new AuthorizationModule(settings));
if (enabled == false || auditingEnabled(settings) == false) {
modules.add(b -> {
b.bind(AuditTrailService.class).toProvider(Providers.of(null));
b.bind(AuditTrail.class).toInstance(AuditTrail.NOOP);
});
}
if (enabled == false) {
modules.add(b -> b.bind(CryptoService.class).toProvider(Providers.of(null)));
modules.add(new SecurityModule(settings, securityLicenseState));
modules.add(new AuditTrailModule(settings));
modules.add(b -> {
b.bind(CryptoService.class).toProvider(Providers.of(null));
});
modules.add(new SecurityModule(settings));
modules.add(new SecurityTransportModule(settings));
return modules;
}
@ -159,14 +216,20 @@ public class Security implements ActionPlugin {
// we can't load that at construction time since the license plugin might not have been loaded at that point
// which might not be the case during Plugin class instantiation. Once nodeModules are pulled
// everything should have been loaded
securityLicenseState = new SecurityLicenseState();
modules.add(b -> b.bind(CryptoService.class).toInstance(cryptoService));
modules.add(new SecurityModule(settings, securityLicenseState));
modules.add(new AuditTrailModule(settings));
modules.add(b -> {
b.bind(CryptoService.class).toInstance(cryptoService);
if (auditingEnabled(settings)) {
b.bind(AuditTrail.class).to(AuditTrailService.class); // interface used by some actions...
}
if (indexAuditLoggingEnabled(settings) == false) {
// TODO: remove this once we can construct SecurityLifecycleService without guice
b.bind(IndexAuditTrail.class).toProvider(Providers.of(null));
}
});
modules.add(new SecurityModule(settings));
modules.add(new SecurityRestModule(settings));
modules.add(new SecurityActionModule(settings));
modules.add(new SecurityTransportModule(settings));
modules.add(new SSLModule(settings));
return modules;
}
@ -175,17 +238,73 @@ public class Security implements ActionPlugin {
return Collections.emptyList();
}
List<Class<? extends LifecycleComponent>> list = new ArrayList<>();
//TODO why only focus on file audit logs? shouldn't we just check if audit trail is enabled in general?
if (AuditTrailModule.fileAuditLoggingEnabled(settings) == true) {
list.add(LoggingAuditTrail.class);
}
list.add(SecurityLicensee.class);
list.add(FileRolesStore.class);
list.add(Realms.class);
return list;
}
public Collection<Object> createComponents(InternalClient client, ThreadPool threadPool, ClusterService clusterService,
ResourceWatcherService resourceWatcherService, List<XPackExtension> extensions) {
if (enabled == false) {
return Collections.emptyList();
}
List<Object> components = new ArrayList<>();
final SSLConfiguration.Global globalSslConfig = new SSLConfiguration.Global(settings);
final ClientSSLService clientSSLService = new ClientSSLService(settings, env, globalSslConfig, resourceWatcherService);
final ServerSSLService serverSSLService = new ServerSSLService(settings, env, globalSslConfig, resourceWatcherService);
components.add(clientSSLService);
components.add(serverSSLService);
// realms construction
final NativeUsersStore nativeUsersStore = new NativeUsersStore(settings, client, threadPool);
final ReservedRealm reservedRealm = new ReservedRealm(env, settings, nativeUsersStore);
Map<String, Realm.Factory> realmFactories = new HashMap<>();
realmFactories.put(FileRealm.TYPE, config -> new FileRealm(config, resourceWatcherService));
realmFactories.put(NativeRealm.TYPE, config -> new NativeRealm(config, nativeUsersStore));
realmFactories.put(ActiveDirectoryRealm.TYPE,
config -> new ActiveDirectoryRealm(config, resourceWatcherService, clientSSLService));
realmFactories.put(LdapRealm.TYPE, config -> new LdapRealm(config, resourceWatcherService, clientSSLService));
realmFactories.put(PkiRealm.TYPE, config -> new PkiRealm(config, resourceWatcherService));
for (XPackExtension extension : extensions) {
Map<String, Realm.Factory> newRealms = extension.getRealms();
for (Map.Entry<String, Realm.Factory> entry : newRealms.entrySet()) {
if (realmFactories.put(entry.getKey(), entry.getValue()) != null) {
throw new IllegalArgumentException("Realm type [" + entry.getKey() + "] is already registered");
}
}
}
final Realms realms = new Realms(settings, env, realmFactories, securityLicenseState, reservedRealm);
components.add(nativeUsersStore);
components.add(realms);
// audit trails construction
if (AUDIT_ENABLED_SETTING.get(settings)) {
List<String> outputs = AUDIT_OUTPUTS_SETTING.get(settings);
if (outputs.isEmpty()) {
throw new IllegalArgumentException("Audit logging is enabled but there are zero output types in "
+ AUDIT_ENABLED_SETTING.getKey());
}
Set<AuditTrail> auditTrails = new LinkedHashSet<>();
for (String output : outputs) {
switch (output) {
case LoggingAuditTrail.NAME:
auditTrails.add(new LoggingAuditTrail(settings, clusterService, threadPool));
break;
case IndexAuditTrail.NAME:
IndexAuditTrail indexAuditTrail = new IndexAuditTrail(settings, client, threadPool, clusterService);
auditTrails.add(indexAuditTrail);
components.add(indexAuditTrail); // SecurityLifecycleService needs this....
break;
default:
throw new IllegalArgumentException("Unknown audit trail output [" + output + "]");
}
}
components.add(new AuditTrailService(settings, auditTrails.stream().collect(Collectors.toList()), securityLicenseState));
}
return components;
}
public Settings additionalSettings() {
if (enabled == false) {
return Settings.EMPTY;
@ -200,7 +319,7 @@ public class Security implements ActionPlugin {
settingsBuilder.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME);
settingsBuilder.put(NetworkModule.TRANSPORT_SERVICE_TYPE_KEY, Security.NAME);
settingsBuilder.put(NetworkModule.HTTP_TYPE_SETTING.getKey(), Security.NAME);
SecurityNettyHttpServerTransport.overrideSettings(settingsBuilder, settings);
SecurityNetty3HttpServerTransport.overrideSettings(settingsBuilder, settings);
addUserSettings(settings, settingsBuilder);
addTribeSettings(settings, settingsBuilder);
return settingsBuilder.build();
@ -216,7 +335,7 @@ public class Security implements ActionPlugin {
SSLConfiguration.Global.addSettings(settingsList);
// transport settings
SecurityNettyTransport.addSettings(settingsList);
SecurityNetty3Transport.addSettings(settingsList);
if (transportClientMode) {
return settingsList;
@ -229,7 +348,10 @@ public class Security implements ActionPlugin {
IPFilter.addSettings(settingsList);
// audit settings
AuditTrailModule.addSettings(settingsList);
settingsList.add(AUDIT_ENABLED_SETTING);
settingsList.add(AUDIT_OUTPUTS_SETTING);
LoggingAuditTrail.registerSettings(settingsList);
IndexAuditTrail.registerSettings(settingsList);
// authentication settings
FileRolesStore.addSettings(settingsList);
@ -241,7 +363,7 @@ public class Security implements ActionPlugin {
InternalAuthorizationService.addSettings(settingsList);
// HTTP settings
SecurityNettyHttpServerTransport.addSettings(settingsList);
SecurityNetty3HttpServerTransport.addSettings(settingsList);
// encryption settings
CryptoService.addSettings(settingsList);
@ -339,20 +461,25 @@ public class Security implements ActionPlugin {
RestChangePasswordAction.class);
}
@Override
public Map<String, Processor.Factory> getProcessors(Processor.Parameters parameters) {
return Collections.singletonMap(SetSecurityUserProcessor.TYPE, new SetSecurityUserProcessor.Factory(parameters.threadContext));
}
public void onModule(NetworkModule module) {
if (transportClientMode) {
if (enabled) {
module.registerTransport(Security.NAME, SecurityNettyTransport.class);
module.registerTransport(Security.NAME, SecurityNetty3Transport.class);
module.registerTransportService(Security.NAME, SecurityClientTransportService.class);
}
return;
}
if (enabled) {
module.registerTransport(Security.NAME, SecurityNettyTransport.class);
module.registerTransport(Security.NAME, SecurityNetty3Transport.class);
module.registerTransportService(Security.NAME, SecurityServerTransportService.class);
module.registerHttpTransport(Security.NAME, SecurityNettyHttpServerTransport.class);
module.registerHttpTransport(Security.NAME, SecurityNetty3HttpServerTransport.class);
}
}
@ -456,13 +583,29 @@ public class Security implements ActionPlugin {
return XPackPlugin.featureEnabledSetting("security." + feature);
}
public static boolean auditingEnabled(Settings settings) {
return AUDIT_ENABLED_SETTING.get(settings);
}
public static boolean indexAuditLoggingEnabled(Settings settings) {
if (auditingEnabled(settings)) {
List<String> outputs = AUDIT_OUTPUTS_SETTING.get(settings);
for (String output : outputs) {
if (output.equals(IndexAuditTrail.NAME)) {
return true;
}
}
}
return false;
}
static void validateAutoCreateIndex(Settings settings) {
String value = settings.get("action.auto_create_index");
if (value == null) {
return;
}
final boolean indexAuditingEnabled = AuditTrailModule.indexAuditLoggingEnabled(settings);
final boolean indexAuditingEnabled = Security.indexAuditLoggingEnabled(settings);
final String auditIndex = indexAuditingEnabled ? "," + IndexAuditTrail.INDEX_NAME_PREFIX + "*" : "";
String errorMessage = LoggerMessageFormat.format("the [action.auto_create_index] setting value [{}] is too" +
" restrictive. disable [action.auto_create_index] or set it to " +

View File

@ -21,8 +21,8 @@ import org.elasticsearch.xpack.XPackFeatureSet;
import org.elasticsearch.xpack.security.authz.store.RolesStore;
import org.elasticsearch.xpack.security.crypto.CryptoService;
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
import org.elasticsearch.xpack.security.transport.netty.SecurityNettyHttpServerTransport;
import org.elasticsearch.xpack.security.transport.netty.SecurityNettyTransport;
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3HttpServerTransport;
import org.elasticsearch.xpack.security.transport.netty3.SecurityNetty3Transport;
import java.io.IOException;
import java.util.ArrayList;
@ -122,8 +122,8 @@ public class SecurityFeatureSet implements XPackFeatureSet {
static Map<String, Object> sslUsage(Settings settings) {
Map<String, Object> map = new HashMap<>(2);
map.put("http", Collections.singletonMap("enabled", SecurityNettyHttpServerTransport.SSL_SETTING.get(settings)));
map.put("transport", Collections.singletonMap("enabled", SecurityNettyTransport.SSL_SETTING.get(settings)));
map.put("http", Collections.singletonMap("enabled", SecurityNetty3HttpServerTransport.SSL_SETTING.get(settings)));
map.put("transport", Collections.singletonMap("enabled", SecurityNetty3Transport.SSL_SETTING.get(settings)));
return map;
}

View File

@ -5,28 +5,21 @@
*/
package org.elasticsearch.xpack.security;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.core.AbstractLicenseeComponent;
import org.elasticsearch.license.plugin.core.Licensee;
import org.elasticsearch.license.plugin.core.LicenseeRegistry;
/**
*
*/
public class SecurityLicensee extends AbstractLicenseeComponent<SecurityLicensee> implements Licensee {
public class SecurityLicensee extends AbstractLicenseeComponent {
private final boolean isTribeNode;
private final SecurityLicenseState securityLicenseState;
@Inject
public SecurityLicensee(Settings settings, LicenseeRegistry clientService, SecurityLicenseState securityLicenseState) {
super(settings, Security.NAME, clientService);
public SecurityLicensee(Settings settings, SecurityLicenseState securityLicenseState) {
super(settings, Security.NAME);
this.securityLicenseState = securityLicenseState;
this.isTribeNode = settings.getGroups("tribe", true).isEmpty() == false;
}
@Override
@ -44,66 +37,50 @@ public class SecurityLicensee extends AbstractLicenseeComponent<SecurityLicensee
}
@Override
public String[] acknowledgmentMessages(License currentLicense, License newLicense) {
switch (newLicense.operationMode()) {
public String[] acknowledgmentMessages(License.OperationMode currentMode, License.OperationMode newMode) {
switch (newMode) {
case BASIC:
if (currentLicense != null) {
switch (currentLicense.operationMode()) {
case TRIAL:
case STANDARD:
case GOLD:
case PLATINUM:
return new String[] {
"The following X-Pack security functionality will be disabled: authentication, authorization, " +
"ip filtering, and auditing. Please restart your node after applying the license.",
"Field and document level access control will be disabled.",
"Custom realms will be ignored."
};
}
switch (currentMode) {
case TRIAL:
case STANDARD:
case GOLD:
case PLATINUM:
return new String[] {
"The following X-Pack security functionality will be disabled: authentication, authorization, " +
"ip filtering, and auditing. Please restart your node after applying the license.",
"Field and document level access control will be disabled.",
"Custom realms will be ignored."
};
}
break;
case GOLD:
if (currentLicense != null) {
switch (currentLicense.operationMode()) {
case BASIC:
case STANDARD:
// ^^ though technically it was already disabled, it's not bad to remind them
case TRIAL:
case PLATINUM:
return new String[] {
"Field and document level access control will be disabled.",
"Custom realms will be ignored."
};
}
switch (currentMode) {
case BASIC:
case STANDARD:
// ^^ though technically it was already disabled, it's not bad to remind them
case TRIAL:
case PLATINUM:
return new String[] {
"Field and document level access control will be disabled.",
"Custom realms will be ignored."
};
}
break;
case STANDARD:
if (currentLicense != null) {
switch (currentLicense.operationMode()) {
case BASIC:
// ^^ though technically it was already disabled, it's not bad to remind them
case GOLD:
case PLATINUM:
case TRIAL:
return new String[] {
"Authentication will be limited to the native realms.",
"IP filtering and auditing will be disabled.",
"Field and document level access control will be disabled.",
"Custom realms will be ignored."
};
}
switch (currentMode) {
case BASIC:
// ^^ though technically it was already disabled, it's not bad to remind them
case GOLD:
case PLATINUM:
case TRIAL:
return new String[] {
"Authentication will be limited to the native realms.",
"IP filtering and auditing will be disabled.",
"Field and document level access control will be disabled.",
"Custom realms will be ignored."
};
}
}
return Strings.EMPTY_ARRAY;
}
@Override
protected void doStart() throws ElasticsearchException {
// we rely on the initial licensee state to be enabled with trial operation mode
// to ensure no operation is blocked due to not registering the licensee on a
// tribe node
if (isTribeNode == false) {
super.doStart();
}
}
}

View File

@ -11,10 +11,9 @@ import org.elasticsearch.cluster.ClusterStateListener;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.component.LifecycleListener;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.Provider;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
import org.elasticsearch.xpack.security.audit.AuditTrailModule;
import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail;
import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore;
import org.elasticsearch.xpack.security.authz.store.NativeRolesStore;
@ -41,8 +40,8 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust
@Inject
public SecurityLifecycleService(Settings settings, ClusterService clusterService, ThreadPool threadPool,
IndexAuditTrail indexAuditTrail, NativeUsersStore nativeUserStore,
NativeRolesStore nativeRolesStore, Provider<InternalClient> clientProvider) {
@Nullable IndexAuditTrail indexAuditTrail, NativeUsersStore nativeUserStore,
NativeRolesStore nativeRolesStore, InternalClient client) {
super(settings);
this.settings = settings;
this.threadPool = threadPool;
@ -54,7 +53,7 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust
clusterService.add(this);
clusterService.add(nativeUserStore);
clusterService.add(nativeRolesStore);
clusterService.add(new SecurityTemplateService(settings, clusterService, clientProvider, threadPool));
clusterService.add(new SecurityTemplateService(settings, clusterService, client, threadPool));
clusterService.addLifecycleListener(new LifecycleListener() {
@Override
@ -111,7 +110,7 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust
}
try {
if (AuditTrailModule.indexAuditLoggingEnabled(settings) &&
if (Security.indexAuditLoggingEnabled(settings) &&
indexAuditTrail.state() == IndexAuditTrail.State.INITIALIZED) {
if (indexAuditTrail.canStart(event, master)) {
threadPool.generic().execute(new AbstractRunnable() {
@ -146,19 +145,23 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust
} catch (Exception e) {
logger.error("failed to stop native roles module", e);
}
try {
indexAuditTrail.stop();
} catch (Exception e) {
logger.error("failed to stop audit trail module", e);
if (indexAuditTrail != null) {
try {
indexAuditTrail.stop();
} catch (Exception e) {
logger.error("failed to stop audit trail module", e);
}
}
}
public void close() {
// There is no .close() method for the roles module
try {
indexAuditTrail.close();
} catch (Exception e) {
logger.error("failed to close audit trail module", e);
if (indexAuditTrail != null) {
try {
indexAuditTrail.close();
} catch (Exception e) {
logger.error("failed to close audit trail module", e);
}
}
}
}

View File

@ -5,21 +5,17 @@
*/
package org.elasticsearch.xpack.security;
import org.elasticsearch.common.inject.util.Providers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.security.support.AbstractSecurityModule;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.security.support.AbstractSecurityModule;
/**
*
*/
public class SecurityModule extends AbstractSecurityModule {
private final SecurityLicenseState securityLicenseState;
public SecurityModule(Settings settings, SecurityLicenseState securityLicenseState) {
public SecurityModule(Settings settings) {
super(settings);
this.securityLicenseState = securityLicenseState;
}
@Override
@ -28,24 +24,14 @@ public class SecurityModule extends AbstractSecurityModule {
return;
}
if (securityLicenseState != null) {
bind(SecurityLicenseState.class).toInstance(securityLicenseState);
} else {
bind(SecurityLicenseState.class).toProvider(Providers.<SecurityLicenseState>of(null));
}
XPackPlugin.bindFeatureSet(binder(), SecurityFeatureSet.class);
if (securityEnabled) {
bind(SecurityContext.Secure.class).asEagerSingleton();
bind(SecurityContext.class).to(SecurityContext.Secure.class);
bind(SecurityLifecycleService.class).asEagerSingleton();
bind(InternalClient.Secure.class).asEagerSingleton();
bind(InternalClient.class).to(InternalClient.Secure.class);
} else {
bind(SecurityContext.class).toInstance(SecurityContext.Insecure.INSTANCE);
bind(InternalClient.Insecure.class).asEagerSingleton();
bind(InternalClient.class).to(InternalClient.Insecure.class);
}
}

View File

@ -37,19 +37,18 @@ public class SecurityTemplateService extends AbstractComponent implements Cluste
public static final String SECURITY_TEMPLATE_NAME = "security-index-template";
private final ThreadPool threadPool;
private final Provider<InternalClient> clientProvider;
private final InternalClient client;
private final AtomicBoolean templateCreationPending = new AtomicBoolean(false);
public SecurityTemplateService(Settings settings, ClusterService clusterService,
Provider<InternalClient> clientProvider, ThreadPool threadPool) {
InternalClient client, ThreadPool threadPool) {
super(settings);
this.threadPool = threadPool;
this.clientProvider = clientProvider;
this.client = client;
clusterService.add(this);
}
private void createSecurityTemplate() {
final Client client = clientProvider.get();
try (InputStream is = getClass().getResourceAsStream("/" + SECURITY_TEMPLATE_NAME + ".json")) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Streams.copy(is, out);
@ -83,7 +82,8 @@ public class SecurityTemplateService extends AbstractComponent implements Cluste
if (securityIndexRouting == null) {
if (event.localNodeMaster()) {
ClusterState state = event.state();
// TODO for the future need to add some checking in the event the template needs to be updated...
// norelease we need to add some checking in the event the template needs to be updated and also the mappings need to be
// updated on index too!
IndexTemplateMetaData templateMeta = state.metaData().templates().get(SECURITY_TEMPLATE_NAME);
final boolean createTemplate = (templateMeta == null);

View File

@ -8,18 +8,19 @@ package org.elasticsearch.xpack.security.action.role;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.xpack.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.security.support.MetadataUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static org.elasticsearch.action.ValidateActions.addValidationError;
@ -33,6 +34,7 @@ public class PutRoleRequest extends ActionRequest<PutRoleRequest> implements Wri
private List<RoleDescriptor.IndicesPrivileges> indicesPrivileges = new ArrayList<>();
private String[] runAs = Strings.EMPTY_ARRAY;
private RefreshPolicy refreshPolicy = RefreshPolicy.IMMEDIATE;
private Map<String, Object> metadata;
public PutRoleRequest() {
}
@ -43,6 +45,10 @@ public class PutRoleRequest extends ActionRequest<PutRoleRequest> implements Wri
if (name == null) {
validationException = addValidationError("role name is missing", validationException);
}
if (metadata != null && MetadataUtils.containsReservedMetadata(metadata)) {
validationException =
addValidationError("metadata keys may not start with [" + MetadataUtils.RESERVED_PREFIX + "]", validationException);
}
return validationException;
}
@ -86,6 +92,10 @@ public class PutRoleRequest extends ActionRequest<PutRoleRequest> implements Wri
return refreshPolicy;
}
public void metadata(Map<String, Object> metadata) {
this.metadata = metadata;
}
public String name() {
return name;
}
@ -102,6 +112,10 @@ public class PutRoleRequest extends ActionRequest<PutRoleRequest> implements Wri
return runAs;
}
public Map<String, Object> metadata() {
return metadata;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
@ -114,6 +128,7 @@ public class PutRoleRequest extends ActionRequest<PutRoleRequest> implements Wri
}
runAs = in.readStringArray();
refreshPolicy = RefreshPolicy.readFrom(in);
metadata = in.readMap();
}
@Override
@ -127,12 +142,14 @@ public class PutRoleRequest extends ActionRequest<PutRoleRequest> implements Wri
}
out.writeStringArray(runAs);
refreshPolicy.writeTo(out);
out.writeMap(metadata);
}
RoleDescriptor roleDescriptor() {
return new RoleDescriptor(name,
clusterPrivileges,
indicesPrivileges.toArray(new RoleDescriptor.IndicesPrivileges[indicesPrivileges.size()]),
runAs);
runAs,
metadata);
}
}

View File

@ -12,6 +12,8 @@ import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.xpack.security.authz.RoleDescriptor;
import java.util.Map;
/**
* Builder for requests to add a role to the administrative index
*/
@ -33,6 +35,7 @@ public class PutRoleRequestBuilder extends ActionRequestBuilder<PutRoleRequest,
request.cluster(descriptor.getClusterPrivileges());
request.addIndex(descriptor.getIndicesPrivileges());
request.runAs(descriptor.getRunAs());
request.metadata(descriptor.getMetadata());
return this;
}
@ -56,4 +59,9 @@ public class PutRoleRequestBuilder extends ActionRequestBuilder<PutRoleRequest,
request.addIndex(indices, privileges, fields, query);
return this;
}
public PutRoleRequestBuilder metadata(Map<String, Object> metadata) {
request.metadata(metadata);
return this;
}
}

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