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') File checkstyleSuppressions = file('checkstyle_suppressions.xml')
subprojects { subprojects {
tasks.withType(Checkstyle) { tasks.withType(Checkstyle) {
@ -7,4 +9,9 @@ subprojects {
suppressions: checkstyleSuppressions 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": case "gold":
return GOLD; return GOLD;
case "platinum": case "platinum":
case "cloud_internal":
case "internal": // bwc for 1.x subscription_type field case "internal": // bwc for 1.x subscription_type field
return PLATINUM; return PLATINUM;
default: 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() { public OperationMode operationMode() {
synchronized (this) {
if (canReadOperationModeFromFile() && operationModeFileWatcher != null) {
return operationModeFileWatcher.getCurrentOperationMode();
}
}
return operationMode; 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 * @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 { project.forbiddenPatterns {
exclude '**/*.key' 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 { integTest {
cluster { 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.enabled', 'true'
setting 'xpack.security.audit.outputs', 'index' setting 'xpack.security.audit.outputs', 'index'
setting 'logger.level', 'DEBUG' 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") @AwaitsFix(bugUrl = "https://github.com/elastic/x-plugins/issues/2354")
public void testShieldIndexAuditTrailWorking() throws Exception { public void testShieldIndexAuditTrailWorking() throws Exception {
try (Response response = getRestClient().performRequest("GET", "/", Response response = getRestClient().performRequest("GET", "/",
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray()))))) { UsernamePasswordToken.basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray()))));
assertThat(response.getStatusLine().getStatusCode(), is(200)); assertThat(response.getStatusLine().getStatusCode(), is(200));
}
final AtomicReference<ClusterState> lastClusterState = new AtomicReference<>(); final AtomicReference<ClusterState> lastClusterState = new AtomicReference<>();
final AtomicBoolean indexExists = new AtomicBoolean(false); final AtomicBoolean indexExists = new AtomicBoolean(false);
boolean found = awaitBusy(() -> { 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(',') 'search/80_date_math_index_names/Missing index with catch'].join(',')
cluster { cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack') plugin ':x-plugins:elasticsearch:x-pack'
setting 'xpack.watcher.enabled', 'false' setting 'xpack.watcher.enabled', 'false'
setting 'xpack.monitoring.enabled', 'false' setting 'xpack.monitoring.enabled', 'false'
setupCommand 'setupDummyUser', setupCommand 'setupDummyUser',

View File

@ -7,29 +7,30 @@ package org.elasticsearch.xpack.security;
import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; 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.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 java.io.IOException;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; 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 USER = "test_user";
private static final String PASS = "changeme"; private static final String PASS = "changeme";
public RestIT(@Name("yaml") RestTestCandidate testCandidate) { public CoreWithSecurityClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate); super(testCandidate);
} }
@ParametersFactory @ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException { public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESRestTestCase.createParameters(0, 1); return ESClientYamlSuiteTestCase.createParameters(0, 1);
} }
@Override @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.ManualExecutionContext;
import org.elasticsearch.xpack.watcher.execution.ManualExecutionTests.ExecutionRunner; import org.elasticsearch.xpack.watcher.execution.ManualExecutionTests.ExecutionRunner;
import org.elasticsearch.xpack.watcher.history.WatchRecord; 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.test.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.transport.actions.delete.DeleteWatchResponse; import org.elasticsearch.xpack.watcher.transport.actions.delete.DeleteWatchResponse;
import org.elasticsearch.xpack.watcher.transport.actions.get.GetWatchRequest; import org.elasticsearch.xpack.watcher.transport.actions.get.GetWatchRequest;
@ -65,7 +65,7 @@ public class GroovyManualExecutionIT extends AbstractWatcherIntegrationTestCase
WatchSourceBuilder watchBuilder = watchBuilder() WatchSourceBuilder watchBuilder = watchBuilder()
.trigger(schedule(cron("0 0 0 1 * ? 2099"))) .trigger(schedule(cron("0 0 0 1 * ? 2099")))
.input(simpleInput("foo", "bar")) .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")); .addAction("log", loggingAction("foobar"));
Watch watch = watchParser().parse("_id", false, watchBuilder.buildAsBytes(XContentType.JSON)); Watch watch = watchParser().parse("_id", false, watchBuilder.buildAsBytes(XContentType.JSON));
@ -80,7 +80,7 @@ public class GroovyManualExecutionIT extends AbstractWatcherIntegrationTestCase
WatchSourceBuilder watchBuilder = watchBuilder() WatchSourceBuilder watchBuilder = watchBuilder()
.trigger(schedule(cron("0 0 0 1 * ? 2099"))) .trigger(schedule(cron("0 0 0 1 * ? 2099")))
.input(simpleInput("foo", "bar")) .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)) .defaultThrottlePeriod(new TimeValue(1, TimeUnit.HOURS))
.addAction("log", loggingAction("foobar")); .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.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.groovy.GroovyPlugin; import org.elasticsearch.script.groovy.GroovyPlugin;
import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram; 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.ExecutableScriptCondition;
import org.elasticsearch.xpack.watcher.condition.script.ScriptCondition; import org.elasticsearch.xpack.watcher.condition.script.ScriptCondition;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext; 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.common.ScriptServiceProxy;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase; import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.watch.Payload; import org.elasticsearch.xpack.watcher.watch.Payload;
import org.junit.AfterClass; import org.junit.AfterClass;
@ -28,7 +28,7 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.TimeUnit; 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; import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.mockExecutionContext;
public class GroovyScriptConditionIT extends AbstractWatcherIntegrationTestCase { public class GroovyScriptConditionIT extends AbstractWatcherIntegrationTestCase {
@ -46,7 +46,7 @@ public class GroovyScriptConditionIT extends AbstractWatcherIntegrationTestCase
} }
private static ThreadPool THREAD_POOL; private static ThreadPool THREAD_POOL;
private ScriptServiceProxy scriptService; private ScriptService scriptService;
@BeforeClass @BeforeClass
public static void startThreadPool() { public static void startThreadPool() {
@ -55,7 +55,7 @@ public class GroovyScriptConditionIT extends AbstractWatcherIntegrationTestCase
@Before @Before
public void init() throws Exception { public void init() throws Exception {
scriptService = getScriptServiceProxy(THREAD_POOL); scriptService = createScriptService(THREAD_POOL);
} }
@AfterClass @AfterClass
@ -83,7 +83,7 @@ public class GroovyScriptConditionIT extends AbstractWatcherIntegrationTestCase
SearchResponse unmetResponse = builder.get(); SearchResponse unmetResponse = builder.get();
ExecutableScriptCondition condition = ExecutableScriptCondition condition =
new ExecutableScriptCondition(new ScriptCondition(Script.inline( new ExecutableScriptCondition(new ScriptCondition(WatcherScript.inline(
String.join( String.join(
" ", " ",
"if (ctx.payload.hits.total < 1) return false;", "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; package org.elasticsearch.messy.tests;
import org.apache.lucene.util.LuceneTestCase; 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.SuppressForbidden;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
@ -19,9 +16,8 @@ import org.elasticsearch.script.ScriptSettings;
import org.elasticsearch.script.groovy.GroovyScriptEngineService; import org.elasticsearch.script.groovy.GroovyScriptEngineService;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.common.ScriptServiceProxy; import org.elasticsearch.xpack.watcher.support.WatcherScript;
import org.junit.Ignore; import org.junit.Ignore;
import org.mockito.Mockito;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -29,7 +25,7 @@ import java.util.Collections;
@Ignore // not a test. @Ignore // not a test.
@SuppressForbidden(reason = "gradle is broken and tries to run me as a test") @SuppressForbidden(reason = "gradle is broken and tries to run me as a test")
public final class MessyTestUtils { public final class MessyTestUtils {
public static ScriptServiceProxy getScriptServiceProxy(ThreadPool tp) throws Exception { public static ScriptService createScriptService(ThreadPool tp) throws Exception {
Settings settings = Settings.builder() Settings settings = Settings.builder()
.put("script.inline", "true") .put("script.inline", "true")
.put("script.indexed", "true") .put("script.indexed", "true")
@ -37,10 +33,10 @@ public final class MessyTestUtils {
.build(); .build();
GroovyScriptEngineService groovyScriptEngineService = new GroovyScriptEngineService(settings); GroovyScriptEngineService groovyScriptEngineService = new GroovyScriptEngineService(settings);
ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.singleton(groovyScriptEngineService)); 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); ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
return ScriptServiceProxy.of(new ScriptService(settings, new Environment(settings), return new ScriptService(settings, new Environment(settings), new ResourceWatcherService(settings, tp),
new ResourceWatcherService(settings, tp), scriptEngineRegistry, scriptContextRegistry, scriptSettings)); scriptEngineRegistry, scriptContextRegistry, scriptSettings);
} }
} }

View File

@ -10,6 +10,7 @@ import org.elasticsearch.action.search.ShardSearchFailure;
import org.elasticsearch.common.text.Text; import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.Index; import org.elasticsearch.index.Index;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.groovy.GroovyPlugin; import org.elasticsearch.script.groovy.GroovyPlugin;
import org.elasticsearch.search.SearchShardTarget; import org.elasticsearch.search.SearchShardTarget;
import org.elasticsearch.search.aggregations.AggregationBuilders; 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.search.internal.InternalSearchResponse;
import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool; 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.ExecutableScriptCondition;
import org.elasticsearch.xpack.watcher.condition.script.ScriptCondition; import org.elasticsearch.xpack.watcher.condition.script.ScriptCondition;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext; 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.test.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.watch.Payload; import org.elasticsearch.xpack.watcher.watch.Payload;
import org.junit.After; import org.junit.After;
@ -40,7 +40,7 @@ import static org.mockito.Mockito.when;
*/ */
public class ScriptConditionSearchIT extends AbstractWatcherIntegrationTestCase { public class ScriptConditionSearchIT extends AbstractWatcherIntegrationTestCase {
private ThreadPool tp = null; private ThreadPool tp = null;
private ScriptServiceProxy scriptService; private ScriptService scriptService;
@Override @Override
protected List<Class<? extends Plugin>> pluginTypes() { protected List<Class<? extends Plugin>> pluginTypes() {
@ -52,7 +52,7 @@ public class ScriptConditionSearchIT extends AbstractWatcherIntegrationTestCase
@Before @Before
public void init() throws Exception { public void init() throws Exception {
tp = new TestThreadPool(ThreadPool.Names.SAME); tp = new TestThreadPool(ThreadPool.Names.SAME);
scriptService = MessyTestUtils.getScriptServiceProxy(tp); scriptService = MessyTestUtils.createScriptService(tp);
} }
@After @After
@ -73,7 +73,7 @@ public class ScriptConditionSearchIT extends AbstractWatcherIntegrationTestCase
.get(); .get();
ExecutableScriptCondition condition = new ExecutableScriptCondition( 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); logger, scriptService);
WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response)); WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response));
@ -92,7 +92,7 @@ public class ScriptConditionSearchIT extends AbstractWatcherIntegrationTestCase
public void testExecuteAccessHits() throws Exception { public void testExecuteAccessHits() throws Exception {
ExecutableScriptCondition condition = new ExecutableScriptCondition(new ScriptCondition( 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); InternalSearchHit hit = new InternalSearchHit(0, "1", new Text("type"), null);
hit.score(1f); hit.score(1f);
hit.shard(new SearchShardTarget("a", new Index("a", "testUUID"), 0)); 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.common.xcontent.XContentParser;
import org.elasticsearch.script.GeneralScriptException; import org.elasticsearch.script.GeneralScriptException;
import org.elasticsearch.script.ScriptException; import org.elasticsearch.script.ScriptException;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptService.ScriptType; import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.search.internal.InternalSearchResponse; import org.elasticsearch.search.internal.InternalSearchResponse;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool; 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.ExecutableScriptCondition;
import org.elasticsearch.xpack.watcher.condition.script.ScriptCondition; import org.elasticsearch.xpack.watcher.condition.script.ScriptCondition;
import org.elasticsearch.xpack.watcher.condition.script.ScriptConditionFactory; import org.elasticsearch.xpack.watcher.condition.script.ScriptConditionFactory;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext; 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.elasticsearch.xpack.watcher.watch.Payload;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
@ -36,7 +36,7 @@ import java.io.IOException;
import static java.util.Collections.singletonMap; import static java.util.Collections.singletonMap;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; 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.support.Exceptions.illegalArgument;
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.mockExecutionContext; import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.mockExecutionContext;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
@ -57,18 +57,18 @@ public class ScriptConditionTests extends ESTestCase {
} }
public void testExecute() throws Exception { public void testExecute() throws Exception {
ScriptServiceProxy scriptService = getScriptServiceProxy(tp); ScriptService scriptService = createScriptService(tp);
ExecutableScriptCondition condition = new ExecutableScriptCondition( 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]); SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500L, new ShardSearchFailure[0]);
WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response)); WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response));
assertFalse(condition.execute(ctx).met()); assertFalse(condition.execute(ctx).met());
} }
public void testExecuteMergedParams() throws Exception { public void testExecuteMergedParams() throws Exception {
ScriptServiceProxy scriptService = getScriptServiceProxy(tp); ScriptService scriptService = createScriptService(tp);
Script script = Script.inline("ctx.payload.hits.total > threshold") WatcherScript script = WatcherScript.inline("ctx.payload.hits.total > threshold")
.lang(Script.DEFAULT_LANG).params(singletonMap("threshold", 1)).build(); .lang(WatcherScript.DEFAULT_LANG).params(singletonMap("threshold", 1)).build();
ExecutableScriptCondition executable = new ExecutableScriptCondition(new ScriptCondition(script), logger, scriptService); ExecutableScriptCondition executable = new ExecutableScriptCondition(new ScriptCondition(script), logger, scriptService);
SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500L, new ShardSearchFailure[0]); SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500L, new ShardSearchFailure[0]);
WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response)); WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response));
@ -76,7 +76,7 @@ public class ScriptConditionTests extends ESTestCase {
} }
public void testParserValid() throws Exception { 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); 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 { 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(); XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject().endObject(); builder.startObject().endObject();
XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes()); XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
@ -118,7 +118,7 @@ public class ScriptConditionTests extends ESTestCase {
} }
public void testScriptConditionParserBadScript() throws Exception { 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()); ScriptType scriptType = randomFrom(ScriptType.values());
String script; String script;
switch (scriptType) { switch (scriptType) {
@ -139,7 +139,7 @@ public class ScriptConditionTests extends ESTestCase {
} }
public void testScriptConditionParser_badLang() throws Exception { 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; ScriptType scriptType = ScriptType.INLINE;
String script = "return true"; String script = "return true";
XContentBuilder builder = createConditionContent(script, "not_a_valid_lang", scriptType); XContentBuilder builder = createConditionContent(script, "not_a_valid_lang", scriptType);
@ -152,9 +152,9 @@ public class ScriptConditionTests extends ESTestCase {
} }
public void testScriptConditionThrowException() throws Exception { public void testScriptConditionThrowException() throws Exception {
ScriptServiceProxy scriptService = getScriptServiceProxy(tp); ScriptService scriptService = createScriptService(tp);
ExecutableScriptCondition condition = new ExecutableScriptCondition( 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]); SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500L, new ShardSearchFailure[0]);
WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response)); WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response));
ScriptException exception = expectThrows(ScriptException.class, () -> condition.execute(ctx)); ScriptException exception = expectThrows(ScriptException.class, () -> condition.execute(ctx));
@ -162,9 +162,9 @@ public class ScriptConditionTests extends ESTestCase {
} }
public void testScriptConditionReturnObjectThrowsException() throws Exception { public void testScriptConditionReturnObjectThrowsException() throws Exception {
ScriptServiceProxy scriptService = getScriptServiceProxy(tp); ScriptService scriptService = createScriptService(tp);
ExecutableScriptCondition condition = new ExecutableScriptCondition( 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]); SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500L, new ShardSearchFailure[0]);
WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response)); WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response));
Exception exception = expectThrows(GeneralScriptException.class, () -> condition.execute(ctx)); Exception exception = expectThrows(GeneralScriptException.class, () -> condition.execute(ctx));
@ -173,9 +173,9 @@ public class ScriptConditionTests extends ESTestCase {
} }
public void testScriptConditionAccessCtx() throws Exception { public void testScriptConditionAccessCtx() throws Exception {
ScriptServiceProxy scriptService = getScriptServiceProxy(tp); ScriptService scriptService = createScriptService(tp);
ExecutableScriptCondition condition = new ExecutableScriptCondition( 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); logger, scriptService);
SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500L, new ShardSearchFailure[0]); SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500L, new ShardSearchFailure[0]);
WatchExecutionContext ctx = mockExecutionContext("_name", new DateTime(DateTimeZone.UTC), new Payload.XContent(response)); 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.common.settings.Settings;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.groovy.GroovyPlugin; 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.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.test.WatcherTestUtils; import org.elasticsearch.xpack.watcher.test.WatcherTestUtils;
import org.elasticsearch.xpack.watcher.transport.actions.put.PutWatchResponse; import org.elasticsearch.xpack.watcher.transport.actions.put.PutWatchResponse;
@ -72,10 +72,10 @@ public class TransformIT extends AbstractWatcherIntegrationTestCase {
} }
public void testScriptTransform() throws Exception { public void testScriptTransform() throws Exception {
final Script script; final WatcherScript script;
if (randomBoolean()) { if (randomBoolean()) {
logger.info("testing script transform with an inline script"); 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()) { } else if (randomBoolean()) {
logger.info("testing script transform with an indexed script"); logger.info("testing script transform with an indexed script");
client().admin().cluster().preparePutStoredScript() client().admin().cluster().preparePutStoredScript()
@ -83,10 +83,10 @@ public class TransformIT extends AbstractWatcherIntegrationTestCase {
.setScriptLang("groovy") .setScriptLang("groovy")
.setSource(new BytesArray("{\"script\" : \"return [key3 : ctx.payload.key1 + ctx.payload.key2]\"}")) .setSource(new BytesArray("{\"script\" : \"return [key3 : ctx.payload.key1 + ctx.payload.key2]\"}"))
.get(); .get();
script = Script.indexed("_id").lang("groovy").build(); script = WatcherScript.indexed("_id").lang("groovy").build();
} else { } else {
logger.info("testing script transform with a file script"); 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: // put a watch that has watch level transform:
@ -182,8 +182,8 @@ public class TransformIT extends AbstractWatcherIntegrationTestCase {
} }
public void testChainTransform() throws Exception { public void testChainTransform() throws Exception {
final Script script1 = Script.inline("return [key3 : ctx.payload.key1 + ctx.payload.key2]").lang("groovy").build(); final WatcherScript script1 = WatcherScript.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 script2 = WatcherScript.inline("return [key4 : ctx.payload.key3 + 10]").lang("groovy").build();
// put a watch that has watch level transform: // put a watch that has watch level transform:
PutWatchResponse putWatchResponse = watcherClient().preparePutWatch("_id1") PutWatchResponse putWatchResponse = watcherClient().preparePutWatch("_id1")
.setSource(watchBuilder() .setSource(watchBuilder()

View File

@ -28,7 +28,6 @@ import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.suggest.Suggesters; import org.elasticsearch.search.suggest.Suggesters;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.xpack.common.ScriptServiceProxy;
import org.elasticsearch.xpack.common.text.TextTemplate; import org.elasticsearch.xpack.common.text.TextTemplate;
import org.elasticsearch.xpack.watcher.actions.ActionWrapper; import org.elasticsearch.xpack.watcher.actions.ActionWrapper;
import org.elasticsearch.xpack.watcher.actions.ExecutableActions; 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.search.SearchInputFactory;
import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput; import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput;
import org.elasticsearch.xpack.watcher.input.simple.SimpleInput; 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.init.proxy.WatcherClientProxy;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest; import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService; import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
@ -190,7 +189,7 @@ public class SearchInputIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s"); 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() SearchRequest request = client().prepareSearch()
.setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE) .setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
@ -224,7 +223,7 @@ public class SearchInputIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s"); 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(); jsonBuilder().value(TextTemplate.indexed("test-template").params(params).build()).bytes();
SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE) SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
@ -252,7 +251,7 @@ public class SearchInputIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s"); 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) SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
.setIndices("test-search-index").request(); .setIndices("test-search-index").request();
@ -347,7 +346,8 @@ public class SearchInputIT extends ESIntegTestCase {
timeValueSeconds(5)); 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"); createIndex("test-search-index");
ensureGreen("test-search-index"); ensureGreen("test-search-index");
SearchInput.Builder siBuilder = SearchInput.builder(new WatcherSearchTemplateRequest(request, template)); SearchInput.Builder siBuilder = SearchInput.builder(new WatcherSearchTemplateRequest(request, template));
@ -362,15 +362,15 @@ public class SearchInputIT extends ESIntegTestCase {
protected WatcherSearchTemplateService watcherSearchTemplateService() { protected WatcherSearchTemplateService watcherSearchTemplateService() {
String master = internalCluster().getMasterName(); String master = internalCluster().getMasterName();
return new WatcherSearchTemplateService(internalCluster().clusterService(master).getSettings(), 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(IndicesQueriesRegistry.class, master),
internalCluster().getInstance(AggregatorParsers.class, master), internalCluster().getInstance(AggregatorParsers.class, master),
internalCluster().getInstance(Suggesters.class, master) internalCluster().getInstance(Suggesters.class, master)
); );
} }
protected ScriptServiceProxy scriptService() { protected ScriptService scriptService() {
return ScriptServiceProxy.of(internalCluster().getInstance(ScriptService.class)); return internalCluster().getInstance(ScriptService.class);
} }
private XContentSource toXContentSource(SearchInput.Result result) throws IOException { private XContentSource toXContentSource(SearchInput.Result result) throws IOException {
@ -387,7 +387,7 @@ public class SearchInputIT extends ESIntegTestCase {
@Override @Override
public ScriptContext.Plugin getCustomScriptContexts() { 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.search.suggest.Suggesters;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.xpack.common.ScriptServiceProxy;
import org.elasticsearch.xpack.common.text.TextTemplate; import org.elasticsearch.xpack.common.text.TextTemplate;
import org.elasticsearch.xpack.watcher.actions.ExecutableActions; import org.elasticsearch.xpack.watcher.actions.ExecutableActions;
import org.elasticsearch.xpack.watcher.condition.always.ExecutableAlwaysCondition; 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.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput; import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput;
import org.elasticsearch.xpack.watcher.input.simple.SimpleInput; 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.init.proxy.WatcherClientProxy;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest; import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService; import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
@ -348,7 +347,7 @@ public class SearchTransformIT extends ESIntegTestCase {
} }
if (templateName != null) { if (templateName != null) {
assertThat(executable.transform().getRequest().getTemplate(), assertThat(executable.transform().getRequest().getTemplate(),
equalTo(Script.file("template1").build())); equalTo(WatcherScript.file("template1").build()));
} }
SearchSourceBuilder source = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery()); SearchSourceBuilder source = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery());
assertThat(executable.transform().getRequest().getRequest().source(), equalTo(source)); assertThat(executable.transform().getRequest().getRequest().source(), equalTo(source));
@ -381,7 +380,7 @@ public class SearchTransformIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s"); 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) SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchTransform.DEFAULT_SEARCH_TYPE)
.setIndices("test-search-index").request(); .setIndices("test-search-index").request();
@ -415,7 +414,7 @@ public class SearchTransformIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s"); 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() SearchRequest request = client()
.prepareSearch() .prepareSearch()
@ -441,7 +440,7 @@ public class SearchTransformIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s"); 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) SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchTransform.DEFAULT_SEARCH_TYPE)
.setIndices("test-search-index").request(); .setIndices("test-search-index").request();
@ -504,7 +503,7 @@ public class SearchTransformIT extends ESIntegTestCase {
timeValueSeconds(5)); timeValueSeconds(5));
} }
private SearchTransform.Result executeSearchTransform(SearchRequest request, Script template, WatchExecutionContext ctx) private SearchTransform.Result executeSearchTransform(SearchRequest request, WatcherScript template, WatchExecutionContext ctx)
throws IOException { throws IOException {
createIndex("test-search-index"); createIndex("test-search-index");
ensureGreen("test-search-index"); ensureGreen("test-search-index");
@ -519,15 +518,15 @@ public class SearchTransformIT extends ESIntegTestCase {
protected WatcherSearchTemplateService watcherSearchTemplateService() { protected WatcherSearchTemplateService watcherSearchTemplateService() {
String master = internalCluster().getMasterName(); String master = internalCluster().getMasterName();
return new WatcherSearchTemplateService(internalCluster().clusterService(master).getSettings(), 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(IndicesQueriesRegistry.class, master),
internalCluster().getInstance(AggregatorParsers.class, master), internalCluster().getInstance(AggregatorParsers.class, master),
internalCluster().getInstance(Suggesters.class, master) internalCluster().getInstance(Suggesters.class, master)
); );
} }
protected ScriptServiceProxy scriptService() { protected ScriptService scriptService() {
return ScriptServiceProxy.of(internalCluster().getInstance(ScriptService.class)); return internalCluster().getInstance(ScriptService.class);
} }
private static Map<String, Object> doc(String date, String value) { private static Map<String, Object> doc(String date, String value) {
@ -551,7 +550,7 @@ public class SearchTransformIT extends ESIntegTestCase {
@Override @Override
public ScriptContext.Plugin getCustomScriptContexts() { 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.ElasticsearchSecurityException;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.action.search.SearchPhaseExecutionException;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.indices.TermsLookup; import org.elasticsearch.indices.TermsLookup;
import org.elasticsearch.plugins.Plugin; 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.MustachePlugin;
import org.elasticsearch.script.mustache.MustacheScriptEngineService; import org.elasticsearch.script.mustache.TemplateQueryBuilder;
import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredString;
@ -25,7 +24,6 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import static java.util.Collections.singletonMap; 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.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is; 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")); //Template template = new Template(source, INLINE, MustacheScriptEngineService.NAME, null, singletonMap("name", "token"));
SearchResponse response = client().prepareSearch("data").setTypes("a") 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(); .execute().actionGet();
assertThat(response.isTimedOut(), is(false)); assertThat(response.isTimedOut(), is(false));
assertThat(response.getHits().hits().length, is(1)); assertThat(response.getHits().hits().length, is(1));
@ -119,7 +117,7 @@ public class SecurityCachePermissionIT extends SecurityIntegTestCase {
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER, .filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER,
new SecuredString("changeme".toCharArray())))) new SecuredString("changeme".toCharArray()))))
.prepareSearch("data").setTypes("a") .prepareSearch("data").setTypes("a")
.setQuery(QueryBuilders.templateQuery(source, singletonMap("name", "token"))) .setQuery(new TemplateQueryBuilder(source, ScriptService.ScriptType.INLINE, singletonMap("name", "token")))
.execute().actionGet()); .execute().actionGet());
assertThat(e.toString(), containsString("ElasticsearchSecurityException[action")); assertThat(e.toString(), containsString("ElasticsearchSecurityException[action"));
assertThat(e.toString(), containsString("unauthorized")); assertThat(e.toString(), containsString("unauthorized"));

View File

@ -158,7 +158,7 @@ public class WatchAckIT extends AbstractWatcherIntegrationTestCase {
assertThat(parsedWatch.status().actionStatus("_a2").ackStatus().state(), assertThat(parsedWatch.status().actionStatus("_a2").ackStatus().state(),
is(ActionStatus.AckStatus.State.AWAITS_SUCCESSFUL_EXECUTION)); 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())); matchQuery(WatchRecord.Field.STATE.getPreferredName(), ExecutionState.THROTTLED.id()));
assertThat(throttledCount, greaterThan(0L)); assertThat(throttledCount, greaterThan(0L));
} }
@ -240,7 +240,7 @@ public class WatchAckIT extends AbstractWatcherIntegrationTestCase {
assertThat(parsedWatch.status().actionStatus("_a2").ackStatus().state(), assertThat(parsedWatch.status().actionStatus("_a2").ackStatus().state(),
is(ActionStatus.AckStatus.State.AWAITS_SUCCESSFUL_EXECUTION)); 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())); matchQuery(WatchRecord.Field.STATE.getPreferredName(), ExecutionState.THROTTLED.id()));
assertThat(throttledCount, greaterThan(0L)); assertThat(throttledCount, greaterThan(0L));
} }

View File

@ -7,7 +7,7 @@ dependencies {
integTest { integTest {
cluster { cluster {
setting 'script.inline', 'true' 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' extraConfigFile 'x-pack/roles.yml', 'roles.yml'
[ [
test_admin: 'superuser', 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.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; 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.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 java.io.IOException;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; 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 USER = "test_admin";
private static final String PASS = "changeme"; private static final String PASS = "changeme";
public RestIT(@Name("yaml") RestTestCandidate testCandidate) { public ReindexWithSecurityClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate); super(testCandidate);
} }
@ParametersFactory @ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException { public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESRestTestCase.createParameters(0, 1); return ESClientYamlSuiteTestCase.createParameters(0, 1);
} }
/** /**

View File

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

View File

@ -13,6 +13,7 @@ import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.transport.MockTransportClient;
import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
@ -115,6 +116,6 @@ public class SecurityTransportClientIT extends ESIntegTestCase {
.put("cluster.name", clusterName) .put("cluster.name", clusterName)
.build(); .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) { task integTest(type: org.elasticsearch.gradle.test.RestIntegTestTask, dependsOn: buildZip) {
cluster { 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.order', '0'
setting 'xpack.security.authc.realms.custom.type', 'custom' setting 'xpack.security.authc.realms.custom.type', 'custom'
setting 'xpack.security.authc.realms.esusers.order', '1' 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.CustomAuthenticationFailureHandler;
import org.elasticsearch.example.realm.CustomRealm; import org.elasticsearch.example.realm.CustomRealm;
import org.elasticsearch.example.realm.CustomRealmFactory; import org.elasticsearch.xpack.security.authc.AuthenticationFailureHandler;
import org.elasticsearch.xpack.security.authc.AuthenticationModule;
import org.elasticsearch.xpack.extensions.XPackExtension; import org.elasticsearch.xpack.extensions.XPackExtension;
import org.elasticsearch.xpack.security.authc.Realm;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; 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 { public class ExampleRealmExtension extends XPackExtension {
static {
// check that the extension's policy works.
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
System.getSecurityManager().checkPrintJobAccess();
return null;
});
}
@Override @Override
public String name() { public String name() {
return "custom realm example"; 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"; return "a very basic implementation of a custom realm to validate it works";
} }
public void onModule(AuthenticationModule authenticationModule) { @Override
authenticationModule.addCustomRealm(CustomRealm.TYPE, CustomRealmFactory.class); public Map<String, Realm.Factory> getRealms() {
authenticationModule.setAuthenticationFailureHandler(CustomAuthenticationFailureHandler.class); return Collections.singletonMap(CustomRealm.TYPE, CustomRealm::new);
// check that the extension's policy works. }
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
System.getSecurityManager().checkPrintJobAccess(); @Override
return null; 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.SecuredString;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; 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"; public static final String TYPE = "custom";
static final String USER_HEADER = "User"; public static final String USER_HEADER = "User";
static final String PW_HEADER = "Password"; public static final String PW_HEADER = "Password";
static final String KNOWN_USER = "custom_user"; static final String KNOWN_USER = "custom_user";
static final String KNOWN_PW = "changeme"; static final String KNOWN_PW = "changeme";
@ -46,7 +46,8 @@ public class CustomRealm extends Realm<UsernamePasswordToken> {
} }
@Override @Override
public User authenticate(UsernamePasswordToken token) { public User authenticate(AuthenticationToken authToken) {
UsernamePasswordToken token = (UsernamePasswordToken)authToken;
final String actualUser = token.principal(); final String actualUser = token.principal();
if (KNOWN_USER.equals(actualUser) && SecuredString.constantTimeEquals(token.credentials(), KNOWN_PW)) { if (KNOWN_USER.equals(actualUser) && SecuredString.constantTimeEquals(token.credentials(), KNOWN_PW)) {
return new User(actualUser, ROLES); 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.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.XPackTransportClient;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -58,11 +60,10 @@ public class CustomRealmIT extends ESIntegTestCase {
} }
public void testHttpAuthentication() throws Exception { 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.USER_HEADER, CustomRealm.KNOWN_USER),
new BasicHeader(CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW))) { new BasicHeader(CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW));
assertThat(response.getStatusLine().getStatusCode(), is(200)); assertThat(response.getStatusLine().getStatusCode(), is(200));
}
} }
public void testTransportClient() throws Exception { 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.USER_HEADER, CustomRealm.KNOWN_USER)
.put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW) .put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW)
.build(); .build();
try (TransportClient client = TransportClient.builder().settings(settings).addPlugin(XPackPlugin.class).build()) { try (TransportClient client = new XPackTransportClient(settings)) {
client.addTransportAddress(publishAddress); client.addTransportAddress(publishAddress);
ClusterHealthResponse response = client.admin().cluster().prepareHealth().execute().actionGet(); ClusterHealthResponse response = client.admin().cluster().prepareHealth().execute().actionGet();
assertThat(response.isTimedOut(), is(false)); 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.USER_HEADER, CustomRealm.KNOWN_USER + randomAsciiOfLength(1))
.put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW) .put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW)
.build(); .build();
try (TransportClient client = TransportClient.builder().addPlugin(XPackPlugin.class).settings(settings).build()) { try (TransportClient client = new XPackTransportClient(settings)) {
client.addTransportAddress(publishAddress); client.addTransportAddress(publishAddress);
client.admin().cluster().prepareHealth().execute().actionGet(); client.admin().cluster().prepareHealth().execute().actionGet();
fail("authentication failure should have resulted in a NoNodesAvailableException"); fail("authentication failure should have resulted in a NoNodesAvailableException");

View File

@ -7,7 +7,7 @@ dependencies {
integTest { integTest {
cluster { cluster {
setting 'script.inline', 'true' 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' extraConfigFile 'x-pack/roles.yml', 'roles.yml'
[ [
test_admin: 'superuser', test_admin: 'superuser',

View File

@ -118,6 +118,13 @@ public class MigrateToolIT extends MigrateToolTestCase {
String token = basicAuthHeaderValue("bob", new SecuredString("changeme".toCharArray())); String token = basicAuthHeaderValue("bob", new SecuredString("changeme".toCharArray()));
// Create "index1" index and try to search from it as "bob" // Create "index1" index and try to search from it as "bob"
client.filterWithHeader(Collections.singletonMap("Authorization", token)).admin().indices().prepareCreate("index1").get(); 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(); 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.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.node.internal.InternalSettingsPreparer; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.XPackTransportClient;
import org.elasticsearch.xpack.XPackPlugin;
import org.junit.After; import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Before; import org.junit.Before;
@ -25,10 +24,8 @@ import org.junit.BeforeClass;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomAsciiOfLength;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
/** /**
@ -45,6 +42,7 @@ import static org.hamcrest.Matchers.notNullValue;
* your test. * your test.
*/ */
@LuceneTestCase.SuppressSysoutChecks(bugUrl = "we log a lot on purpose") @LuceneTestCase.SuppressSysoutChecks(bugUrl = "we log a lot on purpose")
@ESIntegTestCase.SuppressLocalMode
public abstract class MigrateToolTestCase extends LuceneTestCase { public abstract class MigrateToolTestCase extends LuceneTestCase {
/** /**
@ -77,13 +75,9 @@ public abstract class MigrateToolTestCase extends LuceneTestCase {
.put("client.transport.ignore_cluster_name", true) .put("client.transport.ignore_cluster_name", true)
.put("path.home", tempDir) .put("path.home", tempDir)
.put(Security.USER_SETTING.getKey(), "transport_user:changeme") .put(Security.USER_SETTING.getKey(), "transport_user:changeme")
.put("node.mode", "network") // we require network here!
.build(); .build();
TransportClient.Builder transportClientBuilder = TransportClient.builder() TransportClient client = new XPackTransportClient(clientSettings).addTransportAddresses(transportAddresses);
.addPlugin(XPackPlugin.class)
.settings(clientSettings);
TransportClient client = transportClientBuilder.build().addTransportAddresses(transportAddresses);
logger.info("--> Elasticsearch Java TransportClient started"); logger.info("--> Elasticsearch Java TransportClient started");

View File

@ -15,7 +15,7 @@ integTest {
dependsOn copyGraphRestTests dependsOn copyGraphRestTests
cluster { cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack') plugin ':x-plugins:elasticsearch:x-pack'
extraConfigFile 'x-pack/roles.yml', 'roles.yml' extraConfigFile 'x-pack/roles.yml', 'roles.yml'
setupCommand 'setupTestAdminUser', setupCommand 'setupTestAdminUser',
'bin/x-pack/users', 'useradd', 'test_admin', '-p', 'changeme', '-r', 'superuser' '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.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; 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.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 java.io.IOException;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; 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_USERNAME = "test_admin";
private static final String TEST_ADMIN_PASSWORD = "changeme"; private static final String TEST_ADMIN_PASSWORD = "changeme";
public GraphWithSecurityIT(@Name("yaml") RestTestCandidate testCandidate) { public GraphWithSecurityIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate); super(testCandidate);
} }
@ParametersFactory @ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException { public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESRestTestCase.createParameters(0, 1); return ESClientYamlSuiteTestCase.createParameters(0, 1);
} }
protected String[] getCredentials() { protected String[] getCredentials() {

View File

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

View File

@ -17,7 +17,7 @@ subprojects {
cluster { cluster {
systemProperty 'es.logger.level', 'TRACE' 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' setting 'xpack.monitoring.collection.interval', '3s'
extraConfigFile 'x-pack/roles.yml', '../roles.yml' extraConfigFile 'x-pack/roles.yml', '../roles.yml'
setupCommand 'setupTestAdminUser', setupCommand 'setupTestAdminUser',

View File

@ -7,27 +7,28 @@ package org.elasticsearch.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; 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.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 java.io.IOException;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.hamcrest.Matchers.containsString; 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); super(testCandidate);
} }
@ParametersFactory @ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException { public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESRestTestCase.createParameters(0, 1); return ESClientYamlSuiteTestCase.createParameters(0, 1);
} }
@Override @Override

View File

@ -7,26 +7,27 @@ package org.elasticsearch.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; 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.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 java.io.IOException;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; 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); super(testCandidate);
} }
@ParametersFactory @ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException { public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESRestTestCase.createParameters(0, 1); return ESClientYamlSuiteTestCase.createParameters(0, 1);
} }
@Override @Override

View File

@ -147,7 +147,7 @@ processTestResources.dependsOn(
ext.pluginsCount = 1 // we install xpack explicitly ext.pluginsCount = 1 // we install xpack explicitly
project.rootProject.subprojects.findAll { it.path.startsWith(':plugins:') }.each { subproj -> 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 // 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 pluginsCount += 1
} }
@ -166,7 +166,7 @@ integTest {
setting 'xpack.security.ssl.keystore.path', nodeKeystore.name setting 'xpack.security.ssl.keystore.path', nodeKeystore.name
setting 'xpack.security.ssl.keystore.password', 'keypass' 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/ // copy keystores into config/
extraConfigFile nodeKeystore.name, nodeKeystore 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.cluster.node.info.NodeInfo;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse; import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
import org.elasticsearch.common.io.PathUtils; import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.xpack.security.Security; 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.test.ESIntegTestCase;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import org.junit.After; import org.junit.After;
@ -49,7 +50,6 @@ public class SmokeTestMonitoringWithSecurityIT extends ESIntegTestCase {
private static final String USER = "test_user"; private static final String USER = "test_user";
private static final String PASS = "changeme"; private static final String PASS = "changeme";
private static final String KEYSTORE_PASS = "keypass"; private static final String KEYSTORE_PASS = "keypass";
private static final String MONITORING_PATTERN = ".monitoring-*"; private static final String MONITORING_PATTERN = ".monitoring-*";
@Override @Override
@ -61,9 +61,10 @@ public class SmokeTestMonitoringWithSecurityIT extends ESIntegTestCase {
protected Settings externalClusterClientSettings() { protected Settings externalClusterClientSettings() {
return Settings.builder() return Settings.builder()
.put(Security.USER_SETTING.getKey(), USER + ":" + PASS) .put(Security.USER_SETTING.getKey(), USER + ":" + PASS)
.put(SecurityNettyTransport.SSL_SETTING.getKey(), true) .put(SecurityNetty3Transport.SSL_SETTING.getKey(), true)
.put("xpack.security.ssl.keystore.path", clientKeyStore) .put("xpack.security.ssl.keystore.path", clientKeyStore)
.put("xpack.security.ssl.keystore.password", KEYSTORE_PASS) .put("xpack.security.ssl.keystore.password", KEYSTORE_PASS)
.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME)
.build(); .build();
} }

View File

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

View File

@ -9,13 +9,13 @@ dependencies {
ext.pluginsCount = 1 // we install xpack explicitly ext.pluginsCount = 1 // we install xpack explicitly
project.rootProject.subprojects.findAll { it.path.startsWith(':plugins:') }.each { subproj -> 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 // 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 pluginsCount += 1
} }
integTest { integTest {
cluster { cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack') plugin ':x-plugins:elasticsearch:x-pack'
setupCommand 'setupDummyUser', setupCommand 'setupDummyUser',
'bin/x-pack/users', 'useradd', 'test_user', '-p', 'changeme', '-r', 'superuser' '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.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; 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.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 java.io.IOException;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; 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 USER = "test_user";
private static final String PASS = "changeme"; private static final String PASS = "changeme";
public SmokeTestPluginsIT(@Name("yaml") RestTestCandidate testCandidate) { public XSmokeTestPluginsClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate); super(testCandidate);
} }
@ParametersFactory @ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException { public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESRestTestCase.createParameters(0, 1); return ESClientYamlSuiteTestCase.createParameters(0, 1);
} }
@Override @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 { integTest {
cluster { cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack') plugin ':x-plugins:elasticsearch:x-pack'
setting 'script.inline', 'true' setting 'script.inline', 'true'
setting 'xpack.security.enabled', 'false' setting 'xpack.security.enabled', 'false'
setting 'xpack.monitoring.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.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.parser.RestTestParseException; import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@ -18,15 +19,15 @@ import java.io.IOException;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap; 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); super(testCandidate);
} }
@ParametersFactory @ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException { public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESRestTestCase.createParameters(0, 1); return ESClientYamlSuiteTestCase.createParameters(0, 1);
} }
@Before @Before

View File

@ -5,12 +5,12 @@
*/ */
package org.elasticsearch.smoketest; package org.elasticsearch.smoketest;
import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
/** Runs rest tests against external cluster */ /** Runs rest tests against external cluster */
public class WatcherWithGroovyIT extends WatcherRestTestCase { public class WatcherWithGroovyIT extends WatcherRestTestCase {
public WatcherWithGroovyIT(RestTestCandidate testCandidate) { public WatcherWithGroovyIT(ClientYamlTestCandidate testCandidate) {
super(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 { integTest {
cluster { cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack') plugin ':x-plugins:elasticsearch:x-pack'
setting 'xpack.security.enabled', 'false' setting 'xpack.security.enabled', 'false'
setting 'xpack.monitoring.enabled', 'false' setting 'xpack.monitoring.enabled', 'false'
setting 'http.port', '9400' 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.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.parser.RestTestParseException; import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@ -18,15 +19,15 @@ import java.io.IOException;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap; 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); super(testCandidate);
} }
@ParametersFactory @ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException { public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESRestTestCase.createParameters(0, 1); return ESClientYamlSuiteTestCase.createParameters(0, 1);
} }
@Before @Before

View File

@ -6,37 +6,31 @@
package org.elasticsearch.smoketest; package org.elasticsearch.smoketest;
import com.fasterxml.jackson.core.io.JsonStringEncoder; 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.Nullable;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.script.ScriptContextRegistry; import org.elasticsearch.script.ScriptContextRegistry;
import org.elasticsearch.script.ScriptEngineRegistry; import org.elasticsearch.script.ScriptEngineRegistry;
import org.elasticsearch.script.ScriptEngineService;
import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptSettings; import org.elasticsearch.script.ScriptSettings;
import org.elasticsearch.script.mustache.MustacheScriptEngineService; import org.elasticsearch.script.mustache.MustacheScriptEngineService;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.common.ScriptServiceProxy;
import org.elasticsearch.xpack.common.text.DefaultTextTemplateEngine; import org.elasticsearch.xpack.common.text.DefaultTextTemplateEngine;
import org.elasticsearch.xpack.common.text.TextTemplate; import org.elasticsearch.xpack.common.text.TextTemplate;
import org.elasticsearch.xpack.common.text.TextTemplateEngine; import org.elasticsearch.xpack.common.text.TextTemplateEngine;
import org.elasticsearch.xpack.watcher.support.WatcherScript;
import org.junit.Before; import org.junit.Before;
import org.mockito.Mockito; import org.mockito.Mockito;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.Writer; import java.io.Writer;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue; 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(); Settings setting = Settings.builder().put(ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING, true).build();
Environment environment = Mockito.mock(Environment.class); Environment environment = Mockito.mock(Environment.class);
ResourceWatcherService resourceWatcherService = Mockito.mock(ResourceWatcherService.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( ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(
Collections.singleton(new MustacheScriptEngineService(setting)) Collections.singleton(new MustacheScriptEngineService(setting))
@ -58,7 +52,7 @@ public class WatcherTemplateTests extends ESTestCase {
ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, registry); ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, registry);
ScriptService scriptService = new ScriptService(setting, environment, resourceWatcherService, scriptEngineRegistry, ScriptService scriptService = new ScriptService(setting, environment, resourceWatcherService, scriptEngineRegistry,
registry, scriptSettings); registry, scriptSettings);
engine = new DefaultTextTemplateEngine(Settings.EMPTY, ScriptServiceProxy.of(scriptService)); engine = new DefaultTextTemplateEngine(Settings.EMPTY, scriptService);
} }
public void testEscaping() throws Exception { 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.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.parser.RestTestParseException; import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
import java.io.IOException; import java.io.IOException;
/** Runs rest tests against external cluster */ /** 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); super(testCandidate);
} }
@ParametersFactory @ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException { public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESRestTestCase.createParameters(0, 1); return ESClientYamlSuiteTestCase.createParameters(0, 1);
} }
} }

View File

@ -7,7 +7,7 @@ dependencies {
integTest { integTest {
cluster { cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack') plugin ':x-plugins:elasticsearch:x-pack'
setting 'script.inline', 'true' setting 'script.inline', 'true'
setting 'xpack.security.enabled', 'false' setting 'xpack.security.enabled', 'false'
setting 'xpack.monitoring.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.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.parser.RestTestParseException; import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.test.rest.yaml.parser.ClientYamlTestParseException;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@ -18,15 +19,15 @@ import java.io.IOException;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap; 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); super(testCandidate);
} }
@ParametersFactory @ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException { public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESRestTestCase.createParameters(0, 1); return ESClientYamlSuiteTestCase.createParameters(0, 1);
} }
@Before @Before

View File

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

View File

@ -19,7 +19,7 @@ integTest {
'getting_started/10_monitor_cluster_health/Getting started - Monitor cluster health'].join(',') 'getting_started/10_monitor_cluster_health/Getting started - Monitor cluster health'].join(',')
cluster { cluster {
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack') plugin ':x-plugins:elasticsearch:x-pack'
extraConfigFile 'x-pack/roles.yml', 'roles.yml' extraConfigFile 'x-pack/roles.yml', 'roles.yml'
setupCommand 'setupTestAdminUser', setupCommand 'setupTestAdminUser',
'bin/x-pack/users', 'useradd', 'test_admin', '-p', 'changeme', '-r', 'superuser' '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.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; 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.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.After;
import org.junit.Before; import org.junit.Before;
import java.io.IOException; import java.io.IOException;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap; import static java.util.Collections.emptyMap;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; 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_USERNAME = "test_admin";
private static final String TEST_ADMIN_PASSWORD = "changeme"; private static final String TEST_ADMIN_PASSWORD = "changeme";
public WatcherWithSecurityIT(@Name("yaml") RestTestCandidate testCandidate) { public SmokeTestWatcherWithSecurityClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate); super(testCandidate);
} }
@ParametersFactory @ParametersFactory
public static Iterable<Object[]> parameters() throws IOException, RestTestParseException { public static Iterable<Object[]> parameters() throws IOException, ClientYamlTestParseException {
return ESRestTestCase.createParameters(0, 1); return ESClientYamlSuiteTestCase.createParameters(0, 1);
} }
@Before @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: setup:
- do: - do:

View File

@ -21,14 +21,20 @@ ext.compactProfile = 'full'
dependencyLicenses.enabled = false dependencyLicenses.enabled = false
licenseHeaders {
approvedLicenses << 'BCrypt (BSD-like)'
additionalLicense 'BCRYP', 'BCrypt (BSD-like)', 'Copyright (c) 2006 Damien Miller <djm@mindrot.org>'
}
dependencies { dependencies {
// license deps // license deps
compile project(':x-plugins:elasticsearch:license:base') compile project(':x-plugins:elasticsearch:license:base')
testCompile project(':x-plugins:elasticsearch:license:licensor') testCompile project(':x-plugins:elasticsearch:license:licensor')
// security deps // security deps
compile project(path: ':modules:transport-netty3', configuration: 'runtime')
compile 'dk.brics.automaton:automaton:1.11-8' 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:bcprov-jdk15on:1.54'
compile 'org.bouncycastle:bcpkix-jdk15on:1.54' compile 'org.bouncycastle:bcpkix-jdk15on:1.54'
testCompile 'com.google.jimfs:jimfs:1.1' testCompile 'com.google.jimfs:jimfs:1.1'
@ -231,13 +237,6 @@ thirdPartyAudit.excludes = [
'javax.activation.UnsupportedDataTypeException' '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 -> modifyPom { MavenPom pom ->
pom.withXml { XmlProvider xml -> pom.withXml { XmlProvider xml ->
// first find if we have dependencies at all, and grab the node // 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.action.ActionResponse;
import org.elasticsearch.common.component.LifecycleComponent; import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.inject.util.Providers;
import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.plugins.ActionPlugin;
@ -43,15 +44,9 @@ public class Graph extends Plugin implements ActionPlugin {
} }
public Collection<Module> createGuiceModules() { public Collection<Module> createGuiceModules() {
return Collections.singletonList(new GraphModule(enabled, transportClientMode)); return Collections.singletonList(b -> {
} XPackPlugin.bindFeatureSet(b, GraphFeatureSet.class);
});
@Override
public Collection<Class<? extends LifecycleComponent>> getGuiceServiceClasses() {
if (enabled == false|| transportClientMode) {
return Collections.emptyList();
}
return Collections.singletonList(GraphLicensee.class);
} }
@Override @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.NamedWriteableRegistry;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.xpack.XPackFeatureSet; import org.elasticsearch.xpack.XPackFeatureSet;
import java.io.IOException; import java.io.IOException;
@ -20,12 +21,12 @@ import java.io.IOException;
public class GraphFeatureSet implements XPackFeatureSet { public class GraphFeatureSet implements XPackFeatureSet {
private final boolean enabled; private final boolean enabled;
private final GraphLicensee licensee; private final XPackLicenseState licenseState;
@Inject @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.enabled = Graph.enabled(settings);
this.licensee = licensee; this.licenseState = licenseState;
namedWriteableRegistry.register(Usage.class, Usage.writeableName(Graph.NAME), Usage::new); namedWriteableRegistry.register(Usage.class, Usage.writeableName(Graph.NAME), Usage::new);
} }
@ -41,7 +42,7 @@ public class GraphFeatureSet implements XPackFeatureSet {
@Override @Override
public boolean available() { public boolean available() {
return licensee != null && licensee.isAvailable(); return licenseState != null && licenseState.isGraphAllowed();
} }
@Override @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.common.util.CollectionUtils;
import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders; 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.AggregationBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilder; import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.sampler.DiversifiedAggregationBuilder; 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.search.builder.SearchSourceBuilder;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService; 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.Connection.ConnectionId;
import org.elasticsearch.xpack.graph.action.GraphExploreRequest.TermBoost; import org.elasticsearch.xpack.graph.action.GraphExploreRequest.TermBoost;
import org.elasticsearch.xpack.graph.action.Vertex.VertexId; 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> { public class TransportGraphExploreAction extends HandledTransportAction<GraphExploreRequest, GraphExploreResponse> {
private final TransportSearchAction searchAction; private final TransportSearchAction searchAction;
protected final GraphLicensee licensee; protected final XPackLicenseState licenseState;
static class VertexPriorityQueue extends PriorityQueue<Vertex> { static class VertexPriorityQueue extends PriorityQueue<Vertex> {
@ -76,19 +77,19 @@ public class TransportGraphExploreAction extends HandledTransportAction<GraphExp
@Inject @Inject
public TransportGraphExploreAction(Settings settings, ThreadPool threadPool, TransportSearchAction transportSearchAction, public TransportGraphExploreAction(Settings settings, ThreadPool threadPool, TransportSearchAction transportSearchAction,
TransportService transportService, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, TransportService transportService, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
GraphLicensee licensee) { XPackLicenseState licenseState) {
super(settings, GraphExploreAction.NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver, super(settings, GraphExploreAction.NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver,
GraphExploreRequest::new); GraphExploreRequest::new);
this.searchAction = transportSearchAction; this.searchAction = transportSearchAction;
this.licensee = licensee; this.licenseState = licenseState;
} }
@Override @Override
protected void doExecute(GraphExploreRequest request, ActionListener<GraphExploreResponse> listener) { protected void doExecute(GraphExploreRequest request, ActionListener<GraphExploreResponse> listener) {
if (licensee.isAvailable()) { if (licenseState.isGraphAllowed()) {
new AsyncGraphAction(request, listener).start(); new AsyncGraphAction(request, listener).start();
} else { } 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.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.graph.GraphFeatureSet;
import org.elasticsearch.xpack.graph.GraphLicensee;
import org.junit.Before; import org.junit.Before;
import static org.hamcrest.core.Is.is; import static org.hamcrest.core.Is.is;
@ -24,24 +23,24 @@ import static org.mockito.Mockito.when;
*/ */
public class GraphFeatureSetTests extends ESTestCase { public class GraphFeatureSetTests extends ESTestCase {
private GraphLicensee licensee; private XPackLicenseState licenseState;
private NamedWriteableRegistry namedWriteableRegistry; private NamedWriteableRegistry namedWriteableRegistry;
@Before @Before
public void init() throws Exception { public void init() throws Exception {
licensee = mock(GraphLicensee.class); licenseState = mock(XPackLicenseState.class);
namedWriteableRegistry = mock(NamedWriteableRegistry.class); namedWriteableRegistry = mock(NamedWriteableRegistry.class);
} }
public void testWritableRegistration() throws Exception { 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()); verify(namedWriteableRegistry).register(eq(GraphFeatureSet.Usage.class), eq("xpack.usage.graph"), anyObject());
} }
public void testAvailable() throws Exception { public void testAvailable() throws Exception {
GraphFeatureSet featureSet = new GraphFeatureSet(Settings.EMPTY, licensee, namedWriteableRegistry); GraphFeatureSet featureSet = new GraphFeatureSet(Settings.EMPTY, licenseState, namedWriteableRegistry);
boolean available = randomBoolean(); boolean available = randomBoolean();
when(licensee.isAvailable()).thenReturn(available); when(licenseState.isGraphAllowed()).thenReturn(available);
assertThat(featureSet.available(), is(available)); assertThat(featureSet.available(), is(available));
} }
@ -55,7 +54,7 @@ public class GraphFeatureSetTests extends ESTestCase {
} else { } else {
settings.put("xpack.graph.enabled", enabled); settings.put("xpack.graph.enabled", enabled);
} }
GraphFeatureSet featureSet = new GraphFeatureSet(settings.build(), licensee, namedWriteableRegistry); GraphFeatureSet featureSet = new GraphFeatureSet(settings.build(), licenseState, namedWriteableRegistry);
assertThat(featureSet.enabled(), is(enabled)); 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; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.plugin.action.delete; package org.elasticsearch.license;
import org.elasticsearch.action.Action; import org.elasticsearch.action.Action;
import org.elasticsearch.client.ElasticsearchClient; import org.elasticsearch.client.ElasticsearchClient;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.plugin.core; package org.elasticsearch.license;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
@ -18,18 +18,18 @@ import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.component.AbstractLifecycleComponent; import org.elasticsearch.common.component.AbstractLifecycleComponent;
import org.elasticsearch.common.component.Lifecycle; import org.elasticsearch.common.component.Lifecycle;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.joda.FormatDateTimeFormatter; import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.joda.Joda; import org.elasticsearch.common.joda.Joda;
import org.elasticsearch.common.logging.LoggerMessageFormat; import org.elasticsearch.common.logging.LoggerMessageFormat;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.env.Environment;
import org.elasticsearch.gateway.GatewayService; import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.license.core.License; import org.elasticsearch.license.core.License;
import org.elasticsearch.license.core.LicenseVerifier; import org.elasticsearch.license.core.LicenseVerifier;
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseRequest; import org.elasticsearch.license.core.OperationModeFileWatcher;
import org.elasticsearch.license.plugin.action.put.PutLicenseRequest; import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse; import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.scheduler.SchedulerEngine; import org.elasticsearch.xpack.scheduler.SchedulerEngine;
import org.elasticsearch.xpack.support.clock.Clock; import org.elasticsearch.xpack.support.clock.Clock;
@ -40,41 +40,29 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
/** /**
* Service responsible for managing {@link LicensesMetaData} * Service responsible for managing {@link LicensesMetaData}.
* Interfaces through which this is exposed are:
* - LicensesManagerService - responsible for managing signed and one-time-trial licenses
* - LicensesClientService - responsible for listener registration of consumer plugin(s)
* <p> * <p>
* Registration Scheme: * On the master node, the service handles updating the cluster state when a new license is registered.
* <p> * It also listens on all nodes for cluster state updates, and updates {@link XPackLicenseState} when
* A consumer plugin is registered with {@link LicenseeRegistry#register(Licensee)} * the license changes are detected in the cluster state.
* This method can be called at any time during the life-cycle of the consumer plugin.
* If the listener can not be registered immediately, it is queued up and registered on the first clusterChanged event with
* no {@link org.elasticsearch.gateway.GatewayService#STATE_NOT_RECOVERED_BLOCK} block
* Upon successful registration, the listeners are notified appropriately using the notification scheme
* <p>
* Notification Scheme:
* <p>
* All registered listeners are notified of the current license upon registration or when a new license is installed in the cluster state.
* When a new license is notified as enabled to the registered listener, a notification is scheduled at the time of license expiry.
* Registered listeners are notified using {@link #onUpdate(LicensesMetaData)}
*/ */
public class LicensesService extends AbstractLifecycleComponent implements ClusterStateListener, LicensesManagerService, public class LicenseService extends AbstractLifecycleComponent implements ClusterStateListener, SchedulerEngine.Listener {
LicenseeRegistry, SchedulerEngine.Listener {
// pkg private for tests // pkg private for tests
static final TimeValue TRIAL_LICENSE_DURATION = TimeValue.timeValueHours(30 * 24); 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; private final ClusterService clusterService;
/** /** The xpack feature state to update when license changes are made. */
* Currently active consumers to notify to private final XPackLicenseState licenseState;
*/
private final List<InternalLicensee> registeredLicensees = new CopyOnWriteArrayList<>();
/** /**
* Currently active license * Currently active license
@ -83,6 +71,11 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
private SchedulerEngine scheduler; private SchedulerEngine scheduler;
private final Clock clock; private final Clock clock;
/**
* File watcher for operation mode changes
*/
private final OperationModeFileWatcher operationModeFileWatcher;
/** /**
* Callbacks to notify relative to license expiry * Callbacks to notify relative to license expiry
*/ */
@ -93,125 +86,78 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
*/ */
private int trialLicenseMaxNodes = 1000; private int trialLicenseMaxNodes = 1000;
/** public static final String LICENSE_JOB = "licenseJob";
* 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";
private static final FormatDateTimeFormatter DATE_FORMATTER = Joda.forPattern("EEEE, MMMMM dd, yyyy", Locale.ROOT); 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, " + 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:"; "please read the following messages and update the license again, this time with the \"acknowledge=true\" parameter:";
@Inject public LicenseService(Settings settings, ClusterService clusterService, Clock clock, Environment env,
public LicensesService(Settings settings, ClusterService clusterService, Clock clock) { ResourceWatcherService resourceWatcherService, XPackLicenseState licenseState) {
super(settings); super(settings);
this.clusterService = clusterService; this.clusterService = clusterService;
populateExpirationCallbacks();
this.clock = clock; this.clock = clock;
this.scheduler = new SchedulerEngine(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); 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() { private void populateExpirationCallbacks() {
expirationCallbacks.add(new ExpirationCallback.Pre(days(7), days(25), days(1)) { expirationCallbacks.add(new ExpirationCallback.Pre(days(7), days(25), days(1)) {
@Override @Override
public void on(License license) { public void on(License license) {
String general = LoggerMessageFormat.format(null, "\n" + logExpirationWarning(license.expiryDate(), false);
"#\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);
}
}
}
);
expirationCallbacks.add(new ExpirationCallback.Pre(days(0), days(7), TimeValue.timeValueMinutes(10)) { expirationCallbacks.add(new ExpirationCallback.Pre(days(0), days(7), TimeValue.timeValueMinutes(10)) {
@Override @Override
public void on(License license) { public void on(License license) {
String general = LoggerMessageFormat.format(null, "\n" + logExpirationWarning(license.expiryDate(), false);
"#\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);
}
}
}
);
expirationCallbacks.add(new ExpirationCallback.Post(days(0), null, TimeValue.timeValueMinutes(10)) { expirationCallbacks.add(new ExpirationCallback.Post(days(0), null, TimeValue.timeValueMinutes(10)) {
@Override @Override
public void on(License license) { public void on(License license) {
// logged when grace period begins // logged when grace period begins
String general = LoggerMessageFormat.format(null, "\n" + logExpirationWarning(license.expiryDate(), true);
"#\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);
}
}
}
);
} }
/** /**
@ -227,22 +173,23 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
listener.onResponse(new PutLicenseResponse(true, LicensesStatus.EXPIRED)); listener.onResponse(new PutLicenseResponse(true, LicensesStatus.EXPIRED));
} else { } else {
if (!request.acknowledged()) { 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(); final License currentLicense = getLicense();
if (currentLicense != null) { 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 if (!License.isAutoGeneratedLicense(currentLicense.signature()) // current license is not auto-generated
&& currentLicense.issueDate() > newLicense.issueDate()) { // and has a later issue date && currentLicense.issueDate() > newLicense.issueDate()) { // and has a later issue date
acknowledgeMessages.put("license", acknowledgeMessages.put("license", new String[]{
new String[]{"The new license is older than the currently installed license. Are you sure you want to " + "The new license is older than the currently installed license. " +
"override the current license?"}); "Are you sure you want to override the current license?"});
} }
for (InternalLicensee licensee : registeredLicensees) { XPackLicenseState.ACKNOWLEDGMENT_MESSAGES.forEach((feature, ackMessages) -> {
String[] listenerAcknowledgeMessages = licensee.acknowledgmentMessages(currentLicense, newLicense); String[] messages = ackMessages.apply(currentLicense.operationMode(), newLicense.operationMode());
if (listenerAcknowledgeMessages.length > 0) { if (messages.length > 0) {
acknowledgeMessages.put(licensee.id(), listenerAcknowledgeMessages); acknowledgeMessages.put(feature, messages);
} }
} });
if (!acknowledgeMessages.isEmpty()) { if (acknowledgeMessages.isEmpty() == false) {
// needs acknowledgement // needs acknowledgement
listener.onResponse(new PutLicenseResponse(false, LicensesStatus.VALID, ACKNOWLEDGEMENT_HEADER, listener.onResponse(new PutLicenseResponse(false, LicensesStatus.VALID, ACKNOWLEDGEMENT_HEADER,
acknowledgeMessages)); acknowledgeMessages));
@ -278,7 +225,7 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
if (licensesMetaData != null) { if (licensesMetaData != null) {
final License license = licensesMetaData.getLicense(); final License license = licensesMetaData.getLicense();
if (event.getJobName().equals(LICENSE_JOB)) { if (event.getJobName().equals(LICENSE_JOB)) {
notifyLicensees(license); updateLicenseState(license);
} else if (event.getJobName().startsWith(ExpirationCallback.EXPIRATION_JOB_PREFIX)) { } else if (event.getJobName().startsWith(ExpirationCallback.EXPIRATION_JOB_PREFIX)) {
expirationCallbacks.stream() expirationCallbacks.stream()
.filter(expirationCallback -> expirationCallback.getId().equals(event.getJobName())) .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() { public License getLicense() {
final License license = getLicense(clusterService.state().metaData().custom(LicensesMetaData.TYPE)); final License license = getLicense(clusterService.state().metaData().custom(LicensesMetaData.TYPE));
return license == LicensesMetaData.LICENSE_TOMBSTONE ? null : license; return license == LicensesMetaData.LICENSE_TOMBSTONE ? null : license;
@ -377,15 +313,25 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
protected void doStart() throws ElasticsearchException { protected void doStart() throws ElasticsearchException {
clusterService.add(this); clusterService.add(this);
scheduler.start(Collections.emptyList()); 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 @Override
protected void doStop() throws ElasticsearchException { protected void doStop() throws ElasticsearchException {
clusterService.remove(this); clusterService.remove(this);
scheduler.stop(); scheduler.stop();
// clear all handlers
registeredLicensees.clear();
// clear current license // clear current license
currentLicense.set(null); 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) { if (license == LicensesMetaData.LICENSE_TOMBSTONE) {
// implies license has been explicitly deleted // implies license has been explicitly deleted
// update licensee states licenseState.update(License.OperationMode.MISSING, false);
registeredLicensees.forEach(InternalLicensee::onRemove);
return; return;
} }
if (license != null) { if (license != null) {
logger.debug("notifying [{}] listeners", registeredLicensees.size()); long time = clock.millis();
switch (getLicenseState(license, clock.millis())) { boolean active = time >= license.issueDate() &&
case ENABLED: time < license.expiryDate() + GRACE_PERIOD_DURATION.getMillis();
for (InternalLicensee licensee : registeredLicensees) { licenseState.update(license.operationMode(), active);
licensee.onChange(license, LicenseState.ENABLED);
} if (active) {
if (time < license.expiryDate()) {
logger.debug("license [{}] - valid", license.uid()); logger.debug("license [{}] - valid", license.uid());
break; } else {
case GRACE_PERIOD:
for (InternalLicensee licensee : registeredLicensees) {
licensee.onChange(license, LicenseState.GRACE_PERIOD);
}
logger.warn("license [{}] - grace", license.uid()); logger.warn("license [{}] - grace", license.uid());
break; }
case DISABLED: } else {
for (InternalLicensee licensee : registeredLicensees) { logger.warn("license [{}] - expired", license.uid());
licensee.onChange(license, LicenseState.DISABLED);
}
logger.warn("license [{}] - expired", license.uid());
break;
} }
} }
} }
static LicenseState getLicenseState(final License license, long time) {
if (license == null) {
return LicenseState.DISABLED;
}
if (license.issueDate() > time) {
return LicenseState.DISABLED;
}
if (license.expiryDate() > time) {
return LicenseState.ENABLED;
}
if ((license.expiryDate() + GRACE_PERIOD_DURATION.getMillis()) > time) {
return LicenseState.GRACE_PERIOD;
}
return LicenseState.DISABLED;
}
/** /**
* Notifies registered licensees of license state change and/or new active license * Notifies registered licensees of license state change and/or new active license
* based on the license in <code>currentLicensesMetaData</code>. * 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 // license can be null if the trial license is yet to be auto-generated
// in this case, it is a no-op // in this case, it is a no-op
if (license != null) { if (license != null) {
notifyLicensees(license); final License previousLicense = currentLicense.get();
if (license.equals(currentLicense.get()) == false) { if (license.equals(previousLicense) == false) {
currentLicense.set(license); 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) { for (ExpirationCallback expirationCallback : expirationCallbacks) {
scheduler.add(new SchedulerEngine.Job(expirationCallback.getId(), scheduler.add(new SchedulerEngine.Job(expirationCallback.getId(),
(startTime, now) -> (startTime, now) ->
expirationCallback.nextScheduledTimeForExpiry(license.expiryDate(), startTime, now))); expirationCallback.nextScheduledTimeForExpiry(license.expiryDate(), startTime, now)));
} }
if (previousLicense != null) {
// remove operationModeFileWatcher to gc the old license object
previousLicense.removeOperationModeFileWatcher();
}
} }
updateLicenseState(license);
} }
} }
@Override // pkg private for tests
public void register(Licensee licensee) { static SchedulerEngine.Schedule nextLicenseCheck(License license) {
for (final InternalLicensee existingLicensee : registeredLicensees) { return (startTime, time) -> {
if (existingLicensee.id().equals(licensee.id())) { if (time < license.issueDate()) {
throw new IllegalStateException("listener: [" + licensee.id() + "] has been already registered"); // 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();
} }
} return -1; // license is expired, no need to check again
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());
}
}
} }
License getLicense(final LicensesMetaData metaData) { License getLicense(final LicensesMetaData metaData) {
@ -532,7 +454,7 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
License license = metaData.getLicense(); License license = metaData.getLicense();
if (license == LicensesMetaData.LICENSE_TOMBSTONE) { if (license == LicensesMetaData.LICENSE_TOMBSTONE) {
return license; return license;
} else { } else if (license != null) {
boolean autoGeneratedLicense = License.isAutoGeneratedLicense(license.signature()); boolean autoGeneratedLicense = License.isAutoGeneratedLicense(license.signature());
if ((autoGeneratedLicense && TrialLicense.verify(license)) if ((autoGeneratedLicense && TrialLicense.verify(license))
|| (!autoGeneratedLicense && LicenseVerifier.verifyLicense(license))) { || (!autoGeneratedLicense && LicenseVerifier.verifyLicense(license))) {
@ -542,58 +464,4 @@ public class LicensesService extends AbstractLifecycleComponent implements Clust
} }
return null; 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; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.plugin.core; package org.elasticsearch.license;
import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.RestStatus;

View File

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

View File

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

View File

@ -3,37 +3,26 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.plugin; package org.elasticsearch.license;
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;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; 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 java.util.Collections.emptyList;
import static org.elasticsearch.xpack.XPackPlugin.isTribeNode; import static org.elasticsearch.xpack.XPackPlugin.isTribeNode;
import static org.elasticsearch.xpack.XPackPlugin.transportClientMode; import static org.elasticsearch.xpack.XPackPlugin.transportClientMode;
@ -42,7 +31,8 @@ import static org.elasticsearch.xpack.XPackPlugin.transportClientMode;
public class Licensing implements ActionPlugin { public class Licensing implements ActionPlugin {
public static final String NAME = "license"; public static final String NAME = "license";
private final boolean isTransportClient; protected final Settings settings;
protected final boolean isTransportClient;
private final boolean isTribeNode; private final boolean isTribeNode;
static { static {
@ -50,10 +40,15 @@ public class Licensing implements ActionPlugin {
} }
public Licensing(Settings settings) { public Licensing(Settings settings) {
this.settings = settings;
isTransportClient = transportClientMode(settings); isTransportClient = transportClientMode(settings);
isTribeNode = isTribeNode(settings); isTribeNode = isTribeNode(settings);
} }
public Collection<Module> nodeModules() {
return Collections.emptyList();
}
@Override @Override
public List<ActionHandler<? extends ActionRequest<?>, ? extends ActionResponse>> getActions() { public List<ActionHandler<? extends ActionRequest<?>, ? extends ActionResponse>> getActions() {
if (isTribeNode) { if (isTribeNode) {
@ -74,22 +69,12 @@ public class Licensing implements ActionPlugin {
RestDeleteLicenseAction.class); RestDeleteLicenseAction.class);
} }
public Collection<Class<? extends LifecycleComponent>> nodeServices() { public Collection<Object> createComponents(ClusterService clusterService, Clock clock, Environment environment,
if (isTransportClient == false && isTribeNode == false) { ResourceWatcherService resourceWatcherService,
return Collections.<Class<? extends LifecycleComponent>>singletonList(LicensesService.class); XPackLicenseState licenseState) {
} LicenseService licenseService = new LicenseService(settings, clusterService, clock,
return Collections.emptyList(); environment, resourceWatcherService, licenseState);
} return Arrays.asList(licenseService, licenseState);
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 List<Setting<?>> getSettings() { public List<Setting<?>> getSettings() {

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.plugin.action.put; package org.elasticsearch.license;
import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.common.io.stream.StreamInput; 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.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.license.plugin.core.LicensesStatus; import org.elasticsearch.license.LicensesStatus;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; 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; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.plugin.rest; package org.elasticsearch.license;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.license.core.License; import org.elasticsearch.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.BytesRestResponse;
import org.elasticsearch.rest.RestChannel; import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestResponse; import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.action.support.RestBuilderListener; 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.HashMap;
import java.util.Map; 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.NOT_FOUND;
import static org.elasticsearch.rest.RestStatus.OK; import static org.elasticsearch.rest.RestStatus.OK;
public class RestGetLicenseAction extends BaseRestHandler { public class RestGetLicenseAction extends XPackRestHandler {
@Inject @Inject
public RestGetLicenseAction(Settings settings, RestController controller) { public RestGetLicenseAction(Settings settings, RestController controller) {
super(settings); 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 * The licenses are sorted by latest issue_date
*/ */
@Override @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); final Map<String, String> overrideParams = new HashMap<>(2);
overrideParams.put(License.REST_VIEW_MODE, "true"); overrideParams.put(License.REST_VIEW_MODE, "true");
overrideParams.put(License.LICENSE_VERSION_MODE, String.valueOf(License.VERSION_CURRENT)); overrideParams.put(License.LICENSE_VERSION_MODE, String.valueOf(License.VERSION_CURRENT));
final ToXContent.Params params = new ToXContent.DelegatingMapParams(overrideParams, request); final ToXContent.Params params = new ToXContent.DelegatingMapParams(overrideParams, request);
GetLicenseRequest getLicenseRequest = new GetLicenseRequest(); GetLicenseRequest getLicenseRequest = new GetLicenseRequest();
getLicenseRequest.local(request.paramAsBoolean("local", getLicenseRequest.local())); 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) { new RestBuilderListener<GetLicenseResponse>(channel) {
@Override @Override
public RestResponse buildResponse(GetLicenseResponse response, XContentBuilder builder) throws Exception { 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; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.plugin.rest; package org.elasticsearch.license;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.license.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.BytesRestResponse;
import org.elasticsearch.rest.RestChannel; import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestController;
@ -21,25 +16,40 @@ import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestResponse; import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.support.RestBuilderListener; 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.POST;
import static org.elasticsearch.rest.RestRequest.Method.PUT; import static org.elasticsearch.rest.RestRequest.Method.PUT;
public class RestPutLicenseAction extends BaseRestHandler { public class RestPutLicenseAction extends XPackRestHandler {
@Inject @Inject
public RestPutLicenseAction(Settings settings, RestController controller) { public RestPutLicenseAction(Settings settings, RestController controller) {
super(settings); super(settings);
controller.registerHandler(PUT, "/_xpack/license", this); // @deprecated Remove deprecations in 6.0
controller.registerHandler(POST, "/_xpack/license", this); 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 @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 putLicenseRequest = new PutLicenseRequest();
putLicenseRequest.license(request.content().utf8ToString()); putLicenseRequest.license(request.content().utf8ToString());
putLicenseRequest.acknowledge(request.paramAsBoolean("acknowledge", false)); 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) { new RestBuilderListener<PutLicenseResponse>(channel) {
@Override @Override
public RestResponse buildResponse(PutLicenseResponse response, XContentBuilder builder) throws Exception { 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; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.plugin.action.delete; package org.elasticsearch.license;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
@ -17,21 +17,20 @@ import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.plugin.core.LicensesService;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService; import org.elasticsearch.transport.TransportService;
public class TransportDeleteLicenseAction extends TransportMasterNodeAction<DeleteLicenseRequest, DeleteLicenseResponse> { public class TransportDeleteLicenseAction extends TransportMasterNodeAction<DeleteLicenseRequest, DeleteLicenseResponse> {
private final LicensesService licensesService; private final LicenseService licenseService;
@Inject @Inject
public TransportDeleteLicenseAction(Settings settings, TransportService transportService, ClusterService clusterService, public TransportDeleteLicenseAction(Settings settings, TransportService transportService, ClusterService clusterService,
LicensesService licensesService, ThreadPool threadPool, ActionFilters actionFilters, LicenseService licenseService, ThreadPool threadPool, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver) { IndexNameExpressionResolver indexNameExpressionResolver) {
super(settings, DeleteLicenseAction.NAME, transportService, clusterService, threadPool, actionFilters, super(settings, DeleteLicenseAction.NAME, transportService, clusterService, threadPool, actionFilters,
indexNameExpressionResolver, DeleteLicenseRequest::new); indexNameExpressionResolver, DeleteLicenseRequest::new);
this.licensesService = licensesService; this.licenseService = licenseService;
} }
@Override @Override
@ -52,7 +51,7 @@ public class TransportDeleteLicenseAction extends TransportMasterNodeAction<Dele
@Override @Override
protected void masterOperation(final DeleteLicenseRequest request, ClusterState state, final ActionListener<DeleteLicenseResponse> protected void masterOperation(final DeleteLicenseRequest request, ClusterState state, final ActionListener<DeleteLicenseResponse>
listener) throws ElasticsearchException { listener) throws ElasticsearchException {
licensesService.removeLicense(request, new ActionListener<ClusterStateUpdateResponse>() { licenseService.removeLicense(request, new ActionListener<ClusterStateUpdateResponse>() {
@Override @Override
public void onResponse(ClusterStateUpdateResponse clusterStateUpdateResponse) { public void onResponse(ClusterStateUpdateResponse clusterStateUpdateResponse) {
listener.onResponse(new DeleteLicenseResponse(clusterStateUpdateResponse.isAcknowledged())); listener.onResponse(new DeleteLicenseResponse(clusterStateUpdateResponse.isAcknowledged()));

View File

@ -3,34 +3,33 @@
* or more contributor license agreements. Licensed under the Elastic License; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.plugin.action.get; package org.elasticsearch.license;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.ActionFilters; import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.master.TransportMasterNodeReadAction; import org.elasticsearch.action.support.master.TransportMasterNodeReadAction;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.block.ClusterBlockException; import org.elasticsearch.cluster.block.ClusterBlockException;
import org.elasticsearch.cluster.block.ClusterBlockLevel; import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.plugin.core.LicensesManagerService;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService; import org.elasticsearch.transport.TransportService;
public class TransportGetLicenseAction extends TransportMasterNodeReadAction<GetLicenseRequest, GetLicenseResponse> { public class TransportGetLicenseAction extends TransportMasterNodeReadAction<GetLicenseRequest, GetLicenseResponse> {
private final LicensesManagerService licensesManagerService; private final LicenseService licenseService;
@Inject @Inject
public TransportGetLicenseAction(Settings settings, TransportService transportService, ClusterService clusterService, public TransportGetLicenseAction(Settings settings, TransportService transportService, ClusterService clusterService,
LicensesManagerService licensesManagerService, ThreadPool threadPool, ActionFilters actionFilters, LicenseService licenseService, ThreadPool threadPool, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver) { IndexNameExpressionResolver indexNameExpressionResolver) {
super(settings, GetLicenseAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, super(settings, GetLicenseAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver,
GetLicenseRequest::new); GetLicenseRequest::new);
this.licensesManagerService = licensesManagerService; this.licenseService = licenseService;
} }
@Override @Override
@ -51,6 +50,6 @@ public class TransportGetLicenseAction extends TransportMasterNodeReadAction<Get
@Override @Override
protected void masterOperation(final GetLicenseRequest request, ClusterState state, final ActionListener<GetLicenseResponse> protected void masterOperation(final GetLicenseRequest request, ClusterState state, final ActionListener<GetLicenseResponse>
listener) throws ElasticsearchException { 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; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.plugin.action.put; package org.elasticsearch.license;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
@ -16,21 +16,20 @@ import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.plugin.core.LicensesService;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService; import org.elasticsearch.transport.TransportService;
public class TransportPutLicenseAction extends TransportMasterNodeAction<PutLicenseRequest, PutLicenseResponse> { public class TransportPutLicenseAction extends TransportMasterNodeAction<PutLicenseRequest, PutLicenseResponse> {
private final LicensesService licensesService; private final LicenseService licenseService;
@Inject @Inject
public TransportPutLicenseAction(Settings settings, TransportService transportService, ClusterService clusterService, public TransportPutLicenseAction(Settings settings, TransportService transportService, ClusterService clusterService,
LicensesService licensesService, ThreadPool threadPool, ActionFilters actionFilters, LicenseService licenseService, ThreadPool threadPool, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver) { IndexNameExpressionResolver indexNameExpressionResolver) {
super(settings, PutLicenseAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, super(settings, PutLicenseAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver,
PutLicenseRequest::new); PutLicenseRequest::new);
this.licensesService = licensesService; this.licenseService = licenseService;
} }
@Override @Override
@ -51,7 +50,7 @@ public class TransportPutLicenseAction extends TransportMasterNodeAction<PutLice
@Override @Override
protected void masterOperation(final PutLicenseRequest request, ClusterState state, final ActionListener<PutLicenseResponse> protected void masterOperation(final PutLicenseRequest request, ClusterState state, final ActionListener<PutLicenseResponse>
listener) throws ElasticsearchException { 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; * or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
package org.elasticsearch.license.plugin.core; package org.elasticsearch.license;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.ToXContent; 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.decrypt;
import static org.elasticsearch.license.core.CryptUtils.encrypt; import static org.elasticsearch.license.core.CryptUtils.encrypt;
public class TrialLicense { class TrialLicense {
public static License create(License.Builder specBuilder) { public static License create(License.Builder specBuilder) {
License spec = specBuilder License spec = specBuilder

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