Merge branch 'master' into security/redirect-to-login-on-401-xhr-response

Original commit: elastic/x-pack-elasticsearch@4a14381b93
This commit is contained in:
Shaunak Kashyap 2016-07-26 15:05:29 -07:00
commit a1e80e18c9
449 changed files with 9497 additions and 9376 deletions

View File

@ -1,3 +1,5 @@
import org.elasticsearch.gradle.precommit.LicenseHeadersTask
File checkstyleSuppressions = file('checkstyle_suppressions.xml')
subprojects {
tasks.withType(Checkstyle) {
@ -7,4 +9,9 @@ subprojects {
suppressions: checkstyleSuppressions
]
}
tasks.withType(LicenseHeadersTask.class) {
approvedLicenses = ['Elasticsearch Confidential']
additionalLicense 'ESCON', 'Elasticsearch Confidential', 'ELASTICSEARCH CONFIDENTIAL'
}
}

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

@ -3,7 +3,5 @@ subprojects {
project.forbiddenPatterns {
exclude '**/*.key'
}
// someone figure out what the x-plugins logic should be
project.licenseHeaders.enabled = false
}
}

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

@ -38,11 +38,10 @@ public class IndexAuditIT extends ESIntegTestCase {
@AwaitsFix(bugUrl = "https://github.com/elastic/x-plugins/issues/2354")
public void testShieldIndexAuditTrailWorking() throws Exception {
try (Response response = getRestClient().performRequest("GET", "/",
Response response = getRestClient().performRequest("GET", "/",
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray()))))) {
assertThat(response.getStatusLine().getStatusCode(), is(200));
}
UsernamePasswordToken.basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray()))));
assertThat(response.getStatusLine().getStatusCode(), is(200));
final AtomicReference<ClusterState> lastClusterState = new AtomicReference<>();
final AtomicBoolean indexExists = new AtomicBoolean(false);
boolean found = awaitBusy(() -> {

View File

@ -1,6 +0,0 @@
subprojects {
tasks.withType(org.elasticsearch.gradle.precommit.LicenseHeadersTask) {
// someone figure out what the x-plugins logic should be
project.licenseHeaders.enabled = false
}
}

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

@ -7,29 +7,30 @@ package org.elasticsearch.xpack.security;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.parser.RestTestParseException;
import java.io.IOException;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
public class RestIT extends ESRestTestCase {
public class CoreWithSecurityClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
private static final String USER = "test_user";
private static final String PASS = "changeme";
public RestIT(@Name("yaml") RestTestCandidate testCandidate) {
public CoreWithSecurityClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException {
return ESRestTestCase.createParameters(0, 1);
public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESClientYamlSuiteTestCase.createParameters(0, 1);
}
@Override

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

@ -1,215 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.messy.tests;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.groovy.GroovyPlugin;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.xpack.watcher.history.HistoryStore;
import org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.transport.actions.execute.ExecuteWatchResponse;
import org.elasticsearch.xpack.watcher.transport.actions.put.PutWatchResponse;
import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTriggerEvent;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import java.util.List;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
import static org.elasticsearch.search.aggregations.AggregationBuilders.dateHistogram;
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
import static org.elasticsearch.xpack.watcher.actions.ActionBuilders.indexAction;
import static org.elasticsearch.xpack.watcher.client.WatchSourceBuilders.watchBuilder;
import static org.elasticsearch.xpack.watcher.input.InputBuilders.searchInput;
import static org.elasticsearch.xpack.watcher.input.InputBuilders.simpleInput;
import static org.elasticsearch.xpack.watcher.transform.TransformBuilders.scriptTransform;
import static org.elasticsearch.xpack.watcher.trigger.TriggerBuilders.schedule;
import static org.elasticsearch.xpack.watcher.trigger.schedule.Schedules.cron;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.is;
/**
*
*/
public class IndexActionIT extends AbstractWatcherIntegrationTestCase {
@Override
protected List<Class<? extends Plugin>> pluginTypes() {
List<Class<? extends Plugin>> types = super.pluginTypes();
types.add(GroovyPlugin.class);
return types;
}
public void testSimple() throws Exception {
PutWatchResponse putWatchResponse = watcherClient().preparePutWatch("_id").setSource(watchBuilder()
.trigger(schedule(cron("0/1 * * * * ? 2020")))
.input(simpleInput("foo", "bar"))
.addAction("index-buckets", indexAction("idx", "type").setExecutionTimeField("@timestamp")))
.get();
assertThat(putWatchResponse.isCreated(), is(true));
DateTime now = timeWarped() ? timeWarp().clock().now(DateTimeZone.UTC) : DateTime.now(DateTimeZone.UTC);
ExecuteWatchResponse executeWatchResponse = watcherClient().prepareExecuteWatch("_id")
.setTriggerEvent(new ScheduleTriggerEvent(now, now))
.get();
assertThat(executeWatchResponse.getRecordSource().getValue("state"), is((Object) "executed"));
flush("idx");
refresh();
SearchResponse searchResponse = client().prepareSearch("idx").setTypes("type").get();
assertThat(searchResponse.getHits().totalHits(), is(1L));
SearchHit hit = searchResponse.getHits().getAt(0);
if (timeWarped()) {
assertThat(hit.getSource(), hasEntry("@timestamp", (Object) WatcherDateTimeUtils.formatDate(now)));
} else {
assertThat(hit.getSource(), hasKey("@timestamp"));
DateTime timestamp = WatcherDateTimeUtils.parseDate((String) hit.getSource().get("@timestamp"));
assertThat(timestamp.isEqual(now) || timestamp.isAfter(now), is(true));
}
assertThat(hit.getSource(), hasEntry("foo", (Object) "bar"));
}
public void testSimpleWithDocField() throws Exception {
PutWatchResponse putWatchResponse = watcherClient().preparePutWatch("_id").setSource(watchBuilder()
.trigger(schedule(cron("0/1 * * * * ? 2020")))
.input(simpleInput("foo", "bar"))
.addAction("index-buckets",
scriptTransform("return [ '_doc' : ctx.payload ]"),
indexAction("idx", "type").setExecutionTimeField("@timestamp")))
.get();
assertThat(putWatchResponse.isCreated(), is(true));
DateTime now = timeWarped() ? timeWarp().clock().now(DateTimeZone.UTC) : DateTime.now(DateTimeZone.UTC);
ExecuteWatchResponse executeWatchResponse = watcherClient().prepareExecuteWatch("_id")
.setTriggerEvent(new ScheduleTriggerEvent(now, now))
.get();
assertThat(executeWatchResponse.getRecordSource().getValue("state"), is((Object) "executed"));
flush("idx");
refresh();
SearchResponse searchResponse = client().prepareSearch("idx").setTypes("type").get();
assertThat(searchResponse.getHits().totalHits(), is(1L));
SearchHit hit = searchResponse.getHits().getAt(0);
if (timeWarped()) {
assertThat(hit.getSource(), hasEntry("@timestamp", (Object) WatcherDateTimeUtils.formatDate(now)));
} else {
assertThat(hit.getSource(), hasKey("@timestamp"));
DateTime timestamp = WatcherDateTimeUtils.parseDate((String) hit.getSource().get("@timestamp"));
assertThat(timestamp.isEqual(now) || timestamp.isAfter(now), is(true));
}
assertThat(hit.getSource(), hasEntry("foo", (Object) "bar"));
}
public void testSimpleWithDocFieldWrongFieldType() throws Exception {
PutWatchResponse putWatchResponse = watcherClient().preparePutWatch("_id").setSource(watchBuilder()
.trigger(schedule(cron("0/1 * * * * ? 2020")))
.input(simpleInput("foo", "bar"))
.addAction("index-buckets",
scriptTransform("return [ '_doc' : 1 ]"),
indexAction("idx", "type").setExecutionTimeField("@timestamp")))
.get();
assertThat(putWatchResponse.isCreated(), is(true));
DateTime now = timeWarped() ? timeWarp().clock().now(DateTimeZone.UTC) : DateTime.now(DateTimeZone.UTC);
ExecuteWatchResponse executeWatchResponse = watcherClient().prepareExecuteWatch("_id")
.setTriggerEvent(new ScheduleTriggerEvent(now, now))
.setRecordExecution(true)
.get();
assertThat(executeWatchResponse.getRecordSource().getValue("state"), is((Object) "executed"));
flush();
refresh();
assertThat(client().admin().indices().prepareExists("idx").get().isExists(), is(false));
assertThat(docCount(HistoryStore.INDEX_PREFIX + "*", HistoryStore.DOC_TYPE, searchSource()
.query(matchQuery("result.actions.status", "failure"))), is(1L));
}
public void testIndexAggsBucketsAsDocuments() throws Exception {
DateTime now = timeWarped() ? timeWarp().clock().now(DateTimeZone.UTC) : DateTime.now(DateTimeZone.UTC);
long bucketCount = randomIntBetween(2, 5);
for (int i = 0; i < bucketCount; i++) {
index("idx", "type", jsonBuilder().startObject()
.field("timestamp", now.minusDays(i))
.endObject());
}
flush("idx");
refresh();
PutWatchResponse putWatchResponse = watcherClient().preparePutWatch("_id").setSource(watchBuilder()
.trigger(schedule(cron("0/1 * * * * ? 2020")))
.input(searchInput(new SearchRequest("idx")
.types("type")
.searchType(SearchType.QUERY_THEN_FETCH)
.source(searchSource()
.aggregation(dateHistogram("trend")
.field("timestamp")
.dateHistogramInterval(DateHistogramInterval.DAY)))))
.addAction("index-buckets",
// this transform takes the bucket list and assigns it to `_doc`
// this means each bucket will be indexed as a separate doc,
// so we expect to have the same number of documents as the number
// of buckets.
scriptTransform("return [ '_doc' : ctx.payload.aggregations.trend.buckets]"),
indexAction("idx", "bucket").setExecutionTimeField("@timestamp")))
.get();
assertThat(putWatchResponse.isCreated(), is(true));
ExecuteWatchResponse executeWatchResponse = watcherClient().prepareExecuteWatch("_id")
.setTriggerEvent(new ScheduleTriggerEvent(now, now))
.get();
assertThat(executeWatchResponse.getRecordSource().getValue("state"), is((Object) "executed"));
flush("idx");
refresh();
SearchResponse searchResponse = client().prepareSearch("idx").setTypes("bucket")
.addSort("key", SortOrder.DESC)
.get();
assertThat(searchResponse.getHits().getTotalHits(), is(bucketCount));
DateTime key = now.withMillisOfDay(0);
int i = 0;
for (SearchHit hit : searchResponse.getHits()) {
if (timeWarped()) {
assertThat(hit.getSource(), hasEntry("@timestamp", (Object) WatcherDateTimeUtils.formatDate(now)));
} else {
assertThat(hit.getSource(), hasKey("@timestamp"));
DateTime timestamp = WatcherDateTimeUtils.parseDate((String) hit.getSource().get("@timestamp"));
assertThat(timestamp.isEqual(now) || timestamp.isAfter(now), is(true));
}
assertThat(hit.getSource(), hasEntry("key", (Object) key.getMillis()));
key = key.minusDays(1);
}
}
}

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

@ -158,7 +158,7 @@ public class WatchAckIT extends AbstractWatcherIntegrationTestCase {
assertThat(parsedWatch.status().actionStatus("_a2").ackStatus().state(),
is(ActionStatus.AckStatus.State.AWAITS_SUCCESSFUL_EXECUTION));
long throttledCount = docCount(HistoryStore.INDEX_PREFIX + "*", null,
long throttledCount = docCount(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*", null,
matchQuery(WatchRecord.Field.STATE.getPreferredName(), ExecutionState.THROTTLED.id()));
assertThat(throttledCount, greaterThan(0L));
}
@ -240,7 +240,7 @@ public class WatchAckIT extends AbstractWatcherIntegrationTestCase {
assertThat(parsedWatch.status().actionStatus("_a2").ackStatus().state(),
is(ActionStatus.AckStatus.State.AWAITS_SUCCESSFUL_EXECUTION));
long throttledCount = docCount(HistoryStore.INDEX_PREFIX + "*", null,
long throttledCount = docCount(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*", null,
matchQuery(WatchRecord.Field.STATE.getPreferredName(), ExecutionState.THROTTLED.id()));
assertThat(throttledCount, greaterThan(0L));
}

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

@ -7,28 +7,29 @@ package org.elasticsearch.xpack.security;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.parser.RestTestParseException;
import java.io.IOException;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
public class RestIT extends ESRestTestCase {
public class ReindexWithSecurityClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
private static final String USER = "test_admin";
private static final String PASS = "changeme";
public RestIT(@Name("yaml") RestTestCandidate testCandidate) {
public ReindexWithSecurityClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException {
return ESRestTestCase.createParameters(0, 1);
public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESClientYamlSuiteTestCase.createParameters(0, 1);
}
/**

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.security.authc.AuthenticationFailureHandler;
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";
@ -25,13 +38,18 @@ public class ExampleRealmExtension extends XPackExtension {
return "a very basic implementation of a custom realm to validate it works";
}
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 AuthenticationFailureHandler getAuthenticationFailureHandler() {
return new CustomAuthenticationFailureHandler();
}
@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;
@ -58,11 +60,10 @@ public class CustomRealmIT extends ESIntegTestCase {
}
public void testHttpAuthentication() throws Exception {
try (Response response = getRestClient().performRequest("GET", "/",
Response response = getRestClient().performRequest("GET", "/",
new BasicHeader(CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER),
new BasicHeader(CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW))) {
assertThat(response.getStatusLine().getStatusCode(), is(200));
}
new BasicHeader(CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW));
assertThat(response.getStatusLine().getStatusCode(), is(200));
}
public void testTransportClient() throws Exception {
@ -78,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));
@ -98,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

@ -7,31 +7,31 @@ package org.elasticsearch.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.parser.RestTestParseException;
import java.io.IOException;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
public class GraphWithSecurityIT extends ESRestTestCase {
public class GraphWithSecurityIT extends ESClientYamlSuiteTestCase {
private static final String TEST_ADMIN_USERNAME = "test_admin";
private static final String TEST_ADMIN_PASSWORD = "changeme";
public GraphWithSecurityIT(@Name("yaml") RestTestCandidate testCandidate) {
public GraphWithSecurityIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException {
return ESRestTestCase.createParameters(0, 1);
public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESClientYamlSuiteTestCase.createParameters(0, 1);
}
protected String[] getCredentials() {

View File

@ -6,7 +6,8 @@
package org.elasticsearch.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name;
import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import java.io.IOException;
@ -14,14 +15,14 @@ import static org.hamcrest.Matchers.containsString;
public class GraphWithSecurityInsufficientRoleIT extends GraphWithSecurityIT {
public GraphWithSecurityInsufficientRoleIT(@Name("yaml") RestTestCandidate testCandidate) {
public GraphWithSecurityInsufficientRoleIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
public void test() throws IOException {
try {
super.test();
fail();
fail("should have failed because of missing role");
} catch(AssertionError ae) {
assertThat(ae.getMessage(), containsString("action [indices:data/read/xpack/graph/explore"));
assertThat(ae.getMessage(), containsString("returned [403 Forbidden]"));

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

@ -7,27 +7,28 @@ package org.elasticsearch.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.parser.RestTestParseException;
import java.io.IOException;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.hamcrest.Matchers.containsString;
public class MonitoringWithSecurityInsufficientRoleIT extends ESRestTestCase {
public class SmokeTestMonitoringWithSecurityClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
public MonitoringWithSecurityInsufficientRoleIT(@Name("yaml") RestTestCandidate testCandidate) {
public SmokeTestMonitoringWithSecurityClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException {
return ESRestTestCase.createParameters(0, 1);
public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESClientYamlSuiteTestCase.createParameters(0, 1);
}
@Override

View File

@ -7,26 +7,27 @@ package org.elasticsearch.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.parser.RestTestParseException;
import java.io.IOException;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
public class MonitoringWithSecurityIT extends ESRestTestCase {
public class SmokeTestMonitoringWithSecurityClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
public MonitoringWithSecurityIT(@Name("yaml") RestTestCandidate testCandidate) {
public SmokeTestMonitoringWithSecurityClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException {
return ESRestTestCase.createParameters(0, 1);
public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESClientYamlSuiteTestCase.createParameters(0, 1);
}
@Override

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

@ -7,15 +7,16 @@ package org.elasticsearch.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.client.RestTestClient;
import org.elasticsearch.test.rest.parser.RestTestParseException;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@ -26,19 +27,19 @@ import java.nio.file.Path;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
public class SmokeTestPluginsSslIT extends ESRestTestCase {
public class SmokeTestPluginsSslClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
private static final String USER = "test_user";
private static final String PASS = "changeme";
private static final String KEYSTORE_PASS = "keypass";
public SmokeTestPluginsSslIT(@Name("yaml") RestTestCandidate testCandidate) {
public SmokeTestPluginsSslClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException {
return ESRestTestCase.createParameters(0, 1);
public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESClientYamlSuiteTestCase.createParameters(0, 1);
}
static Path keyStore;
@ -46,7 +47,7 @@ public class SmokeTestPluginsSslIT extends ESRestTestCase {
@BeforeClass
public static void getKeyStore() {
try {
keyStore = PathUtils.get(SmokeTestPluginsSslIT.class.getResource("/test-node.jks").toURI());
keyStore = PathUtils.get(SmokeTestPluginsSslClientYamlTestSuiteIT.class.getResource("/test-node.jks").toURI());
} catch (URISyntaxException e) {
throw new ElasticsearchException("exception while reading the store", e);
}
@ -65,9 +66,13 @@ public class SmokeTestPluginsSslIT extends ESRestTestCase {
String token = basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray()));
return Settings.builder()
.put(ThreadContext.PREFIX + ".Authorization", token)
.put(RestTestClient.PROTOCOL, "https")
.put(RestTestClient.TRUSTSTORE_PATH, keyStore)
.put(RestTestClient.TRUSTSTORE_PASSWORD, KEYSTORE_PASS)
.put(ESRestTestCase.TRUSTSTORE_PATH, keyStore)
.put(ESRestTestCase.TRUSTSTORE_PASSWORD, KEYSTORE_PASS)
.build();
}
@Override
protected String getProtocol() {
return "https";
}
}

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,29 +7,30 @@ package org.elasticsearch.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.parser.RestTestParseException;
import java.io.IOException;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
public class SmokeTestPluginsIT extends ESRestTestCase {
public class XSmokeTestPluginsClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
private static final String USER = "test_user";
private static final String PASS = "changeme";
public SmokeTestPluginsIT(@Name("yaml") RestTestCandidate testCandidate) {
public XSmokeTestPluginsClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException {
return ESRestTestCase.createParameters(0, 1);
public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESClientYamlSuiteTestCase.createParameters(0, 1);
}
@Override

View File

@ -0,0 +1,27 @@
apply plugin: 'elasticsearch.rest-test'
dependencies {
testCompile project(path: ':x-plugins:elasticsearch:x-pack', configuration: 'runtime')
testCompile project(path: ':modules:lang-mustache', configuration: 'runtime')
}
integTest {
cluster {
plugin ':x-plugins:elasticsearch:x-pack'
setting 'xpack.watcher.enabled', 'false'
setting 'xpack.monitoring.enabled', 'false'
setting 'path.scripts', "${project.buildDir}/resources/test/templates"
setupCommand 'setupDummyUser',
'bin/x-pack/users', 'useradd', 'test_admin', '-p', 'changeme', '-r', 'superuser'
waitCondition = { node, ant ->
File tmpFile = new File(node.cwd, 'wait.success')
ant.get(src: "http://${node.httpUri()}",
dest: tmpFile.toString(),
username: 'test_admin',
password: 'changeme',
ignoreerrors: true,
retries: 10)
return tmpFile.exists()
}
}
}

View File

@ -0,0 +1,41 @@
/*
* 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.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import java.io.IOException;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
public class SmokeTestSecurityWithMustacheClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
private static final String BASIC_AUTH_VALUE = basicAuthHeaderValue("test_admin", new SecuredString("changeme".toCharArray()));
public SmokeTestSecurityWithMustacheClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESClientYamlSuiteTestCase.createParameters(0, 1);
}
@Override
protected Settings restClientSettings() {
return Settings.builder()
.put(ThreadContext.PREFIX + ".Authorization", BASIC_AUTH_VALUE)
.build();
}
}

View File

@ -0,0 +1,191 @@
---
setup:
- skip:
features: headers
- do:
cluster.health:
wait_for_status: yellow
- do:
xpack.security.put_user:
username: "inline_template_user"
body: >
{
"password": "changeme",
"roles" : [ "inline_template_role" ]
}
- do:
xpack.security.put_user:
username: "stored_template_user"
body: >
{
"password": "changeme",
"roles" : [ "stored_template_role" ]
}
- do:
xpack.security.put_user:
username: "file_template_user"
body: >
{
"password": "changeme",
"roles" : [ "file_template_role" ]
}
- do:
xpack.security.put_role:
name: "inline_template_role"
body: >
{
"indices": [
{
"names": "foobar",
"privileges": ["all"],
"query" : {
"template" : {
"inline" : {
"term" : { "username" : "{{_user.username}}" }
}
}
}
}
]
}
- do:
xpack.security.put_role:
name: "stored_template_role"
body: >
{
"indices": [
{
"names": "foobar",
"privileges": ["all"],
"query" : {
"template" : {
"id" : "1"
}
}
}
]
}
- do:
xpack.security.put_role:
name: "file_template_role"
body: >
{
"indices": [
{
"names": "foobar",
"privileges": ["all"],
"query" : {
"template" : {
"file" : "query"
}
}
}
]
}
- do:
put_template:
id: "1"
body: >
{
"term" : {
"username" : "{{_user.username}}"
}
}
- do:
index:
index: foobar
type: type
id: 1
body: >
{
"username": "inline_template_user"
}
- do:
index:
index: foobar
type: type
id: 2
body: >
{
"username": "stored_template_user"
}
- do:
index:
index: foobar
type: type
id: 3
body: >
{
"username": "file_template_user"
}
- do:
indices.refresh: {}
---
teardown:
- do:
xpack.security.delete_user:
username: "inline_template_user"
ignore: 404
- do:
xpack.security.delete_user:
username: "stored_template_user"
ignore: 404
- do:
xpack.security.delete_user:
username: "file_template_user"
ignore: 404
- do:
xpack.security.delete_role:
name: "inline_template_role"
ignore: 404
- do:
xpack.security.delete_role:
name: "stored_template_role"
ignore: 404
- do:
xpack.security.delete_role:
name: "file_template_role"
ignore: 404
---
"Test inline template":
- do:
headers:
Authorization: "Basic aW5saW5lX3RlbXBsYXRlX3VzZXI6Y2hhbmdlbWU="
search:
index: foobar
body: { "query" : { "match_all" : {} } }
- match: { hits.total: 1}
- match: { hits.hits.0._source.username: inline_template_user}
---
"Test stored template":
- do:
headers:
Authorization: "Basic c3RvcmVkX3RlbXBsYXRlX3VzZXI6Y2hhbmdlbWU="
search:
index: foobar
body: { "query" : { "match_all" : {} } }
- match: { hits.total: 1}
- match: { hits.hits.0._source.username: stored_template_user}
---
"Test file template":
- do:
headers:
Authorization: "Basic ZmlsZV90ZW1wbGF0ZV91c2VyOmNoYW5nZW1l"
search:
index: foobar
body: { "query" : { "match_all" : {} } }
- match: { hits.total: 1}
- match: { hits.hits.0._source.username: file_template_user}

View File

@ -0,0 +1,198 @@
---
setup:
- skip:
features: headers
- do:
indices.create:
index: shared_logs
- do:
cluster.health:
wait_for_status: yellow
- do:
ingest.put_pipeline:
id: "my_pipeline"
body: >
{
"processors": [
{
"set_security_user" : {
"field" : "user"
}
}
]
}
- do:
xpack.security.put_user:
username: "joe"
body: >
{
"password": "changeme",
"roles" : [ "small_companies_role" ],
"metadata" : {
"customer_id" : "1"
}
}
- do:
xpack.security.put_user:
username: "john"
body: >
{
"password": "changeme",
"roles" : [ "small_companies_role" ],
"metadata" : {
"customer_id" : "2"
}
}
---
teardown:
- do:
xpack.security.delete_user:
username: "joe"
ignore: 404
- do:
xpack.security.delete_user:
username: "john"
ignore: 404
- do:
xpack.security.delete_role:
name: "small_companies_role"
ignore: 404
---
"Test shared index seperating user by using DLS role query with user's username":
- do:
xpack.security.put_role:
name: "small_companies_role"
body: >
{
"indices": [
{
"names": "shared_logs",
"privileges": ["read", "create"],
"query" : {
"template" : {
"inline" : {
"term" : { "user.username" : "{{_user.username}}" }
}
}
}
}
]
}
- do:
headers:
Authorization: "Basic am9lOmNoYW5nZW1l"
index:
index: shared_logs
type: type
pipeline: "my_pipeline"
body: >
{
"log": "Joe's first log entry"
}
- do:
headers:
Authorization: "Basic am9objpjaGFuZ2VtZQ=="
index:
index: shared_logs
type: type
pipeline: "my_pipeline"
body: >
{
"log": "John's first log entry"
}
- do:
indices.refresh: {}
# Joe searches:
- do:
headers:
Authorization: "Basic am9lOmNoYW5nZW1l"
search:
index: shared_logs
body: { "query" : { "match_all" : {} } }
- match: { hits.total: 1}
- match: { hits.hits.0._source.user.username: joe}
# John searches:
- do:
headers:
Authorization: "Basic am9objpjaGFuZ2VtZQ=="
search:
index: shared_logs
body: { "query" : { "match_all" : {} } }
- match: { hits.total: 1}
- match: { hits.hits.0._source.user.username: john}
---
"Test shared index seperating user by using DLS role query with user's metadata":
- do:
xpack.security.put_role:
name: "small_companies_role"
body: >
{
"indices": [
{
"names": "shared_logs",
"privileges": ["read", "create"],
"query" : {
"template" : {
"inline" : {
"term" : { "user.metadata.customer_id" : "{{_user.metadata.customer_id}}" }
}
}
}
}
]
}
- do:
headers:
Authorization: "Basic am9lOmNoYW5nZW1l"
index:
index: shared_logs
type: type
pipeline: "my_pipeline"
body: >
{
"log": "Joe's first log entry"
}
- do:
headers:
Authorization: "Basic am9objpjaGFuZ2VtZQ=="
index:
index: shared_logs
type: type
pipeline: "my_pipeline"
body: >
{
"log": "John's first log entry"
}
- do:
indices.refresh: {}
# Joe searches:
- do:
headers:
Authorization: "Basic am9lOmNoYW5nZW1l"
search:
index: shared_logs
body: { "query" : { "match_all" : {} } }
- match: { hits.total: 1}
- match: { hits.hits.0._source.user.username: joe}
# John searches:
- do:
headers:
Authorization: "Basic am9objpjaGFuZ2VtZQ=="
search:
index: shared_logs
body: { "query" : { "match_all" : {} } }
- match: { hits.total: 1}
- match: { hits.hits.0._source.user.username: john}

View File

@ -0,0 +1,5 @@
{
"term" : {
"username" : "{{_user.username}}"
}
}

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,9 +7,10 @@ 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.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
import org.junit.After;
import org.junit.Before;
@ -18,15 +19,15 @@ import java.io.IOException;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
public abstract class WatcherRestTestCase extends ESRestTestCase {
public abstract class WatcherRestTestCase extends ESClientYamlSuiteTestCase {
public WatcherRestTestCase(@Name("yaml") RestTestCandidate testCandidate) {
public WatcherRestTestCase(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException {
return ESRestTestCase.createParameters(0, 1);
public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESClientYamlSuiteTestCase.createParameters(0, 1);
}
@Before

View File

@ -5,12 +5,12 @@
*/
package org.elasticsearch.smoketest;
import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
/** Runs rest tests against external cluster */
public class WatcherWithGroovyIT extends WatcherRestTestCase {
public WatcherWithGroovyIT(RestTestCandidate testCandidate) {
public WatcherWithGroovyIT(ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}

View File

@ -0,0 +1,238 @@
---
"Test simple input to index action":
- do:
xpack.watcher.put_watch:
id: my_watch
body: >
{
"trigger" : { "schedule" : { "cron" : "0/1 * * * * ? 2020" } },
"input" : { "simple" : { "foo": "bar" } },
"actions" : {
"index_action" : {
"index" : {
"index" : "idx",
"doc_type" : "type",
"execution_time_field" : "@timestamp"
}
}
}
}
- match: { _id: "my_watch" }
- do:
xpack.watcher.execute_watch:
id: "my_watch"
body: >
{
"trigger_data" : {
"triggered_time" : "2016-07-07T09:00:00Z",
"scheduled_time" : "2016-07-07T09:00:00Z"
}
}
- match: { "watch_record.state": "executed" }
- do:
indices.refresh: {}
- do:
search:
index: idx
type: type
- match: { hits.total: 1 }
- match: { hits.hits.0._source.foo: bar }
- gte: { hits.hits.0._source.@timestamp: '2016-07-08' }
---
"Test simple input with document field":
- do:
xpack.watcher.put_watch:
id: my_watch
body: >
{
"trigger" : { "schedule" : { "cron" : "0/1 * * * * ? 2020" } },
"input" : { "simple" : { "foo": "bar" } },
"actions" : {
"index_action" : {
"transform" : { "script" : { "inline": "return [ '_doc' : ctx.payload ]" } },
"index" : {
"index" : "idx",
"doc_type" : "type",
"execution_time_field" : "@timestamp"
}
}
}
}
- match: { _id: "my_watch" }
- do:
xpack.watcher.execute_watch:
id: "my_watch"
body: >
{
"trigger_data" : {
"triggered_time" : "2016-07-07T09:00:00Z",
"scheduled_time" : "2016-07-07T09:00:00Z"
}
}
- match: { "watch_record.state": "executed" }
- do:
indices.refresh: {}
- do:
search:
index: idx
type: type
- match: { hits.total: 1 }
- match: { hits.hits.0._source.foo: bar }
- gte: { hits.hits.0._source.@timestamp: '2016-07-08"' }
---
"Test simple input with wrong document results in error":
- do:
xpack.watcher.put_watch:
id: my_watch
body: >
{
"trigger" : { "schedule" : { "cron" : "0/1 * * * * ? 2020" } },
"input" : { "simple" : { "foo": "bar" } },
"actions" : {
"index_action" : {
"transform" : { "script" : { "inline": "return [ '_doc' : 1 ]" } },
"index" : {
"index" : "idx",
"doc_type" : "type",
"execution_time_field" : "@timestamp"
}
}
}
}
- match: { _id: "my_watch" }
- do:
xpack.watcher.execute_watch:
id: "my_watch"
body: >
{
"record_execution" : true,
"trigger_data" : {
"triggered_time" : "2016-07-07T09:00:00Z",
"scheduled_time" : "2016-07-07T09:00:00Z"
}
}
- match: { "watch_record.state": "executed" }
- do:
indices.refresh: {}
- do:
indices.exists:
index: idx
- is_false: ''
- do:
search:
index: .watcher-history-*
type: watch_record
body: >
{
"query" : {
"match" : {
"result.actions.status": "failure"
}
}
}
- match: { hits.total: 1 }
---
"Test search input to index action with aggs":
- do:
bulk:
refresh: true
body:
- '{"index": {"_index": "idx", "_type": "type", "_id": "1"}}'
- '{"@timestamp": "2016-07-07" }'
- '{"index": {"_index": "idx", "_type": "type", "_id": "2"}}'
- '{"@timestamp": "2016-07-08" }'
- '{"index": {"_index": "idx", "_type": "type", "_id": "3"}}'
- '{"@timestamp": "2016-07-09" }'
- do:
xpack.watcher.put_watch:
id: my_watch
body: >
{
"trigger" : { "schedule" : { "cron" : "0/1 * * * * ? 2020" } },
"input" : {
"search" : {
"request": {
"indices" : [ "idx" ],
"types" : [ "type" ],
"body" : {
"aggs" : {
"trend" : {
"date_histogram" : {
"field" : "@timestamp",
"interval" : "day"
}
}
}
}
}
}
},
"actions" : {
"index_action" : {
"transform" : { "script" : { "inline": "return [ '_doc' : ctx.payload.aggregations.trend.buckets]" } },
"index" : {
"index" : "idx",
"doc_type" : "bucket",
"execution_time_field" : "@timestamp"
}
}
}
}
- match: { _id: "my_watch" }
- do:
xpack.watcher.execute_watch:
id: "my_watch"
body: >
{
"trigger_data" : {
"triggered_time" : "2016-07-07T09:00:00Z",
"scheduled_time" : "2016-07-07T09:00:00Z"
}
}
- match: { "watch_record.state": "executed" }
- do:
indices.refresh: {}
- do:
search:
index: idx
type: bucket
- match: { hits.total: 3 }

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

@ -7,9 +7,10 @@ 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.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
import org.junit.After;
import org.junit.Before;
@ -18,15 +19,15 @@ import java.io.IOException;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
public abstract class WatcherRestTestCase extends ESRestTestCase {
public abstract class SmokeTestWatchesWithMustacheClientYamlTestSuiteTestCase extends ESClientYamlSuiteTestCase {
public WatcherRestTestCase(@Name("yaml") RestTestCandidate testCandidate) {
public SmokeTestWatchesWithMustacheClientYamlTestSuiteTestCase(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException {
return ESRestTestCase.createParameters(0, 1);
public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESClientYamlSuiteTestCase.createParameters(0, 1);
}
@Before

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,22 +7,23 @@ 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.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
import java.io.IOException;
/** Runs rest tests against external cluster */
public class WatcherWithMustacheIT extends WatcherRestTestCase {
public class WatcherWithMustacheIT extends SmokeTestWatchesWithMustacheClientYamlTestSuiteTestCase {
public WatcherWithMustacheIT(@Name("yaml") RestTestCandidate testCandidate) {
public WatcherWithMustacheIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException {
return ESRestTestCase.createParameters(0, 1);
public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESClientYamlSuiteTestCase.createParameters(0, 1);
}
}

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,9 +7,10 @@ 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.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
import org.junit.After;
import org.junit.Before;
@ -18,15 +19,15 @@ import java.io.IOException;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
public abstract class WatcherRestTestCase extends ESRestTestCase {
public abstract class WatcherRestTestCase extends ESClientYamlSuiteTestCase {
public WatcherRestTestCase(@Name("yaml") RestTestCandidate testCandidate) {
public WatcherRestTestCase(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException {
return ESRestTestCase.createParameters(0, 1);
public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESClientYamlSuiteTestCase.createParameters(0, 1);
}
@Before

View File

@ -5,12 +5,12 @@
*/
package org.elasticsearch.smoketest;
import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
/** Runs rest tests against external cluster */
public class WatcherWithPainlessIT extends WatcherRestTestCase {
public WatcherWithPainlessIT(RestTestCandidate testCandidate) {
public WatcherWithPainlessIT(ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}

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

@ -7,36 +7,35 @@ package org.elasticsearch.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
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;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
public class WatcherWithSecurityIT extends ESRestTestCase {
public class SmokeTestWatcherWithSecurityClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
private static final String TEST_ADMIN_USERNAME = "test_admin";
private static final String TEST_ADMIN_PASSWORD = "changeme";
public WatcherWithSecurityIT(@Name("yaml") RestTestCandidate testCandidate) {
public SmokeTestWatcherWithSecurityClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException {
return ESRestTestCase.createParameters(0, 1);
public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESClientYamlSuiteTestCase.createParameters(0, 1);
}
@Before

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,43 @@
/*
* 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.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
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 SmokeTestWatcherClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
public SmokeTestWatcherClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESClientYamlSuiteTestCase.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

@ -21,14 +21,20 @@ ext.compactProfile = 'full'
dependencyLicenses.enabled = false
licenseHeaders {
approvedLicenses << 'BCrypt (BSD-like)'
additionalLicense 'BCRYP', 'BCrypt (BSD-like)', 'Copyright (c) 2006 Damien Miller <djm@mindrot.org>'
}
dependencies {
// license deps
compile project(':x-plugins:elasticsearch:license:base')
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'
@ -231,13 +237,6 @@ thirdPartyAudit.excludes = [
'javax.activation.UnsupportedDataTypeException'
]
// someone figure out what the x-plugins logic should be
licenseHeaders.enabled = false
forbiddenApisMain {
signaturesURLs += [file('signatures.txt').toURI().toURL()]
}
modifyPom { MavenPom pom ->
pom.withXml { XmlProvider xml ->
// first find if we have dependencies at all, and grab the node

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,9 @@ 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);
});
}
@Override

View File

@ -10,6 +10,7 @@ import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.xpack.XPackFeatureSet;
import java.io.IOException;
@ -20,12 +21,12 @@ import java.io.IOException;
public class GraphFeatureSet implements XPackFeatureSet {
private final boolean enabled;
private final GraphLicensee licensee;
private final XPackLicenseState licenseState;
@Inject
public GraphFeatureSet(Settings settings, @Nullable GraphLicensee licensee, NamedWriteableRegistry namedWriteableRegistry) {
public GraphFeatureSet(Settings settings, @Nullable XPackLicenseState licenseState, NamedWriteableRegistry namedWriteableRegistry) {
this.enabled = Graph.enabled(settings);
this.licensee = licensee;
this.licenseState = licenseState;
namedWriteableRegistry.register(Usage.class, Usage.writeableName(Graph.NAME), Usage::new);
}
@ -41,7 +42,7 @@ public class GraphFeatureSet implements XPackFeatureSet {
@Override
public boolean available() {
return licensee != null && licensee.isAvailable();
return licenseState != null && licenseState.isGraphAllowed();
}
@Override

View File

@ -1,71 +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.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 static final String ID = Graph.NAME;
@Inject
public GraphLicensee(Settings settings, LicenseeRegistry clientService) {
super(settings, ID, clientService);
}
@Override
public String[] expirationMessages() {
return new String[] {
"Graph explore APIs are disabled"
};
}
@Override
public String[] acknowledgmentMessages(License currentLicense, License newLicense) {
switch (newLicense.operationMode()) {
case BASIC:
case STANDARD:
case GOLD:
if (currentLicense != null) {
switch (currentLicense.operationMode()) {
case TRIAL:
case PLATINUM:
return new String[] { "Graph will be disabled" };
}
}
break;
}
return Strings.EMPTY_ARRAY;
}
/**
* Determine if Graph Exploration should be enabled.
* <p>
* Exploration is only disabled when the license has expired or if the mode is not:
* <ul>
* <li>{@link OperationMode#PLATINUM}</li>
* <li>{@link OperationMode#TRIAL}</li>
* </ul>
*
* @return {@code true} as long as the license is valid. Otherwise {@code false}.
*/
public boolean isAvailable() {
// status is volatile
Status localStatus = status;
OperationMode operationMode = localStatus.getMode();
boolean licensed = operationMode == OperationMode.TRIAL || operationMode == OperationMode.PLATINUM;
return licensed && localStatus.getLicenseState() != LicenseState.DISABLED;
}
}

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

@ -23,7 +23,8 @@ import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.CollectionUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.license.plugin.core.LicenseUtils;
import org.elasticsearch.license.LicenseUtils;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.sampler.DiversifiedAggregationBuilder;
@ -37,7 +38,7 @@ import org.elasticsearch.search.aggregations.bucket.terms.support.IncludeExclude
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.xpack.graph.GraphLicensee;
import org.elasticsearch.xpack.graph.Graph;
import org.elasticsearch.xpack.graph.action.Connection.ConnectionId;
import org.elasticsearch.xpack.graph.action.GraphExploreRequest.TermBoost;
import org.elasticsearch.xpack.graph.action.Vertex.VertexId;
@ -58,7 +59,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class TransportGraphExploreAction extends HandledTransportAction<GraphExploreRequest, GraphExploreResponse> {
private final TransportSearchAction searchAction;
protected final GraphLicensee licensee;
protected final XPackLicenseState licenseState;
static class VertexPriorityQueue extends PriorityQueue<Vertex> {
@ -76,19 +77,19 @@ public class TransportGraphExploreAction extends HandledTransportAction<GraphExp
@Inject
public TransportGraphExploreAction(Settings settings, ThreadPool threadPool, TransportSearchAction transportSearchAction,
TransportService transportService, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
GraphLicensee licensee) {
XPackLicenseState licenseState) {
super(settings, GraphExploreAction.NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver,
GraphExploreRequest::new);
this.searchAction = transportSearchAction;
this.licensee = licensee;
this.licenseState = licenseState;
}
@Override
protected void doExecute(GraphExploreRequest request, ActionListener<GraphExploreResponse> listener) {
if (licensee.isAvailable()) {
if (licenseState.isGraphAllowed()) {
new AsyncGraphAction(request, listener).start();
} else {
listener.onFailure(LicenseUtils.newComplianceException(GraphLicensee.ID));
listener.onFailure(LicenseUtils.newComplianceException(Graph.NAME));
}
}

View File

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

View File

@ -1,135 +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.license;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.core.License.OperationMode;
import org.elasticsearch.license.plugin.core.AbstractLicenseeTestCase;
import org.elasticsearch.xpack.graph.GraphLicensee;
import static org.hamcrest.Matchers.is;
public class LicenseTests extends AbstractLicenseeTestCase {
private SimpleLicenseeRegistry licenseeRegistry = new SimpleLicenseeRegistry();
public void testPlatinumTrialLicenseCanDoEverything() throws Exception {
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
assertLicensePlatinumTrialBehaviour(graphLicensee);
}
public void testBasicLicenseIsDisabled() throws Exception {
licenseeRegistry.setOperationMode(OperationMode.BASIC);
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
}
public void testStandardLicenseIsDisabled() throws Exception {
licenseeRegistry.setOperationMode(OperationMode.STANDARD);
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
}
public void testNoLicenseDoesNotWork() {
licenseeRegistry.setOperationMode(OperationMode.BASIC);
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
licenseeRegistry.disable();
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
}
public void testExpiredPlatinumTrialLicenseIsRestricted() throws Exception {
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
licenseeRegistry.disable();
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
}
public void testUpgradingFromBasicLicenseWorks() {
licenseeRegistry.setOperationMode(OperationMode.BASIC);
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
assertLicensePlatinumTrialBehaviour(graphLicensee);
}
public void testDowngradingToBasicLicenseWorks() {
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
assertLicensePlatinumTrialBehaviour(graphLicensee);
licenseeRegistry.setOperationMode(OperationMode.BASIC);
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
}
public void testUpgradingFromStandardLicenseWorks() {
licenseeRegistry.setOperationMode(OperationMode.STANDARD);
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
assertLicensePlatinumTrialBehaviour(graphLicensee);
}
public void testDowngradingToStandardLicenseWorks() {
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
assertLicensePlatinumTrialBehaviour(graphLicensee);
licenseeRegistry.setOperationMode(OperationMode.STANDARD);
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
}
public void testDowngradingToGoldLicenseWorks() {
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
assertLicensePlatinumTrialBehaviour(graphLicensee);
licenseeRegistry.setOperationMode(OperationMode.GOLD);
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
}
public void testUpgradingExpiredLicenseWorks() {
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(graphLicensee);
licenseeRegistry.disable();
assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(graphLicensee);
licenseeRegistry.setOperationMode(randomTrialOrPlatinumMode());
assertLicensePlatinumTrialBehaviour(graphLicensee);
}
private void assertLicensePlatinumTrialBehaviour(GraphLicensee graphLicensee) {
assertThat("Expected graph exploration to be allowed", graphLicensee.isAvailable(), is(true));
}
private void assertLicenseBasicOrStandardGoldOrNoneOrExpiredBehaviour(GraphLicensee graphLicensee) {
assertThat("Expected graph exploration not to be allowed", graphLicensee.isAvailable(), is(false));
}
}

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.action.delete;
package org.elasticsearch.license;
import org.elasticsearch.action.Action;
import org.elasticsearch.client.ElasticsearchClient;

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.action.delete;
package org.elasticsearch.license;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.support.master.AcknowledgedRequest;

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.action.delete;
package org.elasticsearch.license;
import org.elasticsearch.action.support.master.AcknowledgedRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.action.delete;
package org.elasticsearch.license;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.common.io.stream.StreamInput;

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.core;
package org.elasticsearch.license;
import org.elasticsearch.common.logging.LoggerMessageFormat;
import org.elasticsearch.common.unit.TimeValue;
@ -12,7 +12,7 @@ import org.elasticsearch.xpack.scheduler.SchedulerEngine;
import java.util.UUID;
public abstract class ExpirationCallback {
abstract class ExpirationCallback {
static final String EXPIRATION_JOB_PREFIX = ".license_expiration_job_";

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.action.get;
package org.elasticsearch.license;
import org.elasticsearch.action.Action;
import org.elasticsearch.client.ElasticsearchClient;

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.action.get;
package org.elasticsearch.license;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.support.master.MasterNodeReadRequest;

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.action.get;
package org.elasticsearch.license;
import org.elasticsearch.action.support.master.MasterNodeReadOperationRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.action.get;
package org.elasticsearch.license;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.common.io.stream.StreamInput;

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.core;
package org.elasticsearch.license;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener;
@ -18,18 +18,18 @@ import org.elasticsearch.cluster.metadata.MetaData;
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.plugin.action.delete.DeleteLicenseRequest;
import org.elasticsearch.license.plugin.action.put.PutLicenseRequest;
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
import org.elasticsearch.license.core.OperationModeFileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.scheduler.SchedulerEngine;
import org.elasticsearch.xpack.support.clock.Clock;
@ -40,41 +40,29 @@ 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;
/**
* 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)
* Service responsible for managing {@link LicensesMetaData}.
* <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)}
* On the master node, the service handles updating the cluster state when a new license is registered.
* It also listens on all nodes for cluster state updates, and updates {@link XPackLicenseState} when
* the license changes are detected in the cluster state.
*/
public class LicensesService extends AbstractLifecycleComponent implements ClusterStateListener, LicensesManagerService,
LicenseeRegistry, SchedulerEngine.Listener {
public class LicenseService extends AbstractLifecycleComponent implements ClusterStateListener, SchedulerEngine.Listener {
// pkg private for tests
static final TimeValue TRIAL_LICENSE_DURATION = TimeValue.timeValueHours(30 * 24);
/**
* Duration of grace period after a license has expired
*/
static final TimeValue GRACE_PERIOD_DURATION = days(7);
private final ClusterService clusterService;
/**
* Currently active consumers to notify to
*/
private final List<InternalLicensee> registeredLicensees = new CopyOnWriteArrayList<>();
/** The xpack feature state to update when license changes are made. */
private final XPackLicenseState licenseState;
/**
* Currently active license
@ -83,6 +71,11 @@ 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
*/
@ -93,125 +86,78 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
*/
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, Clock clock) {
public LicenseService(Settings settings, ClusterService clusterService, Clock clock, Environment env,
ResourceWatcherService resourceWatcherService, XPackLicenseState licenseState) {
super(settings);
this.clusterService = clusterService;
populateExpirationCallbacks();
this.clock = clock;
this.scheduler = new SchedulerEngine(clock);
this.licenseState = licenseState;
this.operationModeFileWatcher = new OperationModeFileWatcher(resourceWatcherService,
XPackPlugin.resolveConfigFile(env, "license_mode"), logger, () -> updateLicenseState(getLicense()));
this.scheduler.register(this);
populateExpirationCallbacks();
}
private void logExpirationWarning(long expirationMillis, boolean expired) {
String expiredMsg = expired ? "will expire" : "expired";
String general = LoggerMessageFormat.format(null, "\n" +
"#\n" +
"# License [{}] on [{}]. If you have a new license, please update it.\n" +
"# Otherwise, please reach out to your support contact.\n" +
"# ", expiredMsg, DATE_FORMATTER.printer().print(expirationMillis));
if (expired) {
general = general.toUpperCase(Locale.ROOT);
}
StringBuilder builder = new StringBuilder(general);
builder.append(System.lineSeparator());
if (expired) {
builder.append("# COMMERCIAL PLUGINS OPERATING WITH REDUCED FUNCTIONALITY");
} else {
builder.append("# Commercial plugins operate with reduced functionality on license expiration:");
}
XPackLicenseState.EXPIRATION_MESSAGES.forEach((feature, messages) -> {
if (messages.length > 0) {
builder.append(System.lineSeparator());
builder.append("# - ");
builder.append(feature);
for (String message : messages) {
builder.append(System.lineSeparator());
builder.append("# - ");
builder.append(message);
}
}
});
logger.warn("{}", builder);
}
private void populateExpirationCallbacks() {
expirationCallbacks.add(new ExpirationCallback.Pre(days(7), days(25), days(1)) {
@Override
public void on(License license) {
String general = LoggerMessageFormat.format(null, "\n" +
"#\n" +
"# License will expire on [{}]. If you have a new license, please update it.\n" +
"# Otherwise, please reach out to your support contact.\n" +
"# ", DATE_FORMATTER.printer().print(license.expiryDate()));
if (!registeredLicensees.isEmpty()) {
StringBuilder builder = new StringBuilder(general);
builder.append(System.lineSeparator());
builder.append("# Commercial plugins operate with reduced functionality on license " +
"expiration:");
for (InternalLicensee licensee : registeredLicensees) {
if (licensee.expirationMessages().length > 0) {
builder.append(System.lineSeparator());
builder.append("# - ");
builder.append(licensee.id());
for (String message : licensee.expirationMessages()) {
builder.append(System.lineSeparator());
builder.append("# - ");
builder.append(message);
}
}
}
logger.warn("{}", builder);
} else {
logger.warn("{}", general);
}
}
}
);
@Override
public void on(License license) {
logExpirationWarning(license.expiryDate(), false);
}
});
expirationCallbacks.add(new ExpirationCallback.Pre(days(0), days(7), TimeValue.timeValueMinutes(10)) {
@Override
public void on(License license) {
String general = LoggerMessageFormat.format(null, "\n" +
"#\n" +
"# License will expire on [{}]. If you have a new license, please update it.\n" +
"# Otherwise, please reach out to your support contact.\n" +
"# ", DATE_FORMATTER.printer().print(license.expiryDate()));
if (!registeredLicensees.isEmpty()) {
StringBuilder builder = new StringBuilder(general);
builder.append(System.lineSeparator());
builder.append("# Commercial plugins operate with reduced functionality on license " +
"expiration:");
for (InternalLicensee licensee : registeredLicensees) {
if (licensee.expirationMessages().length > 0) {
builder.append(System.lineSeparator());
builder.append("# - ");
builder.append(licensee.id());
for (String message : licensee.expirationMessages()) {
builder.append(System.lineSeparator());
builder.append("# - ");
builder.append(message);
}
}
}
logger.warn("{}", builder.toString());
} else {
logger.warn("{}", general);
}
}
}
);
@Override
public void on(License license) {
logExpirationWarning(license.expiryDate(), false);
}
});
expirationCallbacks.add(new ExpirationCallback.Post(days(0), null, TimeValue.timeValueMinutes(10)) {
@Override
public void on(License license) {
// logged when grace period begins
String general = LoggerMessageFormat.format(null, "\n" +
"#\n" +
"# LICENSE EXPIRED ON [{}]. IF YOU HAVE A NEW LICENSE, PLEASE\n" +
"# UPDATE IT. OTHERWISE, PLEASE REACH OUT TO YOUR SUPPORT CONTACT.\n" +
"# ", DATE_FORMATTER.printer().print(license.expiryDate()));
if (!registeredLicensees.isEmpty()) {
StringBuilder builder = new StringBuilder(general);
builder.append(System.lineSeparator());
builder.append("# COMMERCIAL PLUGINS OPERATING WITH REDUCED FUNCTIONALITY");
for (InternalLicensee licensee : registeredLicensees) {
if (licensee.expirationMessages().length > 0) {
builder.append(System.lineSeparator());
builder.append("# - ");
builder.append(licensee.id());
for (String message : licensee.expirationMessages()) {
builder.append(System.lineSeparator());
builder.append("# - ");
builder.append(message);
}
}
}
logger.warn("{}", builder.toString());
} else {
logger.warn("{}", general);
}
}
}
);
@Override
public void on(License license) {
// logged when grace period begins
logExpirationWarning(license.expiryDate(), true);
}
});
}
/**
@ -227,22 +173,23 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
listener.onResponse(new PutLicenseResponse(true, LicensesStatus.EXPIRED));
} else {
if (!request.acknowledged()) {
// TODO: ack messages should be generated on the master, since another node's cluster state may be behind...
final License currentLicense = getLicense();
if (currentLicense != null) {
Map<String, String[]> acknowledgeMessages = new HashMap<>(registeredLicensees.size() + 1);
Map<String, String[]> acknowledgeMessages = new HashMap<>();
if (!License.isAutoGeneratedLicense(currentLicense.signature()) // current license is not auto-generated
&& currentLicense.issueDate() > newLicense.issueDate()) { // and has a later issue date
acknowledgeMessages.put("license",
new String[]{"The new license is older than the currently installed license. Are you sure you want to " +
"override the current license?"});
acknowledgeMessages.put("license", new String[]{
"The new license is older than the currently installed license. " +
"Are you sure you want to override the current license?"});
}
for (InternalLicensee licensee : registeredLicensees) {
String[] listenerAcknowledgeMessages = licensee.acknowledgmentMessages(currentLicense, newLicense);
if (listenerAcknowledgeMessages.length > 0) {
acknowledgeMessages.put(licensee.id(), listenerAcknowledgeMessages);
XPackLicenseState.ACKNOWLEDGMENT_MESSAGES.forEach((feature, ackMessages) -> {
String[] messages = ackMessages.apply(currentLicense.operationMode(), newLicense.operationMode());
if (messages.length > 0) {
acknowledgeMessages.put(feature, messages);
}
}
if (!acknowledgeMessages.isEmpty()) {
});
if (acknowledgeMessages.isEmpty() == false) {
// needs acknowledgement
listener.onResponse(new PutLicenseResponse(false, LicensesStatus.VALID, ACKNOWLEDGEMENT_HEADER,
acknowledgeMessages));
@ -278,7 +225,7 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
if (licensesMetaData != null) {
final License license = licensesMetaData.getLicense();
if (event.getJobName().equals(LICENSE_JOB)) {
notifyLicensees(license);
updateLicenseState(license);
} else if (event.getJobName().startsWith(ExpirationCallback.EXPIRATION_JOB_PREFIX)) {
expirationCallbacks.stream()
.filter(expirationCallback -> expirationCallback.getId().equals(event.getJobName()))
@ -313,17 +260,6 @@ 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());
}
}
@Override
public License getLicense() {
final License license = getLicense(clusterService.state().metaData().custom(LicensesMetaData.TYPE));
return license == LicensesMetaData.LICENSE_TOMBSTONE ? null : license;
@ -377,15 +313,25 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
protected void doStart() throws ElasticsearchException {
clusterService.add(this);
scheduler.start(Collections.emptyList());
logger.debug("initializing license state");
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 (clusterState.getNodes().isLocalNodeElectedMaster() &&
(currentMetaData == null || currentMetaData.getLicense() == null)) {
// triggers a cluster changed event
// eventually notifying the current licensee
registerTrialLicense();
}
}
}
@Override
protected void doStop() throws ElasticsearchException {
clusterService.remove(this);
scheduler.stop();
// clear all handlers
registeredLicensees.clear();
// clear current license
currentLicense.set(null);
}
@ -430,54 +376,30 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
}
}
private void notifyLicensees(final License license) {
protected void updateLicenseState(final License license) {
if (license == LicensesMetaData.LICENSE_TOMBSTONE) {
// implies license has been explicitly deleted
// update licensee states
registeredLicensees.forEach(InternalLicensee::onRemove);
licenseState.update(License.OperationMode.MISSING, false);
return;
}
if (license != null) {
logger.debug("notifying [{}] listeners", registeredLicensees.size());
switch (getLicenseState(license, clock.millis())) {
case ENABLED:
for (InternalLicensee licensee : registeredLicensees) {
licensee.onChange(license, LicenseState.ENABLED);
}
long time = clock.millis();
boolean active = time >= license.issueDate() &&
time < license.expiryDate() + GRACE_PERIOD_DURATION.getMillis();
licenseState.update(license.operationMode(), active);
if (active) {
if (time < license.expiryDate()) {
logger.debug("license [{}] - valid", license.uid());
break;
case GRACE_PERIOD:
for (InternalLicensee licensee : registeredLicensees) {
licensee.onChange(license, LicenseState.GRACE_PERIOD);
}
} else {
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;
}
} else {
logger.warn("license [{}] - expired", license.uid());
}
}
}
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>.
@ -489,42 +411,42 @@ 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);
scheduler.add(new SchedulerEngine.Job(LICENSE_JOB, new LicenseSchedule(license)));
license.setOperationModeFileWatcher(operationModeFileWatcher);
scheduler.add(new SchedulerEngine.Job(LICENSE_JOB, nextLicenseCheck(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();
}
}
updateLicenseState(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");
// pkg private for tests
static SchedulerEngine.Schedule nextLicenseCheck(License license) {
return (startTime, time) -> {
if (time < license.issueDate()) {
// when we encounter a license with a future issue date
// which can happen with autogenerated license,
// we want to schedule a notification on the license issue date
// so the license is notificed once it is valid
// see https://github.com/elastic/x-plugins/issues/983
return license.issueDate();
} else if (time < license.expiryDate()) {
return license.expiryDate();
} else if (time < license.expiryDate() + GRACE_PERIOD_DURATION.getMillis()) {
return license.expiryDate() + GRACE_PERIOD_DURATION.getMillis();
}
}
logger.debug("registering licensee [{}]", licensee.id());
registeredLicensees.add(new InternalLicensee(licensee));
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 (clusterState.getNodes().isLocalNodeElectedMaster() &&
(currentMetaData == null || currentMetaData.getLicense() == null)) {
// triggers a cluster changed event
// eventually notifying the current licensee
registerTrialLicense();
} else if (lifecycleState() == Lifecycle.State.STARTED) {
notifyLicensees(currentMetaData.getLicense());
}
}
return -1; // license is expired, no need to check again
};
}
License getLicense(final LicensesMetaData metaData) {
@ -532,7 +454,7 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
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))) {
@ -542,58 +464,4 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
}
return null;
}
/**
* 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 Licensee licensee;
private InternalLicensee(Licensee licensee) {
this.licensee = licensee;
}
@Override
public String toString() {
return "(listener: " + licensee.id() + ", state: " + currentLicenseState.name() + ")";
}
public String id() {
return licensee.id();
}
public String[] expirationMessages() {
return licensee.expirationMessages();
}
public String[] acknowledgmentMessages(License currentLicense, License newLicense) {
return licensee.acknowledgmentMessages(currentLicense, newLicense);
}
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 void onRemove() {
synchronized (this) {
if (currentLicense != null || currentLicenseState != LicenseState.DISABLED) {
currentLicense = null;
currentLicenseState = LicenseState.DISABLED;
licensee.onChange(Licensee.Status.MISSING);
}
}
}
}
}

View File

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

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.core;
package org.elasticsearch.license;
import org.apache.lucene.util.CollectionUtil;
import org.elasticsearch.Version;
@ -32,7 +32,7 @@ import static org.elasticsearch.license.core.CryptUtils.encrypt;
/**
* Contains metadata about registered licenses
*/
public class LicensesMetaData extends AbstractDiffable<MetaData.Custom> implements MetaData.Custom {
class LicensesMetaData extends AbstractDiffable<MetaData.Custom> implements MetaData.Custom {
public static final String TYPE = "licenses";

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.core;
package org.elasticsearch.license;
public enum LicensesStatus {
VALID((byte) 0),

View File

@ -3,37 +3,26 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin;
import org.elasticsearch.action.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.common.inject.Module;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseAction;
import org.elasticsearch.license.plugin.action.delete.TransportDeleteLicenseAction;
import org.elasticsearch.license.plugin.action.get.GetLicenseAction;
import org.elasticsearch.license.plugin.action.get.TransportGetLicenseAction;
import org.elasticsearch.license.plugin.action.put.PutLicenseAction;
import org.elasticsearch.license.plugin.action.put.TransportPutLicenseAction;
import org.elasticsearch.license.plugin.core.LicenseeRegistry;
import org.elasticsearch.license.plugin.core.LicensesManagerService;
import org.elasticsearch.license.plugin.core.LicensesMetaData;
import org.elasticsearch.license.plugin.core.LicensesService;
import org.elasticsearch.license.plugin.rest.RestDeleteLicenseAction;
import org.elasticsearch.license.plugin.rest.RestGetLicenseAction;
import org.elasticsearch.license.plugin.rest.RestPutLicenseAction;
import org.elasticsearch.plugins.ActionPlugin;
import org.elasticsearch.rest.RestHandler;
package org.elasticsearch.license;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.cluster.metadata.MetaData;
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.plugins.ActionPlugin;
import org.elasticsearch.rest.RestHandler;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.support.clock.Clock;
import static java.util.Collections.emptyList;
import static org.elasticsearch.xpack.XPackPlugin.isTribeNode;
import static org.elasticsearch.xpack.XPackPlugin.transportClientMode;
@ -42,7 +31,8 @@ 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 {
@ -50,10 +40,15 @@ public class Licensing implements ActionPlugin {
}
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) {
@ -74,22 +69,12 @@ 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<Module> nodeModules() {
if (isTransportClient == false && isTribeNode == false) {
return Collections.singletonList(b -> {
b.bind(LicensesService.class).asEagerSingleton();
b.bind(LicenseeRegistry.class).to(LicensesService.class);
b.bind(LicensesManagerService.class).to(LicensesService.class);
});
}
return Collections.emptyList();
public Collection<Object> createComponents(ClusterService clusterService, Clock clock, Environment environment,
ResourceWatcherService resourceWatcherService,
XPackLicenseState licenseState) {
LicenseService licenseService = new LicenseService(settings, clusterService, clock,
environment, resourceWatcherService, licenseState);
return Arrays.asList(licenseService, licenseState);
}
public List<Setting<?>> getSettings() {

View File

@ -3,23 +3,11 @@
* 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;
package org.elasticsearch.license;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseAction;
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseRequest;
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseRequestBuilder;
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseResponse;
import org.elasticsearch.license.plugin.action.get.GetLicenseAction;
import org.elasticsearch.license.plugin.action.get.GetLicenseRequest;
import org.elasticsearch.license.plugin.action.get.GetLicenseRequestBuilder;
import org.elasticsearch.license.plugin.action.get.GetLicenseResponse;
import org.elasticsearch.license.plugin.action.put.PutLicenseAction;
import org.elasticsearch.license.plugin.action.put.PutLicenseRequest;
import org.elasticsearch.license.plugin.action.put.PutLicenseRequestBuilder;
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
/**
*

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.action.put;
package org.elasticsearch.license;
import org.elasticsearch.action.Action;
import org.elasticsearch.client.ElasticsearchClient;

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.action.put;
package org.elasticsearch.license;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.ValidateActions;

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.action.put;
package org.elasticsearch.license;
import org.elasticsearch.action.support.master.AcknowledgedRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.action.put;
package org.elasticsearch.license;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.common.io.stream.StreamInput;
@ -11,7 +11,7 @@ import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.license.plugin.core.LicensesStatus;
import org.elasticsearch.license.LicensesStatus;
import java.io.IOException;
import java.util.Collections;

View File

@ -0,0 +1,41 @@
/*
* 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;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
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 XPackRestHandler {
@Inject
public RestDeleteLicenseAction(Settings settings, RestController controller) {
super(settings);
// @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 XPackClient client) {
client.es().admin().cluster().execute(DeleteLicenseAction.INSTANCE,
new DeleteLicenseRequest(),
new AcknowledgedRestListener<>(channel));
}
}

View File

@ -3,24 +3,21 @@
* 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.rest;
package org.elasticsearch.license;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
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 +26,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 +49,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

@ -3,17 +3,12 @@
* 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.rest;
package org.elasticsearch.license;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent;
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 +16,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

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.action.delete;
package org.elasticsearch.license;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener;
@ -17,21 +17,20 @@ import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.plugin.core.LicensesService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
public class TransportDeleteLicenseAction extends TransportMasterNodeAction<DeleteLicenseRequest, DeleteLicenseResponse> {
private final LicensesService licensesService;
private final LicenseService licenseService;
@Inject
public TransportDeleteLicenseAction(Settings settings, TransportService transportService, ClusterService clusterService,
LicensesService licensesService, ThreadPool threadPool, ActionFilters actionFilters,
LicenseService licenseService, ThreadPool threadPool, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver) {
super(settings, DeleteLicenseAction.NAME, transportService, clusterService, threadPool, actionFilters,
indexNameExpressionResolver, DeleteLicenseRequest::new);
this.licensesService = licensesService;
this.licenseService = licenseService;
}
@Override
@ -52,7 +51,7 @@ public class TransportDeleteLicenseAction extends TransportMasterNodeAction<Dele
@Override
protected void masterOperation(final DeleteLicenseRequest request, ClusterState state, final ActionListener<DeleteLicenseResponse>
listener) throws ElasticsearchException {
licensesService.removeLicense(request, new ActionListener<ClusterStateUpdateResponse>() {
licenseService.removeLicense(request, new ActionListener<ClusterStateUpdateResponse>() {
@Override
public void onResponse(ClusterStateUpdateResponse clusterStateUpdateResponse) {
listener.onResponse(new DeleteLicenseResponse(clusterStateUpdateResponse.isAcknowledged()));

View File

@ -3,34 +3,33 @@
* 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.action.get;
package org.elasticsearch.license;
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.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
public class TransportGetLicenseAction extends TransportMasterNodeReadAction<GetLicenseRequest, GetLicenseResponse> {
private final LicensesManagerService licensesManagerService;
private final LicenseService licenseService;
@Inject
public TransportGetLicenseAction(Settings settings, TransportService transportService, ClusterService clusterService,
LicensesManagerService licensesManagerService, ThreadPool threadPool, ActionFilters actionFilters,
LicenseService licenseService, ThreadPool threadPool, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver) {
super(settings, GetLicenseAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver,
GetLicenseRequest::new);
this.licensesManagerService = licensesManagerService;
this.licenseService = licenseService;
}
@Override
@ -51,6 +50,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(licenseService.getLicense()));
}
}

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.action.put;
package org.elasticsearch.license;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener;
@ -16,21 +16,20 @@ import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.plugin.core.LicensesService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
public class TransportPutLicenseAction extends TransportMasterNodeAction<PutLicenseRequest, PutLicenseResponse> {
private final LicensesService licensesService;
private final LicenseService licenseService;
@Inject
public TransportPutLicenseAction(Settings settings, TransportService transportService, ClusterService clusterService,
LicensesService licensesService, ThreadPool threadPool, ActionFilters actionFilters,
LicenseService licenseService, ThreadPool threadPool, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver) {
super(settings, PutLicenseAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver,
PutLicenseRequest::new);
this.licensesService = licensesService;
this.licenseService = licenseService;
}
@Override
@ -51,7 +50,7 @@ public class TransportPutLicenseAction extends TransportMasterNodeAction<PutLice
@Override
protected void masterOperation(final PutLicenseRequest request, ClusterState state, final ActionListener<PutLicenseResponse>
listener) throws ElasticsearchException {
licensesService.registerLicense(request, listener);
licenseService.registerLicense(request, listener);
}
}

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license.plugin.core;
package org.elasticsearch.license;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.ToXContent;
@ -21,7 +21,7 @@ import java.util.Collections;
import static org.elasticsearch.license.core.CryptUtils.decrypt;
import static org.elasticsearch.license.core.CryptUtils.encrypt;
public class TrialLicense {
class TrialLicense {
public static License create(License.Builder specBuilder) {
License spec = specBuilder

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