diff --git a/shield/src/main/java/org/elasticsearch/shield/action/ShieldActionFilter.java b/shield/src/main/java/org/elasticsearch/shield/action/ShieldActionFilter.java index 8ecab39b7c8..c5fbdbcca2f 100644 --- a/shield/src/main/java/org/elasticsearch/shield/action/ShieldActionFilter.java +++ b/shield/src/main/java/org/elasticsearch/shield/action/ShieldActionFilter.java @@ -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 { diff --git a/watcher/src/main/java/org/elasticsearch/watcher/WatcherPlugin.java b/watcher/src/main/java/org/elasticsearch/watcher/WatcherPlugin.java index a3504186e9d..fef620bc677 100644 --- a/watcher/src/main/java/org/elasticsearch/watcher/WatcherPlugin.java +++ b/watcher/src/main/java/org/elasticsearch/watcher/WatcherPlugin.java @@ -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, diff --git a/watcher/src/main/java/org/elasticsearch/watcher/actions/ActionRegistry.java b/watcher/src/main/java/org/elasticsearch/watcher/actions/ActionRegistry.java index e99306e7a65..dab3a8bf25e 100644 --- a/watcher/src/main/java/org/elasticsearch/watcher/actions/ActionRegistry.java +++ b/watcher/src/main/java/org/elasticsearch/watcher/actions/ActionRegistry.java @@ -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 parsers; private final TransformRegistry transformRegistry; private final Clock clock; - private final LicenseService licenseService; + private final WatcherLicensee watcherLicensee; @Inject - public ActionRegistry(Map parsers, TransformRegistry transformRegistry, Clock clock, LicenseService licenseService) { + public ActionRegistry(Map 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); } } diff --git a/watcher/src/main/java/org/elasticsearch/watcher/actions/ActionWrapper.java b/watcher/src/main/java/org/elasticsearch/watcher/actions/ActionWrapper.java index 877b21ef10e..44e076e65ec 100644 --- a/watcher/src/main/java/org/elasticsearch/watcher/actions/ActionWrapper.java +++ b/watcher/src/main/java/org/elasticsearch/watcher/actions/ActionWrapper.java @@ -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); } diff --git a/watcher/src/main/java/org/elasticsearch/watcher/actions/throttler/ActionThrottler.java b/watcher/src/main/java/org/elasticsearch/watcher/actions/throttler/ActionThrottler.java index 0cdd4cbdc50..870f2d998e6 100644 --- a/watcher/src/main/java/org/elasticsearch/watcher/actions/throttler/ActionThrottler.java +++ b/watcher/src/main/java/org/elasticsearch/watcher/actions/throttler/ActionThrottler.java @@ -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); diff --git a/watcher/src/main/java/org/elasticsearch/watcher/execution/ExecutionService.java b/watcher/src/main/java/org/elasticsearch/watcher/execution/ExecutionService.java index 375a40e35ac..c4e07a04d18 100644 --- a/watcher/src/main/java/org/elasticsearch/watcher/execution/ExecutionService.java +++ b/watcher/src/main/java/org/elasticsearch/watcher/execution/ExecutionService.java @@ -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()); diff --git a/watcher/src/main/java/org/elasticsearch/watcher/license/LicenseModule.java b/watcher/src/main/java/org/elasticsearch/watcher/license/LicenseModule.java index abb36be5520..4731209dee3 100644 --- a/watcher/src/main/java/org/elasticsearch/watcher/license/LicenseModule.java +++ b/watcher/src/main/java/org/elasticsearch/watcher/license/LicenseModule.java @@ -18,7 +18,7 @@ public class LicenseModule extends AbstractModule { @Override protected void configure() { - bind(LicenseService.class).asEagerSingleton(); + bind(WatcherLicensee.class).asEagerSingleton(); } private void verifyLicensePlugin() { diff --git a/watcher/src/main/java/org/elasticsearch/watcher/license/LicenseService.java b/watcher/src/main/java/org/elasticsearch/watcher/license/LicenseService.java deleted file mode 100644 index f19c22b1773..00000000000 --- a/watcher/src/main/java/org/elasticsearch/watcher/license/LicenseService.java +++ /dev/null @@ -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 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; - } -} diff --git a/watcher/src/main/java/org/elasticsearch/watcher/license/WatcherLicensee.java b/watcher/src/main/java/org/elasticsearch/watcher/license/WatcherLicensee.java new file mode 100644 index 00000000000..a709634f29b --- /dev/null +++ b/watcher/src/main/java/org/elasticsearch/watcher/license/WatcherLicensee.java @@ -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 { + + 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); + } +} diff --git a/watcher/src/main/java/org/elasticsearch/watcher/transport/actions/WatcherTransportAction.java b/watcher/src/main/java/org/elasticsearch/watcher/transport/actions/WatcherTransportAction.java index 684f5833b17..f974bb75cd2 100644 --- a/watcher/src/main/java/org/elasticsearch/watcher/transport/actions/WatcherTransportAction.java +++ b/watcher/src/main/java/org/elasticsearch/watcher/transport/actions/WatcherTransportAction.java @@ -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, Response extends ActionResponse> extends TransportMasterNodeAction { - 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) { + IndexNameExpressionResolver indexNameExpressionResolver, WatcherLicensee watcherLicensee, Supplier request) { super(settings, actionName, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, request); - this.licenseService = licenseService; + this.watcherLicensee = watcherLicensee; } @Override protected void doExecute(Request request, ActionListener 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)); } } } diff --git a/watcher/src/main/java/org/elasticsearch/watcher/transport/actions/ack/TransportAckWatchAction.java b/watcher/src/main/java/org/elasticsearch/watcher/transport/actions/ack/TransportAckWatchAction.java index d15163b380d..b9a754f44c3 100644 --- a/watcher/src/main/java/org/elasticsearch/watcher/transport/actions/ack/TransportAckWatchAction.java +++ b/watcher/src/main/java/org/elasticsearch/watcher/transport/actions/ack/TransportAckWatchAction.java @@ -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 listener) throws ElasticsearchException { + if (!watcherLicensee.isGetWatchAllowed()) { + listener.onFailure(LicenseUtils.newComplianceException(WatcherLicensee.ID)); + return; + } + try { Watch watch = watcherService.getWatch(request.getId()); if (watch == null) { diff --git a/watcher/src/main/java/org/elasticsearch/watcher/transport/actions/put/TransportPutWatchAction.java b/watcher/src/main/java/org/elasticsearch/watcher/transport/actions/put/TransportPutWatchAction.java index 068e26e2159..c012a0d88ba 100644 --- a/watcher/src/main/java/org/elasticsearch/watcher/transport/actions/put/TransportPutWatchAction.java +++ b/watcher/src/main/java/org/elasticsearch/watcher/transport/actions/put/TransportPutWatchAction.java @@ -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 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())); diff --git a/watcher/src/main/java/org/elasticsearch/watcher/transport/actions/service/TransportWatcherServiceAction.java b/watcher/src/main/java/org/elasticsearch/watcher/transport/actions/service/TransportWatcherServiceAction.java index 42fe8dfb3bd..a94c8040ed4 100644 --- a/watcher/src/main/java/org/elasticsearch/watcher/transport/actions/service/TransportWatcherServiceAction.java +++ b/watcher/src/main/java/org/elasticsearch/watcher/transport/actions/service/TransportWatcherServiceAction.java @@ -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 watchRecordMap) { return ObjectPath.eval("result.actions.0.status", watchRecordMap); } diff --git a/watcher/src/test/java/org/elasticsearch/watcher/actions/throttler/WatchThrottlerTests.java b/watcher/src/test/java/org/elasticsearch/watcher/actions/throttler/WatchThrottlerTests.java index 8581db74351..a4b933e3e1b 100644 --- a/watcher/src/test/java/org/elasticsearch/watcher/actions/throttler/WatchThrottlerTests.java +++ b/watcher/src/test/java/org/elasticsearch/watcher/actions/throttler/WatchThrottlerTests.java @@ -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")); + } } diff --git a/watcher/src/test/java/org/elasticsearch/watcher/execution/ExecutionServiceTests.java b/watcher/src/test/java/org/elasticsearch/watcher/execution/ExecutionServiceTests.java index e260dd50aee..b537164df7b 100644 --- a/watcher/src/test/java/org/elasticsearch/watcher/execution/ExecutionServiceTests.java +++ b/watcher/src/test/java/org/elasticsearch/watcher/execution/ExecutionServiceTests.java @@ -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); } - } diff --git a/watcher/src/test/java/org/elasticsearch/watcher/license/LicenseIntegrationTests.java b/watcher/src/test/java/org/elasticsearch/watcher/license/LicenseIntegrationTests.java deleted file mode 100644 index cd5cc13fdd8..00000000000 --- a/watcher/src/test/java/org/elasticsearch/watcher/license/LicenseIntegrationTests.java +++ /dev/null @@ -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 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 nodeModules() { - return Collections.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 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); - } - } - } - } -} diff --git a/watcher/src/test/java/org/elasticsearch/watcher/license/LicenseTests.java b/watcher/src/test/java/org/elasticsearch/watcher/license/LicenseTests.java new file mode 100644 index 00000000000..1bd9777a21b --- /dev/null +++ b/watcher/src/test/java/org/elasticsearch/watcher/license/LicenseTests.java @@ -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 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(); + } + } +} diff --git a/watcher/src/test/java/org/elasticsearch/watcher/test/AbstractWatcherIntegrationTestCase.java b/watcher/src/test/java/org/elasticsearch/watcher/test/AbstractWatcherIntegrationTestCase.java index dd26d5cf9fe..1e63359a631 100644 --- a/watcher/src/test/java/org/elasticsearch/watcher/test/AbstractWatcherIntegrationTestCase.java +++ b/watcher/src/test/java/org/elasticsearch/watcher/test/AbstractWatcherIntegrationTestCase.java @@ -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)); } } }); diff --git a/watcher/src/test/java/org/elasticsearch/watcher/test/WatcherTestUtils.java b/watcher/src/test/java/org/elasticsearch/watcher/test/WatcherTestUtils.java index dd19a01a666..8aa2d0d68c4 100644 --- a/watcher/src/test/java/org/elasticsearch/watcher/test/WatcherTestUtils.java +++ b/watcher/src/test/java/org/elasticsearch/watcher/test/WatcherTestUtils.java @@ -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 inputData = new LinkedHashMap<>(); inputData.put("bar", "foo"); - LicenseService licenseService = mock(LicenseService.class); - when(licenseService.enabled()).thenReturn(true); - DateTime now = DateTime.now(UTC); Map statuses = new HashMap<>(); statuses.put("_webhook", new ActionStatus(now)); diff --git a/watcher/src/test/java/org/elasticsearch/watcher/watch/WatchTests.java b/watcher/src/test/java/org/elasticsearch/watcher/watch/WatchTests.java index 64e83eff035..e0f26c82e55 100644 --- a/watcher/src/test/java/org/elasticsearch/watcher/watch/WatchTests.java +++ b/watcher/src/test/java/org/elasticsearch/watcher/watch/WatchTests.java @@ -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 {