LicensesService:

- Ensure license registration can be called through any stage of consumer plugin life cycle
 - Added randomized plugin integration tests
 - Run test on plugins with different license registration scheme

Original commit: elastic/x-pack-elasticsearch@1cee85943d
This commit is contained in:
Areek Zillur 2014-11-04 15:48:20 -05:00
parent 6c116e2fb3
commit d9d04fceaf
12 changed files with 307 additions and 186 deletions

View File

@ -18,6 +18,7 @@ import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.collect.ImmutableSet; import org.elasticsearch.common.collect.ImmutableSet;
import org.elasticsearch.common.collect.Sets; import org.elasticsearch.common.collect.Sets;
import org.elasticsearch.common.component.AbstractLifecycleComponent; import org.elasticsearch.common.component.AbstractLifecycleComponent;
import org.elasticsearch.common.component.Lifecycle;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.Singleton; import org.elasticsearch.common.inject.Singleton;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
@ -50,24 +51,24 @@ import static org.elasticsearch.license.core.ESLicenses.reduceAndMap;
* - LicensesManagerService - responsible for managing signed and one-time-trial licenses * - LicensesManagerService - responsible for managing signed and one-time-trial licenses
* - LicensesClientService - responsible for feature registration and notification to consumer plugin(s) * - LicensesClientService - responsible for feature registration and notification to consumer plugin(s)
* <p/> * <p/>
* * <p/>
* Notification Scheme: * Notification Scheme:
* * <p/>
* All registered feature(s) are notified using {@link #notifyFeatures(LicensesMetaData)} (depends on the current * All registered feature(s) are notified using {@link #notifyFeatures(LicensesMetaData)} (depends on the current
* {@link #registeredListeners}). It is idempotent with respect to all the feature listeners. * {@link #registeredListeners}). It is idempotent with respect to all the feature listeners.
* * <p/>
* The notification scheduling is done by {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)} which does the following: * The notification scheduling is done by {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)} which does the following:
* - calls {@link #notifyFeatures(LicensesMetaData)} to notify all registered feature(s) * - calls {@link #notifyFeatures(LicensesMetaData)} to notify all registered feature(s)
* - if there is any license(s) with a future expiry date in the current cluster state: * - if there is any license(s) with a future expiry date in the current cluster state:
* - schedules a delayed {@link LicensingClientNotificationJob} on the MIN of all the expiry dates of all the registered feature(s) * - schedules a delayed {@link LicensingClientNotificationJob} on the MIN of all the expiry dates of all the registered feature(s)
* * <p/>
* The {@link LicensingClientNotificationJob} calls {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)} to schedule * The {@link LicensingClientNotificationJob} calls {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)} to schedule
* another delayed {@link LicensingClientNotificationJob} as stated above. It is a no-op in case of a global block on * another delayed {@link LicensingClientNotificationJob} as stated above. It is a no-op in case of a global block on
* {@link org.elasticsearch.gateway.GatewayService#STATE_NOT_RECOVERED_BLOCK} * {@link org.elasticsearch.gateway.GatewayService#STATE_NOT_RECOVERED_BLOCK}
* * <p/>
* Upon successful registration of a new feature: * Upon successful registration of a new feature:
* - {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)} is called * - {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)} is called
* * <p/>
* Upon clusterChanged(): * Upon clusterChanged():
* - {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)} is called if: * - {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)} is called if:
* - new trial/signed license(s) are found in the cluster state meta data * - new trial/signed license(s) are found in the cluster state meta data
@ -386,38 +387,29 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
*/ */
@Override @Override
public void clusterChanged(ClusterChangedEvent event) { public void clusterChanged(ClusterChangedEvent event) {
final ClusterState currentClusterState = event.state();
final ClusterState previousClusterState = event.previousState(); final ClusterState previousClusterState = event.previousState();
final ClusterState currentClusterState = event.state();
if (!currentClusterState.blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK)) { if (!currentClusterState.blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK)) {
LicensesMetaData oldLicensesMetaData = previousClusterState.getMetaData().custom(LicensesMetaData.TYPE); final LicensesMetaData oldLicensesMetaData = previousClusterState.getMetaData().custom(LicensesMetaData.TYPE);
LicensesMetaData currentLicensesMetaData = currentClusterState.getMetaData().custom(LicensesMetaData.TYPE); final LicensesMetaData currentLicensesMetaData = currentClusterState.getMetaData().custom(LicensesMetaData.TYPE);
logLicenseMetaDataStats("old", oldLicensesMetaData); logLicenseMetaDataStats("old", oldLicensesMetaData);
logLicenseMetaDataStats("new", currentLicensesMetaData); logLicenseMetaDataStats("new", currentLicensesMetaData);
// Check pending feature registrations and try to complete registrations
boolean addedNewRegisteredListener = false;
if (!pendingListeners.isEmpty()) { if (!pendingListeners.isEmpty()) {
ListenerHolder pendingRegistrationLister; ListenerHolder pendingRegistrationListener;
while ((pendingRegistrationLister = pendingListeners.poll()) != null) { while ((pendingRegistrationListener = pendingListeners.poll()) != null) {
boolean masterAvailable = registerListener(pendingRegistrationLister); boolean masterAvailable = registerListener(pendingRegistrationListener);
logger.debug("trying to register pending listener for " + pendingRegistrationLister.feature + " masterAvailable: " + masterAvailable); logger.debug("trying to register pending listener for " + pendingRegistrationListener.feature + " masterAvailable: " + masterAvailable);
if (!masterAvailable) { if (!masterAvailable) {
// if the master is not available do not, break out of trying pendingListeners // if the master is not available do not, break out of trying pendingListeners
pendingListeners.add(pendingRegistrationLister); pendingListeners.add(pendingRegistrationListener);
break; break;
} else {
logger.debug("successfully registered listener for: " + pendingRegistrationLister.feature);
registeredListeners.add(pendingRegistrationLister);
// make sure to notify new registered feature
// notifications could have been scheduled for it before it was registered
addedNewRegisteredListener = true;
} }
} }
} }
// notify all interested plugins // notify all interested plugins
// Change to debug if (previousClusterState.blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK)) {
if (previousClusterState.blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK) || addedNewRegisteredListener) {
logger.debug("calling notifyFeaturesAndScheduleNotification from clusterChanged"); logger.debug("calling notifyFeaturesAndScheduleNotification from clusterChanged");
notifyFeaturesAndScheduleNotification(currentLicensesMetaData); notifyFeaturesAndScheduleNotification(currentLicensesMetaData);
} else { } else {
@ -433,7 +425,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
* Calls {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)} with <code>currentLicensesMetaData</code> * Calls {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)} with <code>currentLicensesMetaData</code>
* if it was not already notified on * if it was not already notified on
*/ */
private void notifyFeaturesAndScheduleNotificationIfNeeded(LicensesMetaData currentLicensesMetaData) { private void notifyFeaturesAndScheduleNotificationIfNeeded(final LicensesMetaData currentLicensesMetaData) {
final LicensesMetaData lastNotifiedLicensesMetaData = lastObservedLicensesState.get(); final LicensesMetaData lastNotifiedLicensesMetaData = lastObservedLicensesState.get();
if (lastNotifiedLicensesMetaData != null && lastNotifiedLicensesMetaData.equals(currentLicensesMetaData)) { if (lastNotifiedLicensesMetaData != null && lastNotifiedLicensesMetaData.equals(currentLicensesMetaData)) {
logger.debug("currentLicensesMetaData has been already notified on"); logger.debug("currentLicensesMetaData has been already notified on");
@ -446,7 +438,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
* Calls {@link #notifyFeatures(LicensesMetaData)} with <code>currentLicensesMetaData</code> * Calls {@link #notifyFeatures(LicensesMetaData)} with <code>currentLicensesMetaData</code>
* and schedules the earliest expiry (if any) notification for registered feature(s) * and schedules the earliest expiry (if any) notification for registered feature(s)
*/ */
private void notifyFeaturesAndScheduleNotification(LicensesMetaData currentLicensesMetaData) { private void notifyFeaturesAndScheduleNotification(final LicensesMetaData currentLicensesMetaData) {
long nextScheduleFrequency = notifyFeatures(currentLicensesMetaData); long nextScheduleFrequency = notifyFeatures(currentLicensesMetaData);
if (nextScheduleFrequency != -1l) { if (nextScheduleFrequency != -1l) {
scheduleNextNotification(nextScheduleFrequency); scheduleNextNotification(nextScheduleFrequency);
@ -463,7 +455,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
* returns the minimum of the expiry times of all the registered feature(s) to * returns the minimum of the expiry times of all the registered feature(s) to
* schedule an expiry notification * schedule an expiry notification
*/ */
private long notifyFeatures(LicensesMetaData currentLicensesMetaData) { private long notifyFeatures(final LicensesMetaData currentLicensesMetaData) {
long nextScheduleFrequency = -1l; long nextScheduleFrequency = -1l;
for (ListenerHolder listenerHolder : registeredListeners) { for (ListenerHolder listenerHolder : registeredListeners) {
long expiryDate = expiryDateForFeature(listenerHolder.feature, currentLicensesMetaData); long expiryDate = expiryDateForFeature(listenerHolder.feature, currentLicensesMetaData);
@ -496,8 +488,6 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
} }
} }
lastObservedLicensesState.set(currentLicensesMetaData);
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logLicenseMetaDataStats("Setting last observed metaData", currentLicensesMetaData); logLicenseMetaDataStats("Setting last observed metaData", currentLicensesMetaData);
if (nextScheduleFrequency == -1l) { if (nextScheduleFrequency == -1l) {
@ -507,9 +497,11 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
} }
} }
lastObservedLicensesState.set(currentLicensesMetaData);
return nextScheduleFrequency; return nextScheduleFrequency;
} }
private void logLicenseMetaDataStats(String prefix, LicensesMetaData licensesMetaData) { private void logLicenseMetaDataStats(String prefix, LicensesMetaData licensesMetaData) {
if (licensesMetaData != null) { if (licensesMetaData != null) {
logger.debug(prefix + " LicensesMetaData: signedLicenses: " + licensesMetaData.getSignatures().size() + " trialLicenses: " + licensesMetaData.getEncodedTrialLicenses().size()); logger.debug(prefix + " LicensesMetaData: signedLicenses: " + licensesMetaData.getSignatures().size() + " trialLicenses: " + licensesMetaData.getEncodedTrialLicenses().size());
@ -524,23 +516,33 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
@Override @Override
public void register(String feature, TrialLicenseOptions trialLicenseOptions, Listener listener) { public void register(String feature, TrialLicenseOptions trialLicenseOptions, Listener listener) {
final ListenerHolder listenerHolder = new ListenerHolder(feature, trialLicenseOptions, listener); final ListenerHolder listenerHolder = new ListenerHolder(feature, trialLicenseOptions, listener);
logger.debug("add listener for: " + listenerHolder.feature + " to pending registration queue"); // don't trust the clusterState for blocks just yet!
final Lifecycle.State state = clusterService.lifecycleState();
if (state != Lifecycle.State.STARTED) {
pendingListeners.add(listenerHolder); pendingListeners.add(listenerHolder);
} else {
if (!registerListener(listenerHolder)) {
pendingListeners.add(listenerHolder);
}
}
} }
/** /**
* Notifies new feature listener if it already has a signed license * Notifies new feature listener if it already has a signed license
* if new feature has a non-null trial license option, a master node request is made to generate the trial license * if new feature has a non-null trial license option, a master node request is made to generate the trial license
* if no trial license option is specified for the feature and no signed license is found, * then notifies features if needed
* then notifies features to be disabled
* then notifies features to be disabled
* *
* @param listenerHolder of the feature to register * @param listenerHolder of the feature to register
* @return true if registration has been completed, false otherwise (if masterNode is not available & trail license spec is provided * @return true if registration has been completed, false otherwise (if masterNode is not available & trail license spec is provided)
* or if there is a global block on {@link org.elasticsearch.gateway.GatewayService#STATE_NOT_RECOVERED_BLOCK}
*/ */
private boolean registerListener(final ListenerHolder listenerHolder) { private boolean registerListener(final ListenerHolder listenerHolder) {
logger.debug("Registering listener for " + listenerHolder.feature); logger.debug("Registering listener for " + listenerHolder.feature);
ClusterState currentState = clusterService.state(); final ClusterState currentState = clusterService.state();
if (currentState.blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK)) {
return false;
}
LicensesMetaData currentMetaData = currentState.metaData().custom(LicensesMetaData.TYPE); LicensesMetaData currentMetaData = currentState.metaData().custom(LicensesMetaData.TYPE);
if (expiryDateForFeature(listenerHolder.feature, currentMetaData) == -1l) { if (expiryDateForFeature(listenerHolder.feature, currentMetaData) == -1l) {
// does not have any license so generate a trial license // does not have any license so generate a trial license
@ -564,17 +566,20 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
return false; return false;
} }
} }
registeredListeners.add(listenerHolder);
} else { } else {
// notify feature as clusterChangedEvent may not happen // notify feature as clusterChangedEvent may not happen
// as no trial or signed license has been found for feature // as no trial or signed license has been found for feature
// Change to debug // Change to debug
logger.debug("Calling notifyFeaturesAndScheduleNotification [no trial license spec provided]"); logger.debug("Calling notifyFeaturesAndScheduleNotification [no trial license spec provided]");
registeredListeners.add(listenerHolder);
notifyFeaturesAndScheduleNotification(currentMetaData); notifyFeaturesAndScheduleNotification(currentMetaData);
} }
} else { } else {
// signed license already found for the new registered // signed license already found for the new registered
// feature, notify feature on registration // feature, notify feature on registration
logger.debug("Calling notifyFeaturesAndScheduleNotification [signed/trial license available]"); logger.debug("Calling notifyFeaturesAndScheduleNotification [signed/trial license available]");
registeredListeners.add(listenerHolder);
notifyFeaturesAndScheduleNotification(currentMetaData); notifyFeaturesAndScheduleNotification(currentMetaData);
} }
return true; return true;
@ -584,8 +589,6 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
final Map<String, ESLicense> effectiveLicenses = getEffectiveLicenses(currentLicensesMetaData); final Map<String, ESLicense> effectiveLicenses = getEffectiveLicenses(currentLicensesMetaData);
ESLicense featureLicense; ESLicense featureLicense;
if ((featureLicense = effectiveLicenses.get(feature)) != null) { if ((featureLicense = effectiveLicenses.get(feature)) != null) {
logger.debug("effective license for " + feature + " relative expiry: " +
TimeValue.timeValueMillis(effectiveLicenses.get(feature).expiryDate() - System.currentTimeMillis()));
return featureLicense.expiryDate(); return featureLicense.expiryDate();
} }
logger.debug("no effective license for " + feature); logger.debug("no effective license for " + feature);
@ -648,7 +651,8 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
*/ */
private class LicensingClientNotificationJob implements Runnable { private class LicensingClientNotificationJob implements Runnable {
public LicensingClientNotificationJob() {} public LicensingClientNotificationJob() {
}
@Override @Override
public void run() { public void run() {
@ -766,7 +770,8 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
private String feature; private String feature;
private TimeValue duration; private TimeValue duration;
private RegisterTrialLicenseRequest() {} private RegisterTrialLicenseRequest() {
}
private RegisterTrialLicenseRequest(String feature, TimeValue duration, int maxNodes) { private RegisterTrialLicenseRequest(String feature, TimeValue duration, int maxNodes) {
this.maxNodes = maxNodes; this.maxNodes = maxNodes;

View File

@ -16,14 +16,13 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.ESLicense; import org.elasticsearch.license.core.ESLicense;
import org.elasticsearch.license.licensor.ESLicenseSigner; import org.elasticsearch.license.licensor.ESLicenseSigner;
import org.elasticsearch.license.plugin.consumer.TestPluginService1; import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationPluginService;
import org.elasticsearch.license.plugin.consumer.TestPluginService2; import org.elasticsearch.license.plugin.consumer.LazyLicenseRegistrationPluginService;
import org.elasticsearch.license.plugin.consumer.TestPluginServiceBase; import org.elasticsearch.license.plugin.consumer.TestPluginServiceBase;
import org.elasticsearch.license.plugin.core.LicensesManagerService; import org.elasticsearch.license.plugin.core.LicensesManagerService;
import org.elasticsearch.license.plugin.core.LicensesMetaData; import org.elasticsearch.license.plugin.core.LicensesMetaData;
import org.elasticsearch.test.ElasticsearchIntegrationTest; import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.test.InternalTestCluster; import org.elasticsearch.test.InternalTestCluster;
import org.hamcrest.Matchers;
import java.util.*; import java.util.*;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
@ -115,30 +114,30 @@ public abstract class AbstractLicensesIntegrationTests extends ElasticsearchInte
}, 2, TimeUnit.SECONDS), equalTo(true)); }, 2, TimeUnit.SECONDS), equalTo(true));
} }
protected void assertConsumerPlugin1DisableNotification(int timeoutInSec) throws InterruptedException { protected void assertEagerConsumerPluginDisableNotification(int timeoutInSec) throws InterruptedException {
assertConsumerPlugin1Notification(false, timeoutInSec); assertEagerConsumerPluginNotification(false, timeoutInSec);
} }
protected void assertConsumerPlugin1EnableNotification(int timeoutInSec) throws InterruptedException { protected void assertEagerConsumerPluginEnableNotification(int timeoutInSec) throws InterruptedException {
assertConsumerPlugin1Notification(true, timeoutInSec); assertEagerConsumerPluginNotification(true, timeoutInSec);
} }
protected void assertConsumerPlugin2DisableNotification(int timeoutInSec) throws InterruptedException { protected void assertLazyConsumerPluginDisableNotification(int timeoutInSec) throws InterruptedException {
assertConsumerPlugin2Notification(false, timeoutInSec); assertLazyConsumerPluginNotification(false, timeoutInSec);
} }
protected void assertConsumerPlugin2EnableNotification(int timeoutInSec) throws InterruptedException { protected void assertLazyConsumerPluginEnableNotification(int timeoutInSec) throws InterruptedException {
assertConsumerPlugin2Notification(true, timeoutInSec); assertLazyConsumerPluginNotification(true, timeoutInSec);
} }
protected void assertConsumerPlugin2Notification(final boolean expectedEnabled, int timeoutInSec) throws InterruptedException { protected void assertLazyConsumerPluginNotification(final boolean expectedEnabled, int timeoutInSec) throws InterruptedException {
final List<TestPluginServiceBase> consumerPluginServices = consumerPlugin2Services(); final List<TestPluginServiceBase> consumerPluginServices = consumerLazyPluginServices();
assertThat("At least one instance has to be present", consumerPluginServices.size(), greaterThan(0)); assertThat("At least one instance has to be present", consumerPluginServices.size(), greaterThan(0));
assertConsumerPluginNotification(consumerPluginServices, expectedEnabled, timeoutInSec); assertConsumerPluginNotification(consumerPluginServices, expectedEnabled, timeoutInSec);
} }
protected void assertConsumerPlugin1Notification(final boolean expectedEnabled, int timeoutInSec) throws InterruptedException { protected void assertEagerConsumerPluginNotification(final boolean expectedEnabled, int timeoutInSec) throws InterruptedException {
final List<TestPluginServiceBase> consumerPluginServices = consumerPlugin1Services(); final List<TestPluginServiceBase> consumerPluginServices = consumerEagerPluginServices();
assertThat("At least one instance has to be present", consumerPluginServices.size(), greaterThan(0)); assertThat("At least one instance has to be present", consumerPluginServices.size(), greaterThan(0));
assertConsumerPluginNotification(consumerPluginServices, expectedEnabled, timeoutInSec); assertConsumerPluginNotification(consumerPluginServices, expectedEnabled, timeoutInSec);
} }
@ -158,19 +157,19 @@ public abstract class AbstractLicensesIntegrationTests extends ElasticsearchInte
} }
private List<TestPluginServiceBase> consumerPlugin2Services() { private List<TestPluginServiceBase> consumerLazyPluginServices() {
final InternalTestCluster clients = internalCluster(); final InternalTestCluster clients = internalCluster();
List<TestPluginServiceBase> consumerPluginServices = new ArrayList<>(); List<TestPluginServiceBase> consumerPluginServices = new ArrayList<>();
for (TestPluginServiceBase service : clients.getDataNodeInstances(TestPluginService2.class)) { for (TestPluginServiceBase service : clients.getDataNodeInstances(LazyLicenseRegistrationPluginService.class)) {
consumerPluginServices.add(service); consumerPluginServices.add(service);
} }
return consumerPluginServices; return consumerPluginServices;
} }
private List<TestPluginServiceBase> consumerPlugin1Services() { private List<TestPluginServiceBase> consumerEagerPluginServices() {
final InternalTestCluster clients = internalCluster(); final InternalTestCluster clients = internalCluster();
List<TestPluginServiceBase> consumerPluginServices = new ArrayList<>(); List<TestPluginServiceBase> consumerPluginServices = new ArrayList<>();
for (TestPluginServiceBase service : clients.getDataNodeInstances(TestPluginService1.class)) { for (TestPluginServiceBase service : clients.getDataNodeInstances(EagerLicenseRegistrationPluginService.class)) {
consumerPluginServices.add(service); consumerPluginServices.add(service);
} }
return consumerPluginServices; return consumerPluginServices;

View File

@ -5,15 +5,19 @@
*/ */
package org.elasticsearch.license.plugin; package org.elasticsearch.license.plugin;
import org.elasticsearch.common.base.Predicate;
import org.elasticsearch.common.collect.Lists; import org.elasticsearch.common.collect.Lists;
import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.license.core.ESLicense; import org.elasticsearch.license.core.ESLicense;
import org.elasticsearch.license.plugin.consumer.TestConsumerPlugin1; import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationConsumerPlugin;
import org.elasticsearch.license.plugin.consumer.TestPluginService1; import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationPluginService;
import org.elasticsearch.license.plugin.action.put.PutLicenseRequestBuilder; import org.elasticsearch.license.plugin.action.put.PutLicenseRequestBuilder;
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse; import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
import org.elasticsearch.license.plugin.consumer.LazyLicenseRegistrationConsumerPlugin;
import org.elasticsearch.license.plugin.consumer.LazyLicenseRegistrationPluginService;
import org.elasticsearch.license.plugin.core.LicensesStatus; import org.elasticsearch.license.plugin.core.LicensesStatus;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
@ -25,100 +29,134 @@ import static org.hamcrest.CoreMatchers.equalTo;
@ClusterScope(scope = TEST, numDataNodes = 10, numClientNodes = 0) @ClusterScope(scope = TEST, numDataNodes = 10, numClientNodes = 0)
public class LicensesPluginIntegrationTests extends AbstractLicensesIntegrationTests { public class LicensesPluginIntegrationTests extends AbstractLicensesIntegrationTests {
private final int trialLicenseDurationInSeconds = 2; private final boolean useEagerLicenseRegistrationPlugin = randomBoolean();
private final String FEATURE_NAME = TestPluginService1.FEATURE_NAME; private final int trialLicenseDurationInSeconds = 2;
protected Settings nodeSettings(int nodeOrdinal) { protected Settings nodeSettings(int nodeOrdinal) {
return ImmutableSettings.settingsBuilder() return ImmutableSettings.settingsBuilder()
.put(super.nodeSettings(nodeOrdinal)) .put(super.nodeSettings(nodeOrdinal))
.put(TestConsumerPlugin1.NAME + ".trial_license_duration_in_seconds", trialLicenseDurationInSeconds) .put(((useEagerLicenseRegistrationPlugin) ? EagerLicenseRegistrationConsumerPlugin.NAME : LazyLicenseRegistrationConsumerPlugin.NAME)
.put("plugin.types", LicensePlugin.class.getName() + "," + TestConsumerPlugin1.class.getName()) + ".trial_license_duration_in_seconds", trialLicenseDurationInSeconds)
.putArray("plugin.types", LicensePlugin.class.getName(),
(useEagerLicenseRegistrationPlugin) ? EagerLicenseRegistrationConsumerPlugin.class.getName() : LazyLicenseRegistrationConsumerPlugin.class.getName())
.build(); .build();
} }
@After @After
public void beforeTest() throws Exception { public void afterTest() throws Exception {
wipeAllLicenses(); wipeAllLicenses();
assertThat(awaitBusy(new Predicate<Object>() {
@Override
public boolean apply(Object o) {
return !clusterService().state().blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK);
}
}), equalTo(true));
} }
@Test @Test
public void testTrialLicenseAndSignedLicenseNotification() throws Exception { public void testTrialLicenseAndSignedLicenseNotification() throws Exception {
logger.info("using "+ ((useEagerLicenseRegistrationPlugin) ? "eager" : "lazy") + " consumer plugin");
logger.info(" --> trial license generated"); logger.info(" --> trial license generated");
// managerService should report feature to be enabled on all data nodes // managerService should report feature to be enabled on all data nodes
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME); assertLicenseManagerEnabledFeatureFor(getCurrentFeatureName());
// consumer plugin service should return enabled on all data nodes // consumer plugin service should return enabled on all data nodes
assertConsumerPlugin1EnableNotification(1); assertConsumerPluginEnabledNotification(1);
logger.info(" --> check trial license expiry notification"); logger.info(" --> check trial license expiry notification");
// consumer plugin should notify onDisabled on all data nodes (expired trial license) // consumer plugin should notify onDisabled on all data nodes (expired trial license)
assertConsumerPlugin1DisableNotification(trialLicenseDurationInSeconds * 2); assertConsumerPluginDisabledNotification(trialLicenseDurationInSeconds * 2);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME); assertLicenseManagerDisabledFeatureFor(getCurrentFeatureName());
logger.info(" --> put signed license"); logger.info(" --> put signed license");
ESLicense license = generateSignedLicense(FEATURE_NAME, TimeValue.timeValueSeconds(trialLicenseDurationInSeconds)); ESLicense license = generateSignedLicense(getCurrentFeatureName(), TimeValue.timeValueSeconds(trialLicenseDurationInSeconds));
final PutLicenseResponse putLicenseResponse = new PutLicenseRequestBuilder(client().admin().cluster()).setLicense(Lists.newArrayList(license)).get(); final PutLicenseResponse putLicenseResponse = new PutLicenseRequestBuilder(client().admin().cluster()).setLicense(Lists.newArrayList(license)).get();
assertThat(putLicenseResponse.isAcknowledged(), equalTo(true)); assertThat(putLicenseResponse.isAcknowledged(), equalTo(true));
assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID));
logger.info(" --> check signed license enabled notification"); logger.info(" --> check signed license enabled notification");
// consumer plugin should notify onEnabled on all data nodes (signed license) // consumer plugin should notify onEnabled on all data nodes (signed license)
assertConsumerPlugin1EnableNotification(1); assertConsumerPluginEnabledNotification(1);
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME); assertLicenseManagerEnabledFeatureFor(getCurrentFeatureName());
logger.info(" --> check signed license expiry notification"); logger.info(" --> check signed license expiry notification");
// consumer plugin should notify onDisabled on all data nodes (expired signed license) // consumer plugin should notify onDisabled on all data nodes (expired signed license)
assertConsumerPlugin1DisableNotification(trialLicenseDurationInSeconds * 2); assertConsumerPluginDisabledNotification(trialLicenseDurationInSeconds * 2);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME); assertLicenseManagerDisabledFeatureFor(getCurrentFeatureName());
} }
@Test @Test
public void testTrialLicenseNotification() throws Exception { public void testTrialLicenseNotification() throws Exception {
logger.info(" --> check onEnabled for trial license"); logger.info(" --> check onEnabled for trial license");
// managerService should report feature to be enabled on all data nodes // managerService should report feature to be enabled on all data nodes
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME); assertLicenseManagerEnabledFeatureFor(getCurrentFeatureName());
// consumer plugin service should return enabled on all data nodes // consumer plugin service should return enabled on all data nodes
assertConsumerPlugin1EnableNotification(1); assertConsumerPluginEnabledNotification(1);
logger.info(" --> sleep for rest of trailLicense duration"); logger.info(" --> sleep for rest of trailLicense duration");
Thread.sleep(trialLicenseDurationInSeconds * 1000l); Thread.sleep(trialLicenseDurationInSeconds * 1000l);
logger.info(" --> check trial license expiry notification"); logger.info(" --> check trial license expiry notification");
// consumer plugin should notify onDisabled on all data nodes (expired signed license) // consumer plugin should notify onDisabled on all data nodes (expired signed license)
assertConsumerPlugin1DisableNotification(trialLicenseDurationInSeconds); assertConsumerPluginDisabledNotification(trialLicenseDurationInSeconds);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME); assertLicenseManagerDisabledFeatureFor(getCurrentFeatureName());
} }
@Test @Test
public void testOverlappingTrialAndSignedLicenseNotification() throws Exception { public void testOverlappingTrialAndSignedLicenseNotification() throws Exception {
logger.info(" --> check onEnabled for trial license"); logger.info(" --> check onEnabled for trial license");
// managerService should report feature to be enabled on all data nodes // managerService should report feature to be enabled on all data nodes
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME); assertLicenseManagerEnabledFeatureFor(getCurrentFeatureName());
// consumer plugin service should return enabled on all data nodes // consumer plugin service should return enabled on all data nodes
assertConsumerPlugin1EnableNotification(1); assertConsumerPluginEnabledNotification(1);
logger.info(" --> put signed license while trial license is in effect"); logger.info(" --> put signed license while trial license is in effect");
ESLicense license = generateSignedLicense(FEATURE_NAME, TimeValue.timeValueSeconds(trialLicenseDurationInSeconds * 2)); ESLicense license = generateSignedLicense(getCurrentFeatureName(), TimeValue.timeValueSeconds(trialLicenseDurationInSeconds * 2));
final PutLicenseResponse putLicenseResponse = new PutLicenseRequestBuilder(client().admin().cluster()).setLicense(Lists.newArrayList(license)).get(); final PutLicenseResponse putLicenseResponse = new PutLicenseRequestBuilder(client().admin().cluster()).setLicense(Lists.newArrayList(license)).get();
assertThat(putLicenseResponse.isAcknowledged(), equalTo(true)); assertThat(putLicenseResponse.isAcknowledged(), equalTo(true));
assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID));
logger.info(" --> check signed license enabled notification"); logger.info(" --> check signed license enabled notification");
// consumer plugin should notify onEnabled on all data nodes (signed license) // consumer plugin should notify onEnabled on all data nodes (signed license)
assertConsumerPlugin1EnableNotification(1); assertConsumerPluginEnabledNotification(1);
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME); assertLicenseManagerEnabledFeatureFor(getCurrentFeatureName());
logger.info(" --> sleep for rest of trailLicense duration"); logger.info(" --> sleep for rest of trailLicense duration");
Thread.sleep(trialLicenseDurationInSeconds * 1000l); Thread.sleep(trialLicenseDurationInSeconds * 1000l);
logger.info(" --> check consumer is still enabled [signed license]"); logger.info(" --> check consumer is still enabled [signed license]");
// consumer plugin should notify onEnabled on all data nodes (signed license) // consumer plugin should notify onEnabled on all data nodes (signed license)
assertConsumerPlugin1EnableNotification(1); assertConsumerPluginEnabledNotification(1);
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME); assertLicenseManagerEnabledFeatureFor(getCurrentFeatureName());
logger.info(" --> check signed license expiry notification"); logger.info(" --> check signed license expiry notification");
// consumer plugin should notify onDisabled on all data nodes (expired signed license) // consumer plugin should notify onDisabled on all data nodes (expired signed license)
assertConsumerPlugin1DisableNotification(trialLicenseDurationInSeconds * 2 * 2); assertConsumerPluginDisabledNotification(trialLicenseDurationInSeconds * 2 * 2);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME); assertLicenseManagerDisabledFeatureFor(getCurrentFeatureName());
} }
private String getCurrentFeatureName() {
if (useEagerLicenseRegistrationPlugin) {
return EagerLicenseRegistrationPluginService.FEATURE_NAME;
} else {
return LazyLicenseRegistrationPluginService.FEATURE_NAME;
}
}
private void assertConsumerPluginEnabledNotification(int timeoutInSec) throws InterruptedException {
if (useEagerLicenseRegistrationPlugin) {
assertEagerConsumerPluginEnableNotification(timeoutInSec);
} else {
assertLazyConsumerPluginEnableNotification(timeoutInSec);
}
}
private void assertConsumerPluginDisabledNotification(int timeoutInSec) throws InterruptedException {
if (useEagerLicenseRegistrationPlugin) {
assertEagerConsumerPluginDisableNotification(timeoutInSec);
} else {
assertLazyConsumerPluginDisableNotification(timeoutInSec);
}
}
} }

View File

@ -5,17 +5,19 @@
*/ */
package org.elasticsearch.license.plugin; package org.elasticsearch.license.plugin;
import org.elasticsearch.common.base.Predicate;
import org.elasticsearch.common.collect.Lists; import org.elasticsearch.common.collect.Lists;
import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.license.core.ESLicense; import org.elasticsearch.license.core.ESLicense;
import org.elasticsearch.license.plugin.action.put.PutLicenseRequestBuilder; import org.elasticsearch.license.plugin.action.put.PutLicenseRequestBuilder;
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse; import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
import org.elasticsearch.license.plugin.consumer.TestConsumerPlugin1; import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationConsumerPlugin;
import org.elasticsearch.license.plugin.consumer.TestConsumerPlugin2; import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationPluginService;
import org.elasticsearch.license.plugin.consumer.TestPluginService1; import org.elasticsearch.license.plugin.consumer.LazyLicenseRegistrationConsumerPlugin;
import org.elasticsearch.license.plugin.consumer.TestPluginService2; import org.elasticsearch.license.plugin.consumer.LazyLicenseRegistrationPluginService;
import org.elasticsearch.license.plugin.core.LicensesStatus; import org.elasticsearch.license.plugin.core.LicensesStatus;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
@ -24,29 +26,30 @@ import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.TEST; import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.TEST;
import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.equalTo;
//@Ignore
@ClusterScope(scope = TEST, numDataNodes = 0, numClientNodes = 0) @ClusterScope(scope = TEST, numDataNodes = 0, numClientNodes = 0)
public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegrationTests { public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegrationTests {
private final int trialLicenseDurationInSeconds = 2; private final int trialLicenseDurationInSeconds = 2;
private final String FEATURE_NAME_1 = TestPluginService1.FEATURE_NAME; private final String FEATURE_NAME_1 = EagerLicenseRegistrationPluginService.FEATURE_NAME;
private final String FEATURE_NAME_2 = TestPluginService2.FEATURE_NAME; private final String FEATURE_NAME_2 = LazyLicenseRegistrationPluginService.FEATURE_NAME;
protected Settings nodeSettings(int nodeOrdinal) { protected Settings nodeSettings(int nodeOrdinal) {
return ImmutableSettings.settingsBuilder() return ImmutableSettings.settingsBuilder()
.put(super.nodeSettings(nodeOrdinal)) .put(super.nodeSettings(nodeOrdinal))
.put(TestConsumerPlugin1.NAME + ".trial_license_duration_in_seconds", trialLicenseDurationInSeconds) .put(EagerLicenseRegistrationConsumerPlugin.NAME + ".trial_license_duration_in_seconds", trialLicenseDurationInSeconds)
.put(TestConsumerPlugin2.NAME + ".trial_license_duration_in_seconds", trialLicenseDurationInSeconds) .put(LazyLicenseRegistrationConsumerPlugin.NAME + ".trial_license_duration_in_seconds", trialLicenseDurationInSeconds)
.putArray("plugin.types", LicensePlugin.class.getName(), TestConsumerPlugin1.class.getName(), TestConsumerPlugin2.class.getName()) .putArray("plugin.types", LicensePlugin.class.getName(), EagerLicenseRegistrationConsumerPlugin.class.getName(), LazyLicenseRegistrationConsumerPlugin.class.getName())
.build(); .build();
} }
private Settings nodeSettingsWithConsumerPlugin(int consumer1TrialLicenseDuration, int consumer2TrialLicenseDuration) { private Settings nodeSettingsWithConsumerPlugin(int consumer1TrialLicenseDuration, int consumer2TrialLicenseDuration) {
return ImmutableSettings.settingsBuilder() return ImmutableSettings.settingsBuilder()
.put(super.nodeSettings(0)) .put(super.nodeSettings(0))
.put(TestConsumerPlugin1.NAME + ".trial_license_duration_in_seconds", consumer1TrialLicenseDuration) .put(EagerLicenseRegistrationConsumerPlugin.NAME + ".trial_license_duration_in_seconds", consumer1TrialLicenseDuration)
.put(TestConsumerPlugin2.NAME + ".trial_license_duration_in_seconds", consumer2TrialLicenseDuration) .put(LazyLicenseRegistrationConsumerPlugin.NAME + ".trial_license_duration_in_seconds", consumer2TrialLicenseDuration)
.putArray("plugin.types", LicensePlugin.class.getName(), TestConsumerPlugin1.class.getName(), TestConsumerPlugin2.class.getName()) .putArray("plugin.types", LicensePlugin.class.getName(), EagerLicenseRegistrationConsumerPlugin.class.getName(), LazyLicenseRegistrationConsumerPlugin.class.getName())
.build(); .build();
} }
@ -61,8 +64,8 @@ public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegration
int nNodes = randomIntBetween(2, 10); int nNodes = randomIntBetween(2, 10);
String[] nodes = startNodesWithConsumerPlugins(nNodes, -1, -1); String[] nodes = startNodesWithConsumerPlugins(nNodes, -1, -1);
assertConsumerPlugin1DisableNotification(trialLicenseDurationInSeconds * 2); assertEagerConsumerPluginDisableNotification(trialLicenseDurationInSeconds * 2);
assertConsumerPlugin2DisableNotification(trialLicenseDurationInSeconds * 2); assertLazyConsumerPluginDisableNotification(trialLicenseDurationInSeconds * 2);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2);
} }
@ -78,8 +81,8 @@ public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegration
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1);
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_2);
// consumer plugin service should return enabled on all data nodes // consumer plugin service should return enabled on all data nodes
assertConsumerPlugin1DisableNotification(1); assertEagerConsumerPluginDisableNotification(1);
assertConsumerPlugin2EnableNotification(1); assertLazyConsumerPluginEnableNotification(1);
logger.info(" --> put signed license for " + FEATURE_NAME_1); logger.info(" --> put signed license for " + FEATURE_NAME_1);
ESLicense license1 = generateSignedLicense(FEATURE_NAME_1, TimeValue.timeValueSeconds(consumer2TrialLicenseDuration)); ESLicense license1 = generateSignedLicense(FEATURE_NAME_1, TimeValue.timeValueSeconds(consumer2TrialLicenseDuration));
@ -88,15 +91,15 @@ public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegration
assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID));
logger.info(" --> check that both " + FEATURE_NAME_1 + " and " + FEATURE_NAME_2 + " are enabled"); logger.info(" --> check that both " + FEATURE_NAME_1 + " and " + FEATURE_NAME_2 + " are enabled");
assertConsumerPlugin1EnableNotification(1); assertEagerConsumerPluginEnableNotification(1);
assertConsumerPlugin2EnableNotification(1); assertLazyConsumerPluginEnableNotification(1);
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_1);
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_2);
logger.info(" --> check signed license expiry notification"); logger.info(" --> check signed license expiry notification");
// consumer plugin should notify onDisabled on all data nodes (expired signed license) // consumer plugin should notify onDisabled on all data nodes (expired signed license)
assertConsumerPlugin1DisableNotification(consumer2TrialLicenseDuration * 2); assertEagerConsumerPluginDisableNotification(consumer2TrialLicenseDuration * 2);
assertConsumerPlugin2DisableNotification(consumer2TrialLicenseDuration * 2); assertLazyConsumerPluginDisableNotification(consumer2TrialLicenseDuration * 2);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2);
} }
@ -106,19 +109,30 @@ public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegration
int nNodes = randomIntBetween(2, 10); int nNodes = randomIntBetween(2, 10);
String[] nodes = startNodesWithConsumerPlugins(nNodes, trialLicenseDurationInSeconds, trialLicenseDurationInSeconds); String[] nodes = startNodesWithConsumerPlugins(nNodes, trialLicenseDurationInSeconds, trialLicenseDurationInSeconds);
waitUntilClusterRecovered();
assertThat(awaitBusy(new Predicate<Object>() {
@Override
public boolean apply(Object o) {
for (LazyLicenseRegistrationPluginService service : internalCluster().getDataNodeInstances(LazyLicenseRegistrationPluginService.class)) {
if (!service.registered.get()) {
return false;
}
}
return true;
}
}), equalTo(true));
logger.info(" --> trial license generated"); logger.info(" --> trial license generated");
// managerService should report feature to be enabled on all data nodes // managerService should report feature to be enabled on all data nodes
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_1);
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_2);
// consumer plugin service should return enabled on all data nodes // consumer plugin service should return enabled on all data nodes
assertConsumerPlugin1EnableNotification(1); assertEagerConsumerPluginEnableNotification(1);
assertConsumerPlugin2EnableNotification(1); assertLazyConsumerPluginEnableNotification(1);
logger.info(" --> check trial license expiry notification"); logger.info(" --> check trial license expiry notification");
// consumer plugin should notify onDisabled on all data nodes (expired trial license) // consumer plugin should notify onDisabled on all data nodes (expired trial license)
assertConsumerPlugin1DisableNotification(trialLicenseDurationInSeconds * 2); assertEagerConsumerPluginDisableNotification(trialLicenseDurationInSeconds * 2);
assertConsumerPlugin2DisableNotification(trialLicenseDurationInSeconds * 2); assertLazyConsumerPluginDisableNotification(trialLicenseDurationInSeconds * 2);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2);
@ -128,15 +142,15 @@ public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegration
logger.info(" --> check signed license enabled notification"); logger.info(" --> check signed license enabled notification");
// consumer plugin should notify onEnabled on all data nodes (signed license) // consumer plugin should notify onEnabled on all data nodes (signed license)
assertConsumerPlugin1EnableNotification(1); assertEagerConsumerPluginEnableNotification(1);
assertConsumerPlugin2EnableNotification(1); assertLazyConsumerPluginEnableNotification(1);
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_1);
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_2);
logger.info(" --> check signed license expiry notification"); logger.info(" --> check signed license expiry notification");
// consumer plugin should notify onDisabled on all data nodes (expired signed license) // consumer plugin should notify onDisabled on all data nodes (expired signed license)
assertConsumerPlugin1DisableNotification(trialLicenseDurationInSeconds * 2); assertEagerConsumerPluginDisableNotification(trialLicenseDurationInSeconds * 2);
assertConsumerPlugin2DisableNotification(trialLicenseDurationInSeconds * 2); assertLazyConsumerPluginDisableNotification(trialLicenseDurationInSeconds * 2);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2);
} }
@ -150,33 +164,33 @@ public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegration
String[] nodes = startNodesWithConsumerPlugins(nNodes, trialLicenseDuration1, trialLicenseDuration2); String[] nodes = startNodesWithConsumerPlugins(nNodes, trialLicenseDuration1, trialLicenseDuration2);
if (trialLicenseDuration1 != -1) { if (trialLicenseDuration1 != -1) {
assertConsumerPlugin1EnableNotification(1); assertEagerConsumerPluginEnableNotification(1);
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_1);
} else { } else {
assertConsumerPlugin1DisableNotification(1); assertEagerConsumerPluginDisableNotification(1);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1);
putLicense(FEATURE_NAME_1, TimeValue.timeValueMillis(300 * 2)); putLicense(FEATURE_NAME_1, TimeValue.timeValueMillis(300 * 2));
} }
if (trialLicenseDuration2 != -1) { if (trialLicenseDuration2 != -1) {
assertConsumerPlugin2EnableNotification(1); assertLazyConsumerPluginEnableNotification(1);
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_2);
} else { } else {
assertConsumerPlugin2DisableNotification(1); assertLazyConsumerPluginDisableNotification(1);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2);
putLicense(FEATURE_NAME_2, TimeValue.timeValueMillis(300 * 2)); putLicense(FEATURE_NAME_2, TimeValue.timeValueMillis(300 * 2));
} }
logger.info(" --> check license enabled notification"); logger.info(" --> check license enabled notification");
assertConsumerPlugin1EnableNotification(1); assertEagerConsumerPluginEnableNotification(1);
assertConsumerPlugin2EnableNotification(1); assertLazyConsumerPluginEnableNotification(1);
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_1);
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_2);
logger.info(" --> check license expiry notification"); logger.info(" --> check license expiry notification");
// consumer plugin should notify onDisabled on all data nodes (expired signed license) // consumer plugin should notify onDisabled on all data nodes (expired signed license)
assertConsumerPlugin1DisableNotification(2 * 2); assertEagerConsumerPluginDisableNotification(2 * 2);
assertConsumerPlugin2DisableNotification(2 * 2); assertLazyConsumerPluginDisableNotification(2 * 2);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2);
@ -196,4 +210,13 @@ public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegration
assertThat(putLicenseResponse.isAcknowledged(), equalTo(true)); assertThat(putLicenseResponse.isAcknowledged(), equalTo(true));
assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID));
} }
private void waitUntilClusterRecovered() throws InterruptedException {
assertThat(awaitBusy(new Predicate<Object>() {
@Override
public boolean apply(Object o) {
return !clusterService().state().blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK);
}
}), equalTo(true));
}
} }

View File

@ -6,22 +6,17 @@
package org.elasticsearch.license.plugin; package org.elasticsearch.license.plugin;
import org.elasticsearch.client.ClusterAdminClient; import org.elasticsearch.client.ClusterAdminClient;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.common.base.Predicate;
import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.discovery.DiscoverySettings;
import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.license.TestUtils; import org.elasticsearch.license.TestUtils;
import org.elasticsearch.license.core.ESLicense; import org.elasticsearch.license.core.ESLicense;
import org.elasticsearch.license.plugin.action.get.GetLicenseRequestBuilder; import org.elasticsearch.license.plugin.action.get.GetLicenseRequestBuilder;
import org.elasticsearch.license.plugin.action.get.GetLicenseResponse; import org.elasticsearch.license.plugin.action.get.GetLicenseResponse;
import org.elasticsearch.license.plugin.action.put.PutLicenseRequestBuilder; import org.elasticsearch.license.plugin.action.put.PutLicenseRequestBuilder;
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse; import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
import org.elasticsearch.license.plugin.consumer.TestConsumerPlugin1; import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationConsumerPlugin;
import org.elasticsearch.license.plugin.consumer.TestPluginService1; import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationPluginService;
import org.elasticsearch.license.plugin.core.LicensesStatus; import org.elasticsearch.license.plugin.core.LicensesStatus;
import org.elasticsearch.node.internal.InternalNode; import org.elasticsearch.node.internal.InternalNode;
import org.junit.Test; import org.junit.Test;
@ -37,7 +32,7 @@ import static org.hamcrest.CoreMatchers.equalTo;
@ClusterScope(scope = TEST, numDataNodes = 0, numClientNodes = 0, maxNumDataNodes = 0, transportClientRatio = 0) @ClusterScope(scope = TEST, numDataNodes = 0, numClientNodes = 0, maxNumDataNodes = 0, transportClientRatio = 0)
public class LicensesServiceClusterTest extends AbstractLicensesIntegrationTests { public class LicensesServiceClusterTest extends AbstractLicensesIntegrationTests {
private final String FEATURE_NAME = TestPluginService1.FEATURE_NAME; private final String FEATURE_NAME = EagerLicenseRegistrationPluginService.FEATURE_NAME;
private final int trialLicenseDurationInSeconds = 2; private final int trialLicenseDurationInSeconds = 2;
@ -57,8 +52,8 @@ public class LicensesServiceClusterTest extends AbstractLicensesIntegrationTests
.put("plugins.load_classpath_plugins", false) .put("plugins.load_classpath_plugins", false)
.put("node.data", true) .put("node.data", true)
.put("format", "json") .put("format", "json")
.put(TestConsumerPlugin1.NAME + ".trial_license_duration_in_seconds", trialLicenseDurationInSeconds) .put(EagerLicenseRegistrationConsumerPlugin.NAME + ".trial_license_duration_in_seconds", trialLicenseDurationInSeconds)
.putArray("plugin.types", LicensePlugin.class.getName(), TestConsumerPlugin1.class.getName()) .putArray("plugin.types", LicensePlugin.class.getName(), EagerLicenseRegistrationConsumerPlugin.class.getName())
.put(InternalNode.HTTP_ENABLED, true); .put(InternalNode.HTTP_ENABLED, true);
} }
@ -91,12 +86,12 @@ public class LicensesServiceClusterTest extends AbstractLicensesIntegrationTests
logger.info("--> start one master out of two [recovery state]"); logger.info("--> start one master out of two [recovery state]");
internalCluster().startNode(nodeSettingsBuilder(0).put("discovery.zen.minimum_master_nodes", 2).put("node.master", true)); internalCluster().startNode(nodeSettingsBuilder(0).put("discovery.zen.minimum_master_nodes", 2).put("node.master", true));
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME);
assertConsumerPlugin1DisableNotification(1); assertEagerConsumerPluginDisableNotification(1);
logger.info("--> start second master out of two [recovered state]"); logger.info("--> start second master out of two [recovered state]");
internalCluster().startNode(nodeSettingsBuilder(1).put("discovery.zen.minimum_master_nodes", 2).put("node.master", true)); internalCluster().startNode(nodeSettingsBuilder(1).put("discovery.zen.minimum_master_nodes", 2).put("node.master", true));
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME); assertLicenseManagerEnabledFeatureFor(FEATURE_NAME);
assertConsumerPlugin1EnableNotification(1); assertEagerConsumerPluginEnableNotification(1);
} }
private List<ESLicense> generateAndPutLicense() throws Exception { private List<ESLicense> generateAndPutLicense() throws Exception {

View File

@ -8,8 +8,8 @@ package org.elasticsearch.license.plugin;
import org.elasticsearch.common.base.Predicate; import org.elasticsearch.common.base.Predicate;
import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.plugin.consumer.TestConsumerPlugin1; import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationConsumerPlugin;
import org.elasticsearch.license.plugin.consumer.TestPluginService1; import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationPluginService;
import org.elasticsearch.node.internal.InternalNode; import org.elasticsearch.node.internal.InternalNode;
import org.elasticsearch.test.ElasticsearchIntegrationTest; import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.test.junit.annotations.TestLogging; import org.elasticsearch.test.junit.annotations.TestLogging;
@ -29,8 +29,8 @@ public class LicensesServiceNodeTests extends AbstractLicensesIntegrationTests {
protected Settings nodeSettings(int nodeOrdinal) { protected Settings nodeSettings(int nodeOrdinal) {
return ImmutableSettings.settingsBuilder() return ImmutableSettings.settingsBuilder()
.put(super.nodeSettings(nodeOrdinal)) .put(super.nodeSettings(nodeOrdinal))
.put(TestConsumerPlugin1.NAME + ".trial_license_duration_in_seconds", 5) .put(EagerLicenseRegistrationConsumerPlugin.NAME + ".trial_license_duration_in_seconds", 5)
.putArray("plugin.types", LicensePlugin.class.getName(), TestConsumerPlugin1.class.getName()) .putArray("plugin.types", LicensePlugin.class.getName(), EagerLicenseRegistrationConsumerPlugin.class.getName())
.put(InternalNode.HTTP_ENABLED, true) .put(InternalNode.HTTP_ENABLED, true)
.build(); .build();
} }
@ -38,11 +38,11 @@ public class LicensesServiceNodeTests extends AbstractLicensesIntegrationTests {
@Test @Test
@TestLogging("_root:DEBUG") @TestLogging("_root:DEBUG")
public void testPluginStatus() throws Exception { public void testPluginStatus() throws Exception {
final Iterable<TestPluginService1> testPluginServices = internalCluster().getDataNodeInstances(TestPluginService1.class); final Iterable<EagerLicenseRegistrationPluginService> testPluginServices = internalCluster().getDataNodeInstances(EagerLicenseRegistrationPluginService.class);
assertThat(awaitBusy(new Predicate<Object>() { assertThat(awaitBusy(new Predicate<Object>() {
@Override @Override
public boolean apply(Object o) { public boolean apply(Object o) {
for (TestPluginService1 pluginService : testPluginServices) { for (EagerLicenseRegistrationPluginService pluginService : testPluginServices) {
if (!pluginService.enabled()) { if (!pluginService.enabled()) {
return false; return false;
} }

View File

@ -13,6 +13,7 @@ import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.common.base.Predicate; import org.elasticsearch.common.base.Predicate;
import org.elasticsearch.common.collect.ImmutableSet; import org.elasticsearch.common.collect.ImmutableSet;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.license.TestUtils; import org.elasticsearch.license.TestUtils;
import org.elasticsearch.license.core.ESLicense; import org.elasticsearch.license.core.ESLicense;
import org.elasticsearch.license.manager.ESLicenseManager; import org.elasticsearch.license.manager.ESLicenseManager;
@ -224,13 +225,13 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
} }
@Test @Test
public void testRandomMultipleClientMultipleFeature() throws Exception { public void testRandomActionSequenceMultipleFeature() throws Exception {
LicensesService licensesService = randomLicensesService(); LicensesService licensesService = randomLicensesService();
LicensesManagerService masterLicensesManagerService = masterLicensesManagerService(); LicensesManagerService masterLicensesManagerService = masterLicensesManagerService();
Map<TestTrackingClientListener, List<Action>> clientListenersWithActions = new HashMap<>(); Map<TestTrackingClientListener, List<Action>> clientListenersWithActions = new HashMap<>();
TimeValue expiryDuration = TimeValue.timeValueSeconds(0); TimeValue expiryDuration = TimeValue.timeValueSeconds(0);
for (int i = 0; i < randomIntBetween(3, 10); i++) { for (int i = 0; i < randomIntBetween(10, 20); i++) {
final TestTrackingClientListener clientListener = new TestTrackingClientListener(); final TestTrackingClientListener clientListener = new TestTrackingClientListener();
String feature = randomRealisticUnicodeOfCodepointLengthBetween(2, 10); String feature = randomRealisticUnicodeOfCodepointLengthBetween(2, 10);
expiryDuration = TimeValue.timeValueMillis(randomIntBetween(1, 5) * 100l + expiryDuration.millis()); expiryDuration = TimeValue.timeValueMillis(randomIntBetween(1, 5) * 100l + expiryDuration.millis());
@ -313,6 +314,17 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
// invoke clusterChanged event to flush out pendingRegistration // invoke clusterChanged event to flush out pendingRegistration
LicensesService licensesService = (LicensesService) clientService; LicensesService licensesService = (LicensesService) clientService;
/*
try {
assertThat(awaitBusy(new Predicate<Object>() {
@Override
public boolean apply(Object o) {
return !clusterService().state().blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK);
}
}), equalTo(true));
} catch (InterruptedException e) {
logger.error("Exception while trying to registerWithTrialLicense", e);
}*/
ClusterChangedEvent event = new ClusterChangedEvent("", clusterService().state(), clusterService().state()); ClusterChangedEvent event = new ClusterChangedEvent("", clusterService().state(), clusterService().state());
licensesService.clusterChanged(event); licensesService.clusterChanged(event);
} }

View File

@ -9,18 +9,24 @@ import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
public class TestConsumerPlugin1 extends TestConsumerPluginBase { /**
* Registers licenses upon the start of the service lifecycle
* see {@link org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationPluginService}
*
* License registration might happen before clusterService start()
*/
public class EagerLicenseRegistrationConsumerPlugin extends TestConsumerPluginBase {
public final static String NAME = "test_consumer_plugin_1"; public final static String NAME = "test_consumer_plugin_1";
@Inject @Inject
public TestConsumerPlugin1(Settings settings) { public EagerLicenseRegistrationConsumerPlugin(Settings settings) {
super(settings); super(settings);
} }
@Override @Override
protected Class<? extends LifecycleComponent> service() { protected Class<? extends LifecycleComponent> service() {
return TestPluginService1.class; return EagerLicenseRegistrationPluginService.class;
} }
@Override @Override

View File

@ -11,13 +11,13 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.plugin.core.LicensesClientService; import org.elasticsearch.license.plugin.core.LicensesClientService;
@Singleton @Singleton
public class TestPluginService1 extends TestPluginServiceBase { public class EagerLicenseRegistrationPluginService extends TestPluginServiceBase {
public static String FEATURE_NAME = "feature1"; public static String FEATURE_NAME = "feature1";
@Inject @Inject
public TestPluginService1(Settings settings, LicensesClientService licensesClientService) { public EagerLicenseRegistrationPluginService(Settings settings, LicensesClientService licensesClientService) {
super(settings, licensesClientService); super(true, settings, licensesClientService, null);
} }
@Override @Override
@ -27,6 +27,6 @@ public class TestPluginService1 extends TestPluginServiceBase {
@Override @Override
public String settingPrefix() { public String settingPrefix() {
return TestConsumerPlugin1.NAME; return EagerLicenseRegistrationConsumerPlugin.NAME;
} }
} }

View File

@ -9,18 +9,24 @@ import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
public class TestConsumerPlugin2 extends TestConsumerPluginBase { /**
* Registers licenses only after cluster has recovered
* see {@link org.elasticsearch.license.plugin.consumer.LazyLicenseRegistrationPluginService}
*
* License registration happens after clusterservice start()
*/
public class LazyLicenseRegistrationConsumerPlugin extends TestConsumerPluginBase {
public static String NAME = "test_consumer_plugin_2"; public static String NAME = "test_consumer_plugin_2";
@Inject @Inject
public TestConsumerPlugin2(Settings settings) { public LazyLicenseRegistrationConsumerPlugin(Settings settings) {
super(settings); super(settings);
} }
@Override @Override
protected Class<? extends LifecycleComponent> service() { protected Class<? extends LifecycleComponent> service() {
return TestPluginService2.class; return LazyLicenseRegistrationPluginService.class;
} }
@Override @Override

View File

@ -5,20 +5,21 @@
*/ */
package org.elasticsearch.license.plugin.consumer; package org.elasticsearch.license.plugin.consumer;
import org.elasticsearch.cluster.ClusterService;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.Singleton; import org.elasticsearch.common.inject.Singleton;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.plugin.core.LicensesClientService; import org.elasticsearch.license.plugin.core.LicensesClientService;
@Singleton @Singleton
public class TestPluginService2 extends TestPluginServiceBase { public class LazyLicenseRegistrationPluginService extends TestPluginServiceBase {
public static String FEATURE_NAME = "feature2"; public static String FEATURE_NAME = "feature2";
@Inject @Inject
public TestPluginService2(Settings settings, LicensesClientService licensesClientService) { public LazyLicenseRegistrationPluginService(Settings settings, LicensesClientService licensesClientService, ClusterService clusterService) {
super(settings, licensesClientService); super(false, settings, licensesClientService, clusterService);
} }
@Override @Override
@ -28,6 +29,6 @@ public class TestPluginService2 extends TestPluginServiceBase {
@Override @Override
public String settingPrefix() { public String settingPrefix() {
return TestConsumerPlugin2.NAME; return LazyLicenseRegistrationConsumerPlugin.NAME;
} }
} }

View File

@ -6,26 +6,36 @@
package org.elasticsearch.license.plugin.consumer; package org.elasticsearch.license.plugin.consumer;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.cluster.ClusterChangedEvent;
import org.elasticsearch.cluster.ClusterService;
import org.elasticsearch.cluster.ClusterStateListener;
import org.elasticsearch.common.component.AbstractLifecycleComponent; import org.elasticsearch.common.component.AbstractLifecycleComponent;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.license.plugin.core.LicensesClientService; import org.elasticsearch.license.plugin.core.LicensesClientService;
import org.elasticsearch.license.plugin.core.LicensesService; import org.elasticsearch.license.plugin.core.LicensesService;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
public abstract class TestPluginServiceBase extends AbstractLifecycleComponent<TestPluginServiceBase> { public abstract class TestPluginServiceBase extends AbstractLifecycleComponent<TestPluginServiceBase> implements ClusterStateListener {
private LicensesClientService licensesClientService; private LicensesClientService licensesClientService;
private final ClusterService clusterService;
// specify the trial license spec for the feature // specify the trial license spec for the feature
// example: 30 day trial on 1000 nodes // example: 30 day trial on 1000 nodes
final LicensesService.TrialLicenseOptions trialLicenseOptions; final LicensesService.TrialLicenseOptions trialLicenseOptions;
final boolean eagerLicenseRegistration;
public final AtomicBoolean registered = new AtomicBoolean(false);
private AtomicBoolean enabled = new AtomicBoolean(false); private AtomicBoolean enabled = new AtomicBoolean(false);
public TestPluginServiceBase(Settings settings, LicensesClientService licensesClientService) { public TestPluginServiceBase(boolean eagerLicenseRegistration, Settings settings, LicensesClientService licensesClientService, ClusterService clusterService) {
super(settings); super(settings);
this.eagerLicenseRegistration = eagerLicenseRegistration;
this.licensesClientService = licensesClientService; this.licensesClientService = licensesClientService;
int durationInSec = settings.getAsInt(settingPrefix() + ".trial_license_duration_in_seconds", -1); int durationInSec = settings.getAsInt(settingPrefix() + ".trial_license_duration_in_seconds", -1);
if (durationInSec == -1) { if (durationInSec == -1) {
@ -33,6 +43,12 @@ public abstract class TestPluginServiceBase extends AbstractLifecycleComponent<T
} else { } else {
this.trialLicenseOptions = new LicensesService.TrialLicenseOptions(TimeValue.timeValueSeconds(durationInSec), 1000); this.trialLicenseOptions = new LicensesService.TrialLicenseOptions(TimeValue.timeValueSeconds(durationInSec), 1000);
} }
if (!eagerLicenseRegistration) {
this.clusterService = clusterService;
clusterService.add(this);
} else {
this.clusterService = null;
}
} }
// should be the same string used by the license Manger to generate // should be the same string used by the license Manger to generate
@ -46,14 +62,34 @@ public abstract class TestPluginServiceBase extends AbstractLifecycleComponent<T
return enabled.get(); return enabled.get();
} }
protected void doStart() throws ElasticsearchException { @Override
public void clusterChanged(ClusterChangedEvent event) {
if (!eagerLicenseRegistration && !event.state().blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK)) {
if (registered.compareAndSet(false, true)) {
logger.info("Registering to licensesService [lazy]");
licensesClientService.register(featureName(), licensesClientService.register(featureName(),
trialLicenseOptions, trialLicenseOptions,
new LicensingClientListener()); new LicensingClientListener());
} }
}
}
protected void doStart() throws ElasticsearchException {
if (eagerLicenseRegistration) {
if (registered.compareAndSet(false, true)) {
logger.info("Registering to licensesService [eager]");
licensesClientService.register(featureName(),
trialLicenseOptions,
new LicensingClientListener());
}
}
}
@Override @Override
protected void doStop() throws ElasticsearchException { protected void doStop() throws ElasticsearchException {
if (clusterService != null) {
clusterService.remove(this);
}
} }
@Override @Override