Watcher: Adhere to new licensing requirements

* Basic license equlas disabling
* trial/gold/platinum: everything is allowed
* On expiry: actions of watches do not execute, PUT/GET on watches is disabled

Closes elastic/elasticsearch#688

Original commit: elastic/x-pack-elasticsearch@7017c62136
This commit is contained in:
Alexander Reelsen 2015-10-14 17:59:09 +02:00
parent 6dbad15e56
commit b927fd08bc
26 changed files with 396 additions and 562 deletions

View File

@ -74,7 +74,7 @@ public class ShieldActionFilter extends AbstractComponent implements ActionFilte
logger.error("blocking [{}] operation due to expired license. Cluster health, cluster stats and indices stats \n" +
"operations are blocked on shield license expiration. All data operations (read and write) continue to work. \n" +
"If you have a new license, please update it. Otherwise, please reach out to your support contact.", action);
throw LicenseUtils.newExpirationException(ShieldPlugin.NAME);
throw LicenseUtils.newComplianceException(ShieldPlugin.NAME);
}
try {

View File

@ -34,7 +34,7 @@ import org.elasticsearch.watcher.history.HistoryModule;
import org.elasticsearch.watcher.history.HistoryStore;
import org.elasticsearch.watcher.input.InputModule;
import org.elasticsearch.watcher.license.LicenseModule;
import org.elasticsearch.watcher.license.LicenseService;
import org.elasticsearch.watcher.license.WatcherLicensee;
import org.elasticsearch.watcher.rest.action.*;
import org.elasticsearch.watcher.shield.ShieldIntegration;
import org.elasticsearch.watcher.shield.WatcherShieldModule;
@ -143,7 +143,7 @@ public class WatcherPlugin extends Plugin {
// as other services may depend on one of the initialized
// constructs
InitializingService.class,
LicenseService.class,
WatcherLicensee.class,
InternalEmailService.class,
InternalHipChatService.class,
InternalSlackService.class,

View File

@ -8,7 +8,7 @@ package org.elasticsearch.watcher.actions;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.watcher.license.LicenseService;
import org.elasticsearch.watcher.license.WatcherLicensee;
import org.elasticsearch.watcher.support.clock.Clock;
import org.elasticsearch.watcher.support.validation.Validation;
import org.elasticsearch.watcher.transform.TransformRegistry;
@ -25,14 +25,14 @@ public class ActionRegistry {
private final Map<String, ActionFactory> parsers;
private final TransformRegistry transformRegistry;
private final Clock clock;
private final LicenseService licenseService;
private final WatcherLicensee watcherLicensee;
@Inject
public ActionRegistry(Map<String, ActionFactory> parsers, TransformRegistry transformRegistry, Clock clock, LicenseService licenseService) {
public ActionRegistry(Map<String, ActionFactory> parsers, TransformRegistry transformRegistry, Clock clock, WatcherLicensee watcherLicensee) {
this.parsers = parsers;
this.transformRegistry = transformRegistry;
this.clock = clock;
this.licenseService = licenseService;
this.watcherLicensee = watcherLicensee;
}
ActionFactory factory(String type) {
@ -55,7 +55,7 @@ public class ActionRegistry {
throw new ElasticsearchParseException("could not parse action [{}] for watch [{}]. {}", id, watchId, error);
}
} else if (token == XContentParser.Token.START_OBJECT && id != null) {
ActionWrapper action = ActionWrapper.parse(watchId, id, parser, this, transformRegistry, clock, licenseService);
ActionWrapper action = ActionWrapper.parse(watchId, id, parser, this, transformRegistry, clock, watcherLicensee);
actions.add(action);
}
}

View File

@ -17,7 +17,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.watcher.actions.throttler.ActionThrottler;
import org.elasticsearch.watcher.actions.throttler.Throttler;
import org.elasticsearch.watcher.execution.WatchExecutionContext;
import org.elasticsearch.watcher.license.LicenseService;
import org.elasticsearch.watcher.license.WatcherLicensee;
import org.elasticsearch.watcher.support.WatcherDateTimeUtils;
import org.elasticsearch.watcher.support.clock.Clock;
import org.elasticsearch.watcher.transform.ExecutableTransform;
@ -137,7 +137,7 @@ public class ActionWrapper implements ToXContent {
static ActionWrapper parse(String watchId, String actionId, XContentParser parser,
ActionRegistry actionRegistry, TransformRegistry transformRegistry,
Clock clock, LicenseService licenseService) throws IOException {
Clock clock, WatcherLicensee watcherLicensee) throws IOException {
assert parser.currentToken() == XContentParser.Token.START_OBJECT;
@ -173,7 +173,7 @@ public class ActionWrapper implements ToXContent {
throw new ElasticsearchParseException("could not parse watch action [{}/{}]. missing action type", watchId, actionId);
}
ActionThrottler throttler = new ActionThrottler(clock, throttlePeriod, licenseService);
ActionThrottler throttler = new ActionThrottler(clock, throttlePeriod, watcherLicensee);
return new ActionWrapper(actionId, throttler, transform, action);
}

View File

@ -5,10 +5,7 @@
*/
package org.elasticsearch.watcher.actions.throttler;
import org.elasticsearch.watcher.actions.throttler.AckThrottler;
import org.elasticsearch.watcher.actions.throttler.PeriodThrottler;
import org.elasticsearch.watcher.actions.throttler.Throttler;
import org.elasticsearch.watcher.license.LicenseService;
import org.elasticsearch.watcher.license.WatcherLicensee;
import org.elasticsearch.watcher.execution.WatchExecutionContext;
import org.elasticsearch.watcher.support.clock.Clock;
import org.elasticsearch.common.Nullable;
@ -21,18 +18,18 @@ public class ActionThrottler implements Throttler {
private static final AckThrottler ACK_THROTTLER = new AckThrottler();
private final LicenseService licenseService;
private final WatcherLicensee watcherLicensee;
private final PeriodThrottler periodThrottler;
private final AckThrottler ackThrottler;
public ActionThrottler(Clock clock, @Nullable TimeValue throttlePeriod, LicenseService licenseService) {
this(new PeriodThrottler(clock, throttlePeriod), ACK_THROTTLER, licenseService);
public ActionThrottler(Clock clock, @Nullable TimeValue throttlePeriod, WatcherLicensee watcherLicensee) {
this(new PeriodThrottler(clock, throttlePeriod), ACK_THROTTLER, watcherLicensee);
}
ActionThrottler(PeriodThrottler periodThrottler, AckThrottler ackThrottler, LicenseService licenseService) {
ActionThrottler(PeriodThrottler periodThrottler, AckThrottler ackThrottler, WatcherLicensee watcherLicensee) {
this.periodThrottler = periodThrottler;
this.ackThrottler = ackThrottler;
this.licenseService = licenseService;
this.watcherLicensee = watcherLicensee;
}
public TimeValue throttlePeriod() {
@ -41,8 +38,8 @@ public class ActionThrottler implements Throttler {
@Override
public Result throttle(String actionId, WatchExecutionContext ctx) {
if (!licenseService.enabled()) {
return Result.throttle("watcher license expired");
if (!watcherLicensee.isExecutingActionsAllowed()) {
return Result.throttle("watcher license does not allow action execution");
}
if (periodThrottler != null) {
Result throttleResult = periodThrottler.throttle(actionId, ctx);

View File

@ -18,6 +18,7 @@ import org.elasticsearch.watcher.condition.Condition;
import org.elasticsearch.watcher.history.HistoryStore;
import org.elasticsearch.watcher.history.WatchRecord;
import org.elasticsearch.watcher.input.Input;
import org.elasticsearch.watcher.license.WatcherLicensee;
import org.elasticsearch.watcher.support.clock.Clock;
import org.elasticsearch.watcher.support.validation.WatcherSettingsValidation;
import org.elasticsearch.watcher.transform.Transform;
@ -353,7 +354,6 @@ public class ExecutionService extends AbstractComponent {
}
if (conditionResult.met()) {
if (watch.actions().count() > 0 && watch.transform() != null) {
ctx.beforeWatchTransform();
Transform.Result transformResult = watch.transform().execute(ctx, ctx.payload());

View File

@ -18,7 +18,7 @@ public class LicenseModule extends AbstractModule {
@Override
protected void configure() {
bind(LicenseService.class).asEagerSingleton();
bind(WatcherLicensee.class).asEagerSingleton();
}
private void verifyLicensePlugin() {

View File

@ -1,86 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.watcher.license;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.component.AbstractLifecycleComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.core.LicenseState;
import org.elasticsearch.license.plugin.core.Licensee;
import org.elasticsearch.license.plugin.core.LicenseeRegistry;
import org.elasticsearch.watcher.WatcherPlugin;
/**
*
*/
public class LicenseService extends AbstractLifecycleComponent<LicenseService> implements Licensee {
public static final String FEATURE_NAME = WatcherPlugin.NAME;
private final LicenseeRegistry clientService;
private volatile LicenseState state;
@Inject
public LicenseService(Settings settings, LicenseeRegistry clientService) {
super(settings);
this.clientService = clientService;
}
@Override
public String id() {
return FEATURE_NAME;
}
@Override
public String[] expirationMessages() {
// TODO add messages to be logged around license expiry
return new String[0];
}
@Override
public String[] acknowledgmentMessages(License currentLicense, License newLicense) {
switch (newLicense.operationMode()) {
case BASIC:
if (currentLicense != null) {
switch (currentLicense.operationMode()) {
case TRIAL:
case GOLD:
case PLATINUM:
return new String[] { "Watcher will be disabled" };
}
}
break;
}
return Strings.EMPTY_ARRAY;
}
@Override
public void onChange(License license, LicenseState state) {
synchronized (this) {
this.state = state;
}
}
@Override
protected void doStart() throws ElasticsearchException {
clientService.register(this);
}
@Override
protected void doStop() throws ElasticsearchException {
}
@Override
protected void doClose() throws ElasticsearchException {
}
public boolean enabled() {
return state != LicenseState.DISABLED;
}
}

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.watcher.license;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.core.AbstractLicenseeComponent;
import org.elasticsearch.license.plugin.core.LicenseState;
import org.elasticsearch.license.plugin.core.LicenseeRegistry;
import org.elasticsearch.watcher.WatcherPlugin;
import static org.elasticsearch.license.core.License.OperationMode.*;
public class WatcherLicensee extends AbstractLicenseeComponent<WatcherLicensee> {
public static final String ID = WatcherPlugin.NAME;
@Inject
public WatcherLicensee(Settings settings, LicenseeRegistry clientService) {
super(settings, ID, clientService);
}
@Override
public String[] expirationMessages() {
return new String[] {
"PUT / GET watch APIs are disabled, DELETE watch API continues to work",
"Watches execute and write to the history",
"The actions of the watches don't execute"
};
}
@Override
public String[] acknowledgmentMessages(License currentLicense, License newLicense) {
switch (newLicense.operationMode()) {
case BASIC:
if (currentLicense != null) {
switch (currentLicense.operationMode()) {
case TRIAL:
case GOLD:
case PLATINUM:
return new String[] { "Watcher will be disabled" };
}
}
break;
}
return Strings.EMPTY_ARRAY;
}
public boolean isExecutingActionsAllowed() {
return isPutWatchAllowed();
}
public boolean isGetWatchAllowed() {
return isPutWatchAllowed();
}
public boolean isPutWatchAllowed() {
boolean isLicenseActive = getLicense().status() == License.Status.ACTIVE;
return isLicenseActive && isWatcherTransportActionAllowed();
}
public boolean isWatcherTransportActionAllowed() {
Status localStatus = status;
boolean isLicenseStateActive = localStatus.getLicenseState() != LicenseState.DISABLED;
License.OperationMode operationMode = localStatus.getMode();
return isLicenseStateActive && (operationMode == TRIAL || operationMode == GOLD || operationMode == PLATINUM);
}
}

View File

@ -16,7 +16,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.plugin.core.LicenseUtils;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.watcher.license.LicenseService;
import org.elasticsearch.watcher.license.WatcherLicensee;
import java.util.function.Supplier;
@ -25,21 +25,21 @@ import java.util.function.Supplier;
*/
public abstract class WatcherTransportAction<Request extends MasterNodeRequest<Request>, Response extends ActionResponse> extends TransportMasterNodeAction<Request, Response> {
private final LicenseService licenseService;
protected final WatcherLicensee watcherLicensee;
public WatcherTransportAction(Settings settings, String actionName, TransportService transportService,
ClusterService clusterService, ThreadPool threadPool, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver, LicenseService licenseService, Supplier<Request> request) {
IndexNameExpressionResolver indexNameExpressionResolver, WatcherLicensee watcherLicensee, Supplier<Request> request) {
super(settings, actionName, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, request);
this.licenseService = licenseService;
this.watcherLicensee = watcherLicensee;
}
@Override
protected void doExecute(Request request, ActionListener<Response> listener) {
if (licenseService.enabled()) {
if (watcherLicensee.isWatcherTransportActionAllowed()) {
super.doExecute(request, listener);
} else {
listener.onFailure(LicenseUtils.newExpirationException(LicenseService.FEATURE_NAME));
listener.onFailure(LicenseUtils.newComplianceException(WatcherLicensee.ID));
}
}
}

View File

@ -18,7 +18,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.watcher.WatcherService;
import org.elasticsearch.watcher.license.LicenseService;
import org.elasticsearch.watcher.license.WatcherLicensee;
import org.elasticsearch.watcher.transport.actions.WatcherTransportAction;
import org.elasticsearch.watcher.watch.WatchStatus;
import org.elasticsearch.watcher.watch.WatchStore;
@ -33,8 +33,8 @@ public class TransportAckWatchAction extends WatcherTransportAction<AckWatchRequ
@Inject
public TransportAckWatchAction(Settings settings, TransportService transportService, ClusterService clusterService,
ThreadPool threadPool, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
WatcherService watcherService, LicenseService licenseService) {
super(settings, AckWatchAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, licenseService, AckWatchRequest::new);
WatcherService watcherService, WatcherLicensee watcherLicensee) {
super(settings, AckWatchAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, watcherLicensee, AckWatchRequest::new);
this.watcherService = watcherService;
}

View File

@ -18,7 +18,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.watcher.WatcherService;
import org.elasticsearch.watcher.license.LicenseService;
import org.elasticsearch.watcher.license.WatcherLicensee;
import org.elasticsearch.watcher.transport.actions.WatcherTransportAction;
import org.elasticsearch.watcher.watch.WatchStatus;
import org.elasticsearch.watcher.watch.WatchStore;
@ -33,8 +33,8 @@ public class TransportActivateWatchAction extends WatcherTransportAction<Activat
@Inject
public TransportActivateWatchAction(Settings settings, TransportService transportService, ClusterService clusterService,
ThreadPool threadPool, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
WatcherService watcherService, LicenseService licenseService) {
super(settings, ActivateWatchAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, licenseService, ActivateWatchRequest::new);
WatcherService watcherService, WatcherLicensee watcherLicensee) {
super(settings, ActivateWatchAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, watcherLicensee, ActivateWatchRequest::new);
this.watcherService = watcherService;
}

View File

@ -19,7 +19,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.watcher.WatcherService;
import org.elasticsearch.watcher.license.LicenseService;
import org.elasticsearch.watcher.license.WatcherLicensee;
import org.elasticsearch.watcher.transport.actions.WatcherTransportAction;
import org.elasticsearch.watcher.watch.WatchStore;
@ -33,8 +33,8 @@ public class TransportDeleteWatchAction extends WatcherTransportAction<DeleteWat
@Inject
public TransportDeleteWatchAction(Settings settings, TransportService transportService, ClusterService clusterService,
ThreadPool threadPool, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
WatcherService watcherService, LicenseService licenseService) {
super(settings, DeleteWatchAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, licenseService, DeleteWatchRequest::new);
WatcherService watcherService, WatcherLicensee watcherLicensee) {
super(settings, DeleteWatchAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, watcherLicensee, DeleteWatchRequest::new);
this.watcherService = watcherService;
}

View File

@ -26,7 +26,7 @@ import org.elasticsearch.watcher.execution.ExecutionService;
import org.elasticsearch.watcher.execution.ManualExecutionContext;
import org.elasticsearch.watcher.history.WatchRecord;
import org.elasticsearch.watcher.input.simple.SimpleInput;
import org.elasticsearch.watcher.license.LicenseService;
import org.elasticsearch.watcher.license.WatcherLicensee;
import org.elasticsearch.watcher.support.clock.Clock;
import org.elasticsearch.watcher.support.xcontent.WatcherParams;
import org.elasticsearch.watcher.transport.actions.WatcherTransportAction;
@ -57,9 +57,9 @@ public class TransportExecuteWatchAction extends WatcherTransportAction<ExecuteW
@Inject
public TransportExecuteWatchAction(Settings settings, TransportService transportService, ClusterService clusterService,
ThreadPool threadPool, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, ExecutionService executionService,
Clock clock, LicenseService licenseService, WatchStore watchStore, TriggerService triggerService,
Clock clock, WatcherLicensee watcherLicensee, WatchStore watchStore, TriggerService triggerService,
Watch.Parser watchParser) {
super(settings, ExecuteWatchAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, licenseService, ExecuteWatchRequest::new);
super(settings, ExecuteWatchAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, watcherLicensee, ExecuteWatchRequest::new);
this.executionService = executionService;
this.watchStore = watchStore;
this.clock = clock;

View File

@ -18,10 +18,11 @@ import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.license.plugin.core.LicenseUtils;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.watcher.WatcherService;
import org.elasticsearch.watcher.license.LicenseService;
import org.elasticsearch.watcher.license.WatcherLicensee;
import org.elasticsearch.watcher.support.xcontent.WatcherParams;
import org.elasticsearch.watcher.transport.actions.WatcherTransportAction;
import org.elasticsearch.watcher.watch.Watch;
@ -41,8 +42,8 @@ public class TransportGetWatchAction extends WatcherTransportAction<GetWatchRequ
@Inject
public TransportGetWatchAction(Settings settings, TransportService transportService, ClusterService clusterService,
ThreadPool threadPool, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
WatcherService watcherService, LicenseService licenseService) {
super(settings, GetWatchAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, licenseService, GetWatchRequest::new);
WatcherService watcherService, WatcherLicensee watcherLicensee) {
super(settings, GetWatchAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, watcherLicensee, GetWatchRequest::new);
this.watcherService = watcherService;
}
@ -58,6 +59,11 @@ public class TransportGetWatchAction extends WatcherTransportAction<GetWatchRequ
@Override
protected void masterOperation(GetWatchRequest request, ClusterState state, ActionListener<GetWatchResponse> listener) throws ElasticsearchException {
if (!watcherLicensee.isGetWatchAllowed()) {
listener.onFailure(LicenseUtils.newComplianceException(WatcherLicensee.ID));
return;
}
try {
Watch watch = watcherService.getWatch(request.getId());
if (watch == null) {

View File

@ -16,10 +16,11 @@ import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.plugin.core.LicenseUtils;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.watcher.WatcherService;
import org.elasticsearch.watcher.license.LicenseService;
import org.elasticsearch.watcher.license.WatcherLicensee;
import org.elasticsearch.watcher.transport.actions.WatcherTransportAction;
import org.elasticsearch.watcher.watch.WatchStore;
@ -32,8 +33,8 @@ public class TransportPutWatchAction extends WatcherTransportAction<PutWatchRequ
@Inject
public TransportPutWatchAction(Settings settings, TransportService transportService, ClusterService clusterService,
ThreadPool threadPool, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
WatcherService watcherService, LicenseService licenseService) {
super(settings, PutWatchAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, licenseService, PutWatchRequest::new);
WatcherService watcherService, WatcherLicensee watcherLicensee) {
super(settings, PutWatchAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, watcherLicensee, PutWatchRequest::new);
this.watcherService = watcherService;
}
@ -49,6 +50,11 @@ public class TransportPutWatchAction extends WatcherTransportAction<PutWatchRequ
@Override
protected void masterOperation(PutWatchRequest request, ClusterState state, ActionListener<PutWatchResponse> listener) throws ElasticsearchException {
if (!watcherLicensee.isPutWatchAllowed()) {
listener.onFailure(LicenseUtils.newComplianceException(WatcherLicensee.ID));
return;
}
try {
IndexResponse indexResponse = watcherService.putWatch(request.getId(), request.getSource(), request.masterNodeTimeout(), request.isActive());
listener.onResponse(new PutWatchResponse(indexResponse.getId(), indexResponse.getVersion(), indexResponse.isCreated()));

View File

@ -18,7 +18,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.watcher.WatcherLifeCycleService;
import org.elasticsearch.watcher.license.LicenseService;
import org.elasticsearch.watcher.license.WatcherLicensee;
import org.elasticsearch.watcher.transport.actions.WatcherTransportAction;
/**
@ -30,8 +30,8 @@ public class TransportWatcherServiceAction extends WatcherTransportAction<Watche
@Inject
public TransportWatcherServiceAction(Settings settings, TransportService transportService, ClusterService clusterService,
ThreadPool threadPool, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
WatcherLifeCycleService lifeCycleService, LicenseService licenseService) {
super(settings, WatcherServiceAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, licenseService, WatcherServiceRequest::new);
WatcherLifeCycleService lifeCycleService, WatcherLicensee watcherLicensee) {
super(settings, WatcherServiceAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, watcherLicensee, WatcherServiceRequest::new);
this.lifeCycleService = lifeCycleService;
}

View File

@ -21,7 +21,7 @@ import org.elasticsearch.watcher.WatcherBuild;
import org.elasticsearch.watcher.WatcherLifeCycleService;
import org.elasticsearch.watcher.WatcherService;
import org.elasticsearch.watcher.execution.ExecutionService;
import org.elasticsearch.watcher.license.LicenseService;
import org.elasticsearch.watcher.license.WatcherLicensee;
import org.elasticsearch.watcher.transport.actions.WatcherTransportAction;
/**
@ -36,8 +36,8 @@ public class TransportWatcherStatsAction extends WatcherTransportAction<WatcherS
@Inject
public TransportWatcherStatsAction(Settings settings, TransportService transportService, ClusterService clusterService,
ThreadPool threadPool, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, WatcherService watcherService,
ExecutionService executionService, LicenseService licenseService, WatcherLifeCycleService lifeCycleService) {
super(settings, WatcherStatsAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, licenseService, WatcherStatsRequest::new);
ExecutionService executionService, WatcherLicensee watcherLicensee, WatcherLifeCycleService lifeCycleService) {
super(settings, WatcherStatsAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, watcherLicensee, WatcherStatsRequest::new);
this.watcherService = watcherService;
this.executionService = executionService;
this.lifeCycleService = lifeCycleService;

View File

@ -349,7 +349,6 @@ public class ActionThrottleTests extends AbstractWatcherIntegrationTestCase {
assertThat(watchRecord.state(), equalTo(ExecutionState.THROTTLED));
}
private String getExecutionStatus(Map<String, Object> watchRecordMap) {
return ObjectPath.eval("result.actions.0.status", watchRecordMap);
}

View File

@ -7,7 +7,7 @@ package org.elasticsearch.watcher.actions.throttler;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.watcher.execution.WatchExecutionContext;
import org.elasticsearch.watcher.license.LicenseService;
import org.elasticsearch.watcher.license.WatcherLicensee;
import org.junit.Test;
import static org.hamcrest.Matchers.*;
@ -27,9 +27,9 @@ public class WatchThrottlerTests extends ESTestCase {
when(periodThrottler.throttle("_action", ctx)).thenReturn(Throttler.Result.NO);
Throttler.Result expectedResult = Throttler.Result.throttle("_reason");
when(ackThrottler.throttle("_action", ctx)).thenReturn(expectedResult);
LicenseService licenseService = mock(LicenseService.class);
when(licenseService.enabled()).thenReturn(true);
ActionThrottler throttler = new ActionThrottler(periodThrottler, ackThrottler, licenseService);
WatcherLicensee watcherLicensee = mock(WatcherLicensee.class);
when(watcherLicensee.isExecutingActionsAllowed()).thenReturn(true);
ActionThrottler throttler = new ActionThrottler(periodThrottler, ackThrottler, watcherLicensee);
Throttler.Result result = throttler.throttle("_action", ctx);
assertThat(result, notNullValue());
assertThat(result, is(expectedResult));
@ -43,9 +43,9 @@ public class WatchThrottlerTests extends ESTestCase {
Throttler.Result expectedResult = Throttler.Result.throttle("_reason");
when(periodThrottler.throttle("_action", ctx)).thenReturn(expectedResult);
when(ackThrottler.throttle("_action", ctx)).thenReturn(Throttler.Result.NO);
LicenseService licenseService = mock(LicenseService.class);
when(licenseService.enabled()).thenReturn(true);
ActionThrottler throttler = new ActionThrottler(periodThrottler, ackThrottler, licenseService);
WatcherLicensee watcherLicensee = mock(WatcherLicensee.class);
when(watcherLicensee.isExecutingActionsAllowed()).thenReturn(true);
ActionThrottler throttler = new ActionThrottler(periodThrottler, ackThrottler, watcherLicensee);
Throttler.Result result = throttler.throttle("_action", ctx);
assertThat(result, notNullValue());
assertThat(result, is(expectedResult));
@ -60,9 +60,9 @@ public class WatchThrottlerTests extends ESTestCase {
when(periodThrottler.throttle("_action", ctx)).thenReturn(periodResult);
Throttler.Result ackResult = Throttler.Result.throttle("_reason_ack");
when(ackThrottler.throttle("_action", ctx)).thenReturn(ackResult);
LicenseService licenseService = mock(LicenseService.class);
when(licenseService.enabled()).thenReturn(true);
ActionThrottler throttler = new ActionThrottler(periodThrottler, ackThrottler, licenseService);
WatcherLicensee watcherLicensee = mock(WatcherLicensee.class);
when(watcherLicensee.isExecutingActionsAllowed()).thenReturn(true);
ActionThrottler throttler = new ActionThrottler(periodThrottler, ackThrottler, watcherLicensee);
Throttler.Result result = throttler.throttle("_action", ctx);
assertThat(result, notNullValue());
// we always check the period first... so the result will come for the period throttler
@ -76,9 +76,9 @@ public class WatchThrottlerTests extends ESTestCase {
WatchExecutionContext ctx = mock(WatchExecutionContext.class);
when(periodThrottler.throttle("_action", ctx)).thenReturn(Throttler.Result.NO);
when(ackThrottler.throttle("_action", ctx)).thenReturn(Throttler.Result.NO);
LicenseService licenseService = mock(LicenseService.class);
when(licenseService.enabled()).thenReturn(true);
ActionThrottler throttler = new ActionThrottler(periodThrottler, ackThrottler, licenseService);
WatcherLicensee watcherLicensee = mock(WatcherLicensee.class);
when(watcherLicensee.isExecutingActionsAllowed()).thenReturn(true);
ActionThrottler throttler = new ActionThrottler(periodThrottler, ackThrottler, watcherLicensee);
Throttler.Result result = throttler.throttle("_action", ctx);
assertThat(result, notNullValue());
assertThat(result, is(Throttler.Result.NO));
@ -90,11 +90,25 @@ public class WatchThrottlerTests extends ESTestCase {
WatchExecutionContext ctx = mock(WatchExecutionContext.class);
Throttler.Result ackResult = mock(Throttler.Result.class);
when(ackThrottler.throttle("_action", ctx)).thenReturn(ackResult);
LicenseService licenseService = mock(LicenseService.class);
when(licenseService.enabled()).thenReturn(true);
ActionThrottler throttler = new ActionThrottler(null, ackThrottler, licenseService);
WatcherLicensee watcherLicensee = mock(WatcherLicensee.class);
when(watcherLicensee.isExecutingActionsAllowed()).thenReturn(true);
ActionThrottler throttler = new ActionThrottler(null, ackThrottler, watcherLicensee);
Throttler.Result result = throttler.throttle("_action", ctx);
assertThat(result, notNullValue());
assertThat(result, sameInstance(ackResult));
}
@Test
public void testThatRestrictedLicenseReturnsCorrectResult() throws Exception {
AckThrottler ackThrottler = mock(AckThrottler.class);
WatchExecutionContext ctx = mock(WatchExecutionContext.class);
Throttler.Result ackResult = mock(Throttler.Result.class);
when(ackThrottler.throttle("_action", ctx)).thenReturn(ackResult);
WatcherLicensee watcherLicensee = mock(WatcherLicensee.class);
when(watcherLicensee.isExecutingActionsAllowed()).thenReturn(false);
ActionThrottler throttler = new ActionThrottler(null, ackThrottler, watcherLicensee);
Throttler.Result result = throttler.throttle("_action", ctx);
assertThat(result, notNullValue());
assertThat(result.reason(), is("watcher license does not allow action execution"));
}
}

View File

@ -8,11 +8,7 @@ package org.elasticsearch.watcher.execution;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.watcher.actions.Action;
import org.elasticsearch.watcher.actions.ActionStatus;
import org.elasticsearch.watcher.actions.ActionWrapper;
import org.elasticsearch.watcher.actions.ExecutableAction;
import org.elasticsearch.watcher.actions.ExecutableActions;
import org.elasticsearch.watcher.actions.*;
import org.elasticsearch.watcher.actions.throttler.ActionThrottler;
import org.elasticsearch.watcher.actions.throttler.Throttler;
import org.elasticsearch.watcher.condition.Condition;
@ -29,11 +25,7 @@ import org.elasticsearch.watcher.support.validation.WatcherSettingsValidation;
import org.elasticsearch.watcher.transform.ExecutableTransform;
import org.elasticsearch.watcher.transform.Transform;
import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent;
import org.elasticsearch.watcher.watch.Payload;
import org.elasticsearch.watcher.watch.Watch;
import org.elasticsearch.watcher.watch.WatchLockService;
import org.elasticsearch.watcher.watch.WatchStatus;
import org.elasticsearch.watcher.watch.WatchStore;
import org.elasticsearch.watcher.watch.*;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.junit.Before;
@ -45,17 +37,9 @@ import java.util.concurrent.ArrayBlockingQueue;
import static java.util.Collections.singletonMap;
import static org.elasticsearch.common.unit.TimeValue.timeValueSeconds;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.hamcrest.Matchers.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.*;
/**
*/
@ -601,5 +585,4 @@ public class ExecutionServiceTests extends ESTestCase {
verify(actionTransform, never()).execute(context, payload);
verify(action, never()).execute("_action", context, payload);
}
}

View File

@ -1,339 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.watcher.license;
import com.carrotsearch.randomizedtesting.RandomizedTest;
import com.carrotsearch.randomizedtesting.SysGlobals;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.core.LicenseState;
import org.elasticsearch.license.plugin.core.Licensee;
import org.elasticsearch.license.plugin.core.LicenseeRegistry;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.watcher.actions.ActionStatus;
import org.elasticsearch.watcher.history.HistoryStore;
import org.elasticsearch.watcher.test.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.watcher.transport.actions.get.GetWatchResponse;
import org.elasticsearch.watcher.transport.actions.put.PutWatchResponse;
import org.elasticsearch.watcher.transport.actions.service.WatcherServiceResponse;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.elasticsearch.watcher.actions.ActionBuilders.indexAction;
import static org.elasticsearch.watcher.client.WatchSourceBuilders.watchBuilder;
import static org.elasticsearch.watcher.condition.ConditionBuilders.alwaysCondition;
import static org.elasticsearch.watcher.input.InputBuilders.simpleInput;
import static org.elasticsearch.watcher.trigger.TriggerBuilders.schedule;
import static org.elasticsearch.watcher.trigger.schedule.Schedules.interval;
import static org.hamcrest.Matchers.*;
/**
*
*/
public class LicenseIntegrationTests extends AbstractWatcherIntegrationTestCase {
static final License DUMMY_LICENSE = License.builder()
.expiryDate(System.currentTimeMillis())
.issueDate(System.currentTimeMillis())
.issuedTo("LicensingTests")
.issuer("test")
.maxNodes(Integer.MAX_VALUE)
.signature("_signature")
.type("basic")
.uid(String.valueOf(RandomizedTest.systemPropertyAsInt(SysGlobals.CHILDVM_SYSPROP_JVM_ID, 0)) + System.identityHashCode(LicenseIntegrationTests.class))
.build();
@Override
protected Class<? extends Plugin> licensePluginClass() {
return MockLicensePlugin.class;
}
@Override
protected boolean timeWarped() {
return true;
}
@Override
protected boolean checkWatcherRunningOnlyOnce() {
return false;
}
@Test
public void testEnableDisableBehaviour() throws Exception {
// put watch API should work
final String watchName = randomAsciiOfLength(10);
PutWatchResponse putWatchResponse = watcherClient().preparePutWatch(watchName).setSource(watchBuilder()
.trigger(schedule(interval("1s")))
.input(simpleInput())
.condition(alwaysCondition())
.addAction("_index", indexAction("idx", "type")))
.execute().actionGet();
assertThat(putWatchResponse.isCreated(), is(true));
timeWarp().scheduler().trigger(watchName);
// waiting for the watch to be executed at least once... so we can ack it
assertWatchWithMinimumPerformedActionsCount(watchName, 1, false);
// ack watch API should work
assertThat(watcherClient().prepareAckWatch(watchName).get().getStatus().actionStatus("_index").ackStatus().state(), is(ActionStatus.AckStatus.State.ACKED));
// get watch API should work
assertThat(watcherClient().prepareGetWatch(watchName).get().getId(), is(watchName));
// delete watch API should work
assertThat(watcherClient().prepareDeleteWatch(watchName).get().isFound(), is(true));
// watcher stats API should work
assertThat(watcherClient().prepareWatcherStats().get().getWatchesCount(), is(0L));
// watcher service API should work
WatcherServiceResponse serviceResponse = watcherClient().prepareWatchService().restart().get();
assertThat(serviceResponse.isAcknowledged(), is(true));
ensureWatcherStarted();
// lets put back the watch and so we can test it when the license is disabled
putWatchResponse = watcherClient().preparePutWatch(watchName).setSource(watchBuilder()
.trigger(schedule(interval("10s")))
.input(simpleInput())
.condition(alwaysCondition())
.addAction("_index", indexAction("idx", "type")))
.execute().actionGet();
assertThat(putWatchResponse.isCreated(), is(true));
flush();
final long docCountBeforeDisable = docCount("idx", "type", matchAllQuery());
assertThat(docCountBeforeDisable, is(1L));
final long recordCountBeforeDisable = historyRecordsCount(watchName);
assertThat(recordCountBeforeDisable, is(1L));
final long executedBeforeDisable = findNumberOfPerformedActions(watchName);
assertThat(executedBeforeDisable, is(1L));
disableLicensing();
//=====
// first lets verify that when the license is disabled and the watch is triggered, it is executed,
// the history record is written for it, but it's throttled and its actions are not executed
//=====
// trigger the watch.. should execute the watch but not its action
// we need to move the clock so the watch_record id will be unique
timeWarp().clock().fastForwardSeconds(10);
timeWarp().scheduler().trigger(watchName);
// lets wait until we have another history record
assertBusy(new Runnable() {
@Override
public void run() {
assertThat(historyRecordsCount(watchName), greaterThan(recordCountBeforeDisable));
}
});
// ensure that the number of executed records stayed the same
assertThat(findNumberOfPerformedActions(watchName), equalTo(executedBeforeDisable));
// while the execution count grows, the number of documents indexed by the action stays the same
// as with the license disabled, the actions are not executed
assertThat(docCount("idx", "type", matchAllQuery()), is(docCountBeforeDisable));
// and last... lets verify that we have throttled watches due to license expiration
long throttledCount = docCount(HistoryStore.INDEX_PREFIX + "*", HistoryStore.DOC_TYPE, boolQuery()
.must(matchQuery("result.actions.reason", "watcher license expired"))
.must(termQuery("result.actions.status", "throttled")));
assertThat(throttledCount, is(1L));
//=====
// now... lets verify that all the watcher APIs are blocked when the license is disabled
//=====
try {
watcherClient().preparePutWatch(watchName).setSource(watchBuilder()
.trigger(schedule(interval("1s")))
.input(simpleInput())
.condition(alwaysCondition())
.addAction("_index", indexAction("idx", "type")))
.execute().actionGet();
fail("put watch API should NOT work when license is disabled");
} catch (ElasticsearchSecurityException ee) {
assertThat(ee.getHeader("es.license.expired.feature"), hasItem(LicenseService.FEATURE_NAME));
assertThat(ee.status(), is(RestStatus.UNAUTHORIZED));
}
try {
watcherClient().prepareAckWatch(watchName).get();
fail("ack watch API should NOT work when license is disabled");
} catch (ElasticsearchSecurityException ee) {
assertThat(ee.getHeader("es.license.expired.feature"), hasItem(LicenseService.FEATURE_NAME));
assertThat(ee.status(), is(RestStatus.UNAUTHORIZED));
}
try {
watcherClient().prepareGetWatch(watchName).get();
fail("get watch API should NOT work when license is disabled");
} catch (ElasticsearchSecurityException ee) {
assertThat(ee.getHeader("es.license.expired.feature"), hasItem(LicenseService.FEATURE_NAME));
assertThat(ee.status(), is(RestStatus.UNAUTHORIZED));
}
try {
watcherClient().prepareDeleteWatch(watchName).get();
fail("delete watch API should NOT work when license is disabled");
} catch (ElasticsearchSecurityException ee) {
assertThat(ee.getHeader("es.license.expired.feature"), hasItem(LicenseService.FEATURE_NAME));
assertThat(ee.status(), is(RestStatus.UNAUTHORIZED));
}
// watcher stats should not work
try {
watcherClient().prepareWatcherStats().get();
fail("watcher stats API should NOT work when license is disabled");
} catch (ElasticsearchSecurityException ee) {
assertThat(ee.getHeader("es.license.expired.feature"), hasItem(LicenseService.FEATURE_NAME));
assertThat(ee.status(), is(RestStatus.UNAUTHORIZED));
}
try {
watcherClient().prepareWatchService().restart().get();
fail("watcher service API should NOT work when license is disabled");
} catch (ElasticsearchSecurityException ee) {
assertThat(ee.getHeader("es.license.expired.feature"), hasItem(LicenseService.FEATURE_NAME));
assertThat(ee.status(), is(RestStatus.UNAUTHORIZED));
}
enableLicensing();
// put watch API should work
putWatchResponse = watcherClient().preparePutWatch(watchName).setSource(watchBuilder()
.trigger(schedule(interval("1s")))
.input(simpleInput())
.condition(alwaysCondition())
.addAction("_index", indexAction("idx", "type")))
.execute().actionGet();
assertThat(putWatchResponse, notNullValue());
// we need to move the clock so the watch_record id will be unique
timeWarp().clock().fastForwardSeconds(10);
timeWarp().scheduler().trigger(watchName);
// waiting for the watch to be executed at least once... so we can ack it
assertWatchWithMinimumPerformedActionsCount(watchName, 1, false);
assertBusy(new Runnable() {
@Override
public void run() {
GetWatchResponse response = watcherClient().prepareGetWatch(watchName).get();
assertThat(response.getStatus().actionStatus("_index").ackStatus().state(), equalTo(ActionStatus.AckStatus.State.ACKABLE));
}
});
// ack watch API should work
assertThat(watcherClient().prepareAckWatch(watchName).get().getStatus().actionStatus("_index").ackStatus().state(), is(ActionStatus.AckStatus.State.ACKED));
// get watch API should work
assertThat(watcherClient().prepareGetWatch(watchName).get().getId(), is(watchName));
// delete watch API should work
assertThat(watcherClient().prepareDeleteWatch(watchName).get().isFound(), is(true));
// watcher stats API should work
assertThat(watcherClient().prepareWatcherStats().get().getWatchesCount(), is(0L));
// watcher service API should work
assertThat(watcherClient().prepareWatchService().stop().get().isAcknowledged(), is(true));
}
public static void disableLicensing() {
for (MockLicenseService service : internalCluster().getInstances(MockLicenseService.class)) {
service.disable();
}
}
public static void enableLicensing() {
for (MockLicenseService service : internalCluster().getInstances(MockLicenseService.class)) {
service.enable();
}
}
public static class MockLicensePlugin extends Plugin {
public static final String NAME = "internal-test-licensing";
@Override
public String name() {
return NAME;
}
@Override
public String description() {
return name();
}
@Override
public Collection<Module> nodeModules() {
return Collections.<Module>singletonList(new InternalLicenseModule());
}
}
public static class InternalLicenseModule extends AbstractModule {
@Override
protected void configure() {
bind(MockLicenseService.class).asEagerSingleton();
bind(LicenseeRegistry.class).to(MockLicenseService.class);
}
}
public static class MockLicenseService extends AbstractComponent implements LicenseeRegistry {
private final List<Licensee> licensees = new ArrayList<>();
@Inject
public MockLicenseService(Settings settings) {
super(settings);
enable();
}
@Override
public void register(Licensee licensee) {
licensees.add(licensee);
enable();
}
public void enable() {
// enabled all listeners (incl. shield)
for (Licensee licensee : licensees) {
licensee.onChange(DUMMY_LICENSE, LicenseState.ENABLED);
}
}
public void disable() {
// only disable watcher listener (we need shield to work)
for (Licensee licensee : licensees) {
if (licensee instanceof LicenseService) {
licensee.onChange(DUMMY_LICENSE, LicenseState.DISABLED);
}
}
}
}
}

View File

@ -0,0 +1,211 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.watcher.license;
import com.carrotsearch.randomizedtesting.RandomizedTest;
import com.carrotsearch.randomizedtesting.SysGlobals;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.core.LicenseState;
import org.elasticsearch.license.plugin.core.Licensee;
import org.elasticsearch.license.plugin.core.LicenseeRegistry;
import org.elasticsearch.test.ESTestCase;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.Matchers.is;
public class LicenseTests extends ESTestCase {
private SimpleLicenseeRegistry licenseeRegistry = new SimpleLicenseeRegistry();
@Test
public void testPlatinumGoldTrialLicenseCanDoEverything() throws Exception {
License license = licenseBuilder()
.type(randomFrom("platinum", "gold", "trial"))
.build();
licenseeRegistry.setLicense(license);
WatcherLicensee watcherLicensee = new WatcherLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(watcherLicensee);
assertLicenseGoldPlatinumTrialBehaviour(watcherLicensee);
}
@Test
public void testBasicLicenseIsDisabled() throws Exception {
License license = licenseBuilder()
.type("basic")
.build();
licenseeRegistry.setLicense(license);
WatcherLicensee watcherLicensee = new WatcherLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(watcherLicensee);
assertLicenseBasicOrNoneBehaviour(watcherLicensee);
}
@Test
public void testNoLicenseDoesNotWork() {
License license = licenseBuilder()
.type("basic")
.build();
licenseeRegistry.setLicense(license);
WatcherLicensee watcherLicensee = new WatcherLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(watcherLicensee);
licenseeRegistry.disable();
assertLicenseBasicOrNoneBehaviour(watcherLicensee);
}
@Test
public void testExpiredPlatinumGoldTrialLicenseIsRestricted() throws Exception {
License license = expiredLicenseBuilder()
.type(randomFrom("platinum", "gold", "trial"))
.build();
licenseeRegistry.setLicense(license);
WatcherLicensee watcherLicensee = new WatcherLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(watcherLicensee);
assertLicenseExpiredBehaviour(watcherLicensee);
}
@Test
public void testUpgradingFromBasicLicenseWorks() {
License basicLicense = licenseBuilder()
.type("basic")
.build();
licenseeRegistry.setLicense(basicLicense);
WatcherLicensee watcherLicensee = new WatcherLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(watcherLicensee);
assertLicenseBasicOrNoneBehaviour(watcherLicensee);
License fancyLicense = licenseBuilder()
.type(randomFrom("platinum", "gold", "trial"))
.build();
licenseeRegistry.setLicense(fancyLicense);
assertLicenseGoldPlatinumTrialBehaviour(watcherLicensee);
}
@Test
public void testDowngradingToBasicLicenseWorks() {
License basicLicense = licenseBuilder()
.type(randomFrom("platinum", "gold", "trial"))
.build();
licenseeRegistry.setLicense(basicLicense);
WatcherLicensee watcherLicensee = new WatcherLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(watcherLicensee);
assertLicenseGoldPlatinumTrialBehaviour(watcherLicensee);
License fancyLicense = licenseBuilder()
.type("basic")
.build();
licenseeRegistry.setLicense(fancyLicense);
assertLicenseBasicOrNoneBehaviour(watcherLicensee);
}
@Test
public void testUpgradingExpiredLicenseWorks() {
License expiredLicense = expiredLicenseBuilder()
.type(randomFrom("platinum", "gold", "trial"))
.build();
licenseeRegistry.setLicense(expiredLicense);
WatcherLicensee watcherLicensee = new WatcherLicensee(Settings.EMPTY, licenseeRegistry);
licenseeRegistry.register(watcherLicensee);
assertLicenseExpiredBehaviour(watcherLicensee);
License fancyLicense = licenseBuilder()
.type(randomFrom("platinum", "gold", "trial"))
.build();
licenseeRegistry.setLicense(fancyLicense);
assertLicenseGoldPlatinumTrialBehaviour(watcherLicensee);
}
private void assertLicenseGoldPlatinumTrialBehaviour(WatcherLicensee watcherLicensee) {
assertThat("Expected putting a watch to be allowed", watcherLicensee.isPutWatchAllowed(), is(true));
assertThat("Expected getting a watch to be allowed", watcherLicensee.isGetWatchAllowed(), is(true));
assertThat("Expected watcher transport actions to be allowed", watcherLicensee.isWatcherTransportActionAllowed(), is(true));
assertThat("Expected actions of a watch to be executed", watcherLicensee.isExecutingActionsAllowed(), is(true));
}
private void assertLicenseBasicOrNoneBehaviour(WatcherLicensee watcherLicensee) {
assertThat("Expected putting a watch not to be allowed", watcherLicensee.isPutWatchAllowed(), is(false));
assertThat("Expected getting a watch not to be allowed", watcherLicensee.isGetWatchAllowed(), is(false));
assertThat("Expected watcher transport actions not to be allowed", watcherLicensee.isWatcherTransportActionAllowed(), is(false));
assertThat("Expected actions of a watch not to be executed", watcherLicensee.isExecutingActionsAllowed(), is(false));
}
private void assertLicenseExpiredBehaviour(WatcherLicensee watcherLicensee) {
assertThat("Expected putting a watch not to be allowed", watcherLicensee.isPutWatchAllowed(), is(false));
assertThat("Expected getting a watch not to be allowed", watcherLicensee.isGetWatchAllowed(), is(false));
assertThat("Expected actions of a watch not to be executed", watcherLicensee.isExecutingActionsAllowed(), is(false));
assertThat("Expected watcher transport actions to be allowed", watcherLicensee.isWatcherTransportActionAllowed(), is(true));
}
private License.Builder expiredLicenseBuilder() {
return licenseBuilder()
.issueDate(System.currentTimeMillis() - 86400)
.expiryDate(System.currentTimeMillis() - 1);
}
private License.Builder licenseBuilder() {
return License.builder()
.issueDate(System.currentTimeMillis())
.expiryDate(System.currentTimeMillis() + (86400 * 1000))
.issuedTo("LicensingTests")
.issuer("test")
.maxNodes(Integer.MAX_VALUE)
.signature("_signature")
.uid(String.valueOf(RandomizedTest.systemPropertyAsInt(SysGlobals.CHILDVM_SYSPROP_JVM_ID, 0)) + System.identityHashCode(LicenseTests.class));
}
public static class SimpleLicenseeRegistry extends AbstractComponent implements LicenseeRegistry {
private final List<Licensee> licensees = new ArrayList<>();
private License license;
public SimpleLicenseeRegistry() {
super(Settings.EMPTY);
}
@Override
public void register(Licensee licensee) {
licensees.add(licensee);
enable();
}
public void enable() {
for (Licensee licensee : licensees) {
licensee.onChange(license, randomBoolean() ? LicenseState.GRACE_PERIOD : LicenseState.ENABLED);
}
}
public void disable() {
for (Licensee licensee : licensees) {
licensee.onChange(license, LicenseState.DISABLED);
}
}
public void setLicense(License newLicense) {
license = newLicense;
enable();
}
}
}

View File

@ -9,12 +9,10 @@ import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.routing.IndexRoutingTable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.Callback;
@ -35,16 +33,12 @@ import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.TestCluster;
import org.elasticsearch.watcher.*;
import org.elasticsearch.watcher.actions.email.service.Authentication;
import org.elasticsearch.watcher.actions.email.service.Email;
import org.elasticsearch.watcher.actions.email.service.EmailService;
import org.elasticsearch.watcher.actions.email.service.Profile;
import org.elasticsearch.watcher.actions.email.service.*;
import org.elasticsearch.watcher.client.WatcherClient;
import org.elasticsearch.watcher.execution.ExecutionService;
import org.elasticsearch.watcher.execution.ExecutionState;
import org.elasticsearch.watcher.execution.TriggeredWatchStore;
import org.elasticsearch.watcher.history.HistoryStore;
import org.elasticsearch.watcher.license.LicenseService;
import org.elasticsearch.watcher.license.WatcherLicensee;
import org.elasticsearch.watcher.support.WatcherIndexTemplateRegistry;
import org.elasticsearch.watcher.support.clock.ClockMock;
import org.elasticsearch.watcher.support.http.HttpClient;
@ -54,7 +48,6 @@ import org.elasticsearch.watcher.trigger.ScheduleTriggerEngineMock;
import org.elasticsearch.watcher.trigger.TriggerService;
import org.elasticsearch.watcher.trigger.schedule.ScheduleModule;
import org.elasticsearch.watcher.watch.Watch;
import org.elasticsearch.watcher.watch.WatchStore;
import org.hamcrest.Matcher;
import org.jboss.netty.util.internal.SystemPropertyUtil;
import org.junit.After;
@ -318,8 +311,8 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
return new NoopEmailService();
}
protected LicenseService licenseService() {
return getInstanceFromMaster(LicenseService.class);
protected WatcherLicensee licenseService() {
return getInstanceFromMaster(WatcherLicensee.class);
}
protected IndexNameExpressionResolver indexNameExpressionResolver() {
@ -478,8 +471,8 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
assertBusy(new Runnable() {
@Override
public void run() {
for (LicenseService service : internalCluster().getInstances(LicenseService.class)) {
assertThat(service.enabled(), is(true));
for (WatcherLicensee service : internalCluster().getInstances(WatcherLicensee.class)) {
assertThat(service.isWatcherTransportActionAllowed(), is(true));
}
}
});

View File

@ -14,12 +14,7 @@ import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.*;
import org.elasticsearch.env.Environment;
import org.elasticsearch.script.ScriptContextRegistry;
import org.elasticsearch.script.ScriptEngineService;
@ -33,11 +28,7 @@ import org.elasticsearch.watcher.actions.ActionWrapper;
import org.elasticsearch.watcher.actions.ExecutableActions;
import org.elasticsearch.watcher.actions.email.EmailAction;
import org.elasticsearch.watcher.actions.email.ExecutableEmailAction;
import org.elasticsearch.watcher.actions.email.service.Authentication;
import org.elasticsearch.watcher.actions.email.service.EmailService;
import org.elasticsearch.watcher.actions.email.service.EmailTemplate;
import org.elasticsearch.watcher.actions.email.service.HtmlSanitizer;
import org.elasticsearch.watcher.actions.email.service.Profile;
import org.elasticsearch.watcher.actions.email.service.*;
import org.elasticsearch.watcher.actions.webhook.ExecutableWebhookAction;
import org.elasticsearch.watcher.actions.webhook.WebhookAction;
import org.elasticsearch.watcher.condition.script.ExecutableScriptCondition;
@ -47,7 +38,6 @@ import org.elasticsearch.watcher.execution.Wid;
import org.elasticsearch.watcher.input.search.ExecutableSearchInput;
import org.elasticsearch.watcher.input.simple.ExecutableSimpleInput;
import org.elasticsearch.watcher.input.simple.SimpleInput;
import org.elasticsearch.watcher.license.LicenseService;
import org.elasticsearch.watcher.support.Script;
import org.elasticsearch.watcher.support.WatcherUtils;
import org.elasticsearch.watcher.support.http.HttpClient;
@ -73,18 +63,10 @@ import org.elasticsearch.watcher.watch.WatchStatus;
import org.hamcrest.Matcher;
import org.joda.time.DateTime;
import javax.mail.internet.AddressException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.mail.internet.AddressException;
import java.util.*;
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomInt;
import static java.util.Collections.emptyMap;
@ -94,8 +76,6 @@ import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
import static org.elasticsearch.test.ESTestCase.randomFrom;
import static org.joda.time.DateTimeZone.UTC;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
*
@ -227,9 +207,6 @@ public final class WatcherTestUtils {
Map<String, Object> inputData = new LinkedHashMap<>();
inputData.put("bar", "foo");
LicenseService licenseService = mock(LicenseService.class);
when(licenseService.enabled()).thenReturn(true);
DateTime now = DateTime.now(UTC);
Map<String, ActionStatus> statuses = new HashMap<>();
statuses.put("_webhook", new ActionStatus(now));

View File

@ -61,7 +61,7 @@ import org.elasticsearch.watcher.input.search.SearchInputFactory;
import org.elasticsearch.watcher.input.simple.ExecutableSimpleInput;
import org.elasticsearch.watcher.input.simple.SimpleInput;
import org.elasticsearch.watcher.input.simple.SimpleInputFactory;
import org.elasticsearch.watcher.license.LicenseService;
import org.elasticsearch.watcher.license.WatcherLicensee;
import org.elasticsearch.watcher.support.Script;
import org.elasticsearch.watcher.support.WatcherUtils;
import org.elasticsearch.watcher.support.clock.Clock;
@ -146,7 +146,7 @@ public class WatchTests extends ESTestCase {
private HtmlSanitizer htmlSanitizer;
private HttpAuthRegistry authRegistry;
private SecretService secretService;
private LicenseService licenseService;
private WatcherLicensee watcherLicensee;
private ESLogger logger;
private Settings settings = Settings.EMPTY;
@ -159,7 +159,7 @@ public class WatchTests extends ESTestCase {
templateEngine = mock(TextTemplateEngine.class);
htmlSanitizer = mock(HtmlSanitizer.class);
secretService = mock(SecretService.class);
licenseService = mock(LicenseService.class);
watcherLicensee = mock(WatcherLicensee.class);
authRegistry = new HttpAuthRegistry(singletonMap("basic", new BasicAuthFactory(secretService)));
logger = Loggers.getLogger(WatchTests.class);
}
@ -455,11 +455,11 @@ public class WatchTests extends ESTestCase {
break;
}
}
return new ActionRegistry(unmodifiableMap(parsers), transformRegistry, SystemClock.INSTANCE, licenseService);
return new ActionRegistry(unmodifiableMap(parsers), transformRegistry, SystemClock.INSTANCE, watcherLicensee);
}
private ActionThrottler randomThrottler() {
return new ActionThrottler(SystemClock.INSTANCE, randomBoolean() ? null : TimeValue.timeValueMinutes(randomIntBetween(3, 5)), licenseService);
return new ActionThrottler(SystemClock.INSTANCE, randomBoolean() ? null : TimeValue.timeValueMinutes(randomIntBetween(3, 5)), watcherLicensee);
}
static class ParseOnlyScheduleTriggerEngine extends ScheduleTriggerEngine {