LicensesService:
- notification management - dont notify when NOT_RECOVERED_BLOCK is on - clean up & fixes - improve tests Original commit: elastic/x-pack-elasticsearch@907af6d308
This commit is contained in:
parent
d1b39f2c8e
commit
50fb5250ee
|
@ -26,8 +26,6 @@ public interface LicensesManagerService {
|
|||
|
||||
public void unregisterLicenses(final DeleteLicenseRequestHolder requestHolder, final ActionListener<ClusterStateUpdateResponse> listener);
|
||||
|
||||
public LicensesStatus checkLicenses(Set<ESLicense> licenses);
|
||||
|
||||
public Set<String> enabledFeatures();
|
||||
|
||||
public List<ESLicense> getLicenses();
|
||||
|
|
|
@ -37,6 +37,7 @@ import java.io.IOException;
|
|||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
@ -50,7 +51,6 @@ import static org.elasticsearch.license.core.ESLicenses.reduceAndMap;
|
|||
* - LicensesClientService - allow interested plugins (features) to register to licensing notifications
|
||||
* <p/>
|
||||
* TODO: documentation
|
||||
* TODO: figure out when to check GatewayService.STATE_NOT_RECOVERED_BLOCK
|
||||
*/
|
||||
@Singleton
|
||||
public class LicensesService extends AbstractLifecycleComponent<LicensesService> implements ClusterStateListener, LicensesManagerService, LicensesClientService {
|
||||
|
@ -65,9 +65,11 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
|
||||
private final TransportService transportService;
|
||||
|
||||
private List<ListenerHolder> registeredListeners = new CopyOnWriteArrayList<>();
|
||||
private final List<ListenerHolder> registeredListeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
private Queue<ListenerHolder> pendingRegistrations = new ConcurrentLinkedQueue<>();
|
||||
private final Queue<ListenerHolder> pendingListeners = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private final Queue<ScheduledFuture> scheduledNotifications = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private final AtomicReference<LicensesMetaData> lastObservedLicensesState;
|
||||
|
||||
|
@ -175,32 +177,12 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public LicensesStatus checkLicenses(Set<ESLicense> licenses) {
|
||||
final ImmutableMap<String, ESLicense> map = reduceAndMap(licenses);
|
||||
return checkLicenses(map);
|
||||
}
|
||||
|
||||
private LicensesStatus checkLicenses(Map<String, ESLicense> licenseMap) {
|
||||
LicensesStatus status = LicensesStatus.VALID;
|
||||
try {
|
||||
licenseManager.verifyLicenses(licenseMap);
|
||||
} catch (ExpiredLicenseException e) {
|
||||
status = LicensesStatus.EXPIRED;
|
||||
} catch (InvalidLicenseException e) {
|
||||
status = LicensesStatus.INVALID;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> enabledFeatures() {
|
||||
Set<String> enabledFeatures = Sets.newHashSet();
|
||||
if (registeredListeners != null) {
|
||||
for (ListenerHolder holder : registeredListeners) {
|
||||
if (holder.enabled.get()) {
|
||||
enabledFeatures.add(holder.feature);
|
||||
}
|
||||
for (ListenerHolder holder : registeredListeners) {
|
||||
if (holder.enabled.get()) {
|
||||
enabledFeatures.add(holder.feature);
|
||||
}
|
||||
}
|
||||
return enabledFeatures;
|
||||
|
@ -240,6 +222,22 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private LicensesStatus checkLicenses(Set<ESLicense> licenses) {
|
||||
final ImmutableMap<String, ESLicense> map = reduceAndMap(licenses);
|
||||
return checkLicenses(map);
|
||||
}
|
||||
|
||||
private LicensesStatus checkLicenses(Map<String, ESLicense> licenseMap) {
|
||||
LicensesStatus status = LicensesStatus.VALID;
|
||||
try {
|
||||
licenseManager.verifyLicenses(licenseMap);
|
||||
} catch (ExpiredLicenseException e) {
|
||||
status = LicensesStatus.EXPIRED;
|
||||
} catch (InvalidLicenseException e) {
|
||||
status = LicensesStatus.INVALID;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
private void registerTrialLicense(final RegisterTrialLicenseRequest request) {
|
||||
clusterService.submitStateUpdateTask("register trial license []", new ProcessedClusterStateUpdateTask() {
|
||||
|
@ -310,7 +308,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
|
||||
@Override
|
||||
protected void doStop() throws ElasticsearchException {
|
||||
// Should notificationScheduler be cancelled on stop as well?
|
||||
// Should scheduledNotifications be cancelled on stop as well?
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -318,15 +316,21 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
logger.info("Closing LicensesService");
|
||||
clusterService.remove(this);
|
||||
|
||||
if (registeredListeners != null) {
|
||||
// notify features to be disabled
|
||||
for (ListenerHolder holder : registeredListeners) {
|
||||
holder.disableFeatureIfNeeded();
|
||||
}
|
||||
// clear all handlers
|
||||
registeredListeners.clear();
|
||||
// cancel all notifications
|
||||
for (ScheduledFuture scheduledNotification : scheduledNotifications) {
|
||||
scheduledNotification.cancel(true);
|
||||
}
|
||||
|
||||
// notify features to be disabled
|
||||
for (ListenerHolder holder : registeredListeners) {
|
||||
holder.disableFeatureIfNeeded();
|
||||
}
|
||||
// clear all handlers
|
||||
registeredListeners.clear();
|
||||
|
||||
// empty out notification queue
|
||||
scheduledNotifications.clear();
|
||||
|
||||
lastObservedLicensesState.set(null);
|
||||
}
|
||||
|
||||
|
@ -338,27 +342,39 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
logLicenseMetaDataStats("old", oldLicensesMetaData);
|
||||
logLicenseMetaDataStats("new", currentLicensesMetaData);
|
||||
// Check pending feature registrations and try to complete registrations
|
||||
if (!pendingRegistrations.isEmpty()) {
|
||||
if (!pendingListeners.isEmpty()) {
|
||||
ListenerHolder pendingRegistrationLister;
|
||||
while ((pendingRegistrationLister = pendingRegistrations.poll()) != null) {
|
||||
boolean masterAvailable = registerListener(pendingRegistrationLister);
|
||||
boolean masterAvailable = false;
|
||||
while ((pendingRegistrationLister = pendingListeners.poll()) != null) {
|
||||
masterAvailable = registerListener(pendingRegistrationLister);
|
||||
logger.info("trying to register pending listener for " + pendingRegistrationLister.feature + " masterAvailable: " + masterAvailable);
|
||||
if (!masterAvailable) {
|
||||
// if the master is not available do not, break out of trying pendingRegistrations
|
||||
pendingRegistrations.add(pendingRegistrationLister);
|
||||
// if the master is not available do not, break out of trying pendingListeners
|
||||
pendingListeners.add(pendingRegistrationLister);
|
||||
break;
|
||||
} else {
|
||||
logger.info("successfully registered listener for: " + pendingRegistrationLister.feature);
|
||||
registeredListeners.add(pendingRegistrationLister);
|
||||
}
|
||||
}
|
||||
if (masterAvailable) {
|
||||
// make sure to notify new registered feature
|
||||
// notifications could have been scheduled for it before it was registered
|
||||
notifyFeaturesAndScheduleNotification(currentLicensesMetaData);
|
||||
}
|
||||
}
|
||||
|
||||
clearFinishedNotifications();
|
||||
|
||||
// notify all interested plugins
|
||||
// notifyFeaturesIfNeeded will short-circuit with -1 if the currentLicensesMetaData has been notified on earlier
|
||||
// Change to debug
|
||||
logger.info("calling notifyFeaturesAndScheduleNotificationIfNeeded from clusterChanged");
|
||||
notifyFeaturesAndScheduleNotificationIfNeeded(currentLicensesMetaData);
|
||||
if (event.previousState().blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK)) {
|
||||
notifyFeaturesAndScheduleNotification(currentLicensesMetaData);
|
||||
} else {
|
||||
notifyFeaturesAndScheduleNotificationIfNeeded(currentLicensesMetaData);
|
||||
}
|
||||
} else {
|
||||
logger.info("clusterChanged: no action [has STATE_NOT_RECOVERED_BLOCK]");
|
||||
}
|
||||
|
@ -368,8 +384,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
final LicensesMetaData lastNotifiedLicensesMetaData = lastObservedLicensesState.get();
|
||||
if (lastNotifiedLicensesMetaData != null && lastNotifiedLicensesMetaData.equals(currentLicensesMetaData)) {
|
||||
logger.info("currentLicensesMetaData has been already notified on");
|
||||
// TODO: figure out when we do not want to notify when clusterChanged() is triggered
|
||||
//return;
|
||||
return;
|
||||
}
|
||||
notifyFeaturesAndScheduleNotification(currentLicensesMetaData);
|
||||
}
|
||||
|
@ -381,6 +396,65 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
}
|
||||
}
|
||||
|
||||
private long notifyFeatures(LicensesMetaData currentLicensesMetaData) {
|
||||
long nextScheduleFrequency = -1l;
|
||||
long offset = TimeValue.timeValueMillis(100).getMillis();
|
||||
StringBuilder sb = new StringBuilder("Registered listeners: [ ");
|
||||
for (ListenerHolder listenerHolder : registeredListeners) {
|
||||
|
||||
sb.append("( ");
|
||||
sb.append("feature:");
|
||||
sb.append(listenerHolder.feature);
|
||||
sb.append(", ");
|
||||
|
||||
long expiryDate;
|
||||
if ((expiryDate = expiryDateForFeature(listenerHolder.feature, currentLicensesMetaData)) != -1l) {
|
||||
sb.append(" license expiry: ");
|
||||
sb.append(expiryDate);
|
||||
sb.append(", ");
|
||||
}
|
||||
long expiryDuration = expiryDate - System.currentTimeMillis();
|
||||
|
||||
if (expiryDate == -1l) {
|
||||
sb.append("no trial/signed license found");
|
||||
sb.append(", ");
|
||||
} else {
|
||||
sb.append("license expires in: ");
|
||||
sb.append(TimeValue.timeValueMillis(expiryDuration).toString());
|
||||
sb.append(", ");
|
||||
}
|
||||
|
||||
if (expiryDuration > 0l) {
|
||||
sb.append("calling enableFeatureIfNeeded");
|
||||
|
||||
listenerHolder.enableFeatureIfNeeded();
|
||||
if (nextScheduleFrequency == -1l) {
|
||||
nextScheduleFrequency = expiryDuration + offset;
|
||||
} else {
|
||||
nextScheduleFrequency = Math.min(expiryDuration + offset, nextScheduleFrequency);
|
||||
}
|
||||
} else {
|
||||
sb.append("calling disableFeatureIfNeeded");
|
||||
listenerHolder.disableFeatureIfNeeded();
|
||||
}
|
||||
sb.append(" )");
|
||||
}
|
||||
sb.append("]");
|
||||
// Change to debug
|
||||
logger.info(sb.toString());
|
||||
|
||||
logLicenseMetaDataStats("Setting last observed metaData", currentLicensesMetaData);
|
||||
lastObservedLicensesState.set(currentLicensesMetaData);
|
||||
|
||||
if (nextScheduleFrequency == -1l) {
|
||||
logger.info("no need to schedule next notification");
|
||||
} else {
|
||||
logger.info("next notification time: " + TimeValue.timeValueMillis(nextScheduleFrequency).toString());
|
||||
}
|
||||
|
||||
return nextScheduleFrequency;
|
||||
|
||||
}
|
||||
private void logLicenseMetaDataStats(String prefix, LicensesMetaData licensesMetaData) {
|
||||
if (licensesMetaData != null) {
|
||||
logger.info(prefix + " LicensesMetaData: signedLicenses: " + licensesMetaData.getSignatures().size() + " trialLicenses: " + licensesMetaData.getEncodedTrialLicenses().size());
|
||||
|
@ -397,7 +471,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
registeredListeners.add(listenerHolder);
|
||||
} else {
|
||||
logger.info("add listener for: " + listenerHolder.feature + " to pending registration queue");
|
||||
pendingRegistrations.add(listenerHolder);
|
||||
pendingListeners.add(listenerHolder);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -468,11 +542,6 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
return -1l;
|
||||
}
|
||||
|
||||
|
||||
private String executorName() {
|
||||
return ThreadPool.Names.GENERIC;
|
||||
}
|
||||
|
||||
private Map<String, ESLicense> getEffectiveLicenses(LicensesMetaData metaData) {
|
||||
Map<String, ESLicense> map = new HashMap<>();
|
||||
if (metaData != null) {
|
||||
|
@ -485,11 +554,29 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
|
||||
}
|
||||
|
||||
private void clearFinishedNotifications() {
|
||||
while (!scheduledNotifications.isEmpty()) {
|
||||
ScheduledFuture notification = scheduledNotifications.peek();
|
||||
if (notification.isDone()) {
|
||||
// remove the notifications that are done
|
||||
scheduledNotifications.poll();
|
||||
} else {
|
||||
// stop emptying out the queue as soon as the first undone future hits
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String executorName() {
|
||||
return ThreadPool.Names.GENERIC;
|
||||
}
|
||||
|
||||
private void scheduleNextNotification(long nextScheduleDelay) {
|
||||
clearFinishedNotifications();
|
||||
|
||||
try {
|
||||
final TimeValue delay = TimeValue.timeValueMillis(nextScheduleDelay);
|
||||
// TODO: enqueue Future for management
|
||||
threadPool.schedule(delay, executorName(), new LicensingClientNotificationJob());
|
||||
scheduledNotifications.add(threadPool.schedule(delay, executorName(), new LicensingClientNotificationJob()));
|
||||
logger.info("Scheduling next notification after: " + delay);
|
||||
} catch (EsRejectedExecutionException ex) {
|
||||
logger.info("Couldn't re-schedule licensing client notification job", ex);
|
||||
|
@ -498,8 +585,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
|
||||
public class LicensingClientNotificationJob implements Runnable {
|
||||
|
||||
public LicensingClientNotificationJob() {
|
||||
}
|
||||
public LicensingClientNotificationJob() {}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -507,76 +593,21 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
logger.trace("Performing LicensingClientNotificationJob");
|
||||
}
|
||||
|
||||
LicensesMetaData currentLicensesMetaData = clusterService.state().metaData().custom(LicensesMetaData.TYPE);
|
||||
long nextScheduleDelay = notifyFeatures(currentLicensesMetaData);
|
||||
if (nextScheduleDelay != -1l) {
|
||||
try {
|
||||
scheduleNextNotification(nextScheduleDelay);
|
||||
} catch (EsRejectedExecutionException ex) {
|
||||
logger.info("Reschedule licensing client notification job was rejected", ex);
|
||||
// next clusterChanged event will deal with the missed notifications
|
||||
if (!clusterService.state().blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK)) {
|
||||
LicensesMetaData currentLicensesMetaData = clusterService.state().metaData().custom(LicensesMetaData.TYPE);
|
||||
long nextScheduleDelay = notifyFeatures(currentLicensesMetaData);
|
||||
if (nextScheduleDelay != -1l) {
|
||||
try {
|
||||
scheduleNextNotification(nextScheduleDelay);
|
||||
} catch (EsRejectedExecutionException ex) {
|
||||
logger.info("Reschedule licensing client notification job was rejected", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long notifyFeatures(LicensesMetaData currentLicensesMetaData) {
|
||||
long nextScheduleFrequency = -1l;
|
||||
long offset = TimeValue.timeValueMillis(100).getMillis();
|
||||
StringBuilder sb = new StringBuilder("Registered listeners: [ ");
|
||||
for (ListenerHolder listenerHolder : registeredListeners) {
|
||||
|
||||
sb.append("( ");
|
||||
sb.append("feature:");
|
||||
sb.append(listenerHolder.feature);
|
||||
sb.append(", ");
|
||||
|
||||
long expiryDate;
|
||||
if ((expiryDate = expiryDateForFeature(listenerHolder.feature, currentLicensesMetaData)) != -1l) {
|
||||
sb.append(" license expiry: ");
|
||||
sb.append(expiryDate);
|
||||
sb.append(", ");
|
||||
}
|
||||
long expiryDuration = expiryDate - System.currentTimeMillis();
|
||||
|
||||
if (expiryDate == -1l) {
|
||||
sb.append("no trial/signed license found");
|
||||
sb.append(", ");
|
||||
} else {
|
||||
sb.append("license expires in: ");
|
||||
sb.append(TimeValue.timeValueMillis(expiryDuration).toString());
|
||||
sb.append(", ");
|
||||
}
|
||||
|
||||
if (expiryDuration > 0l) {
|
||||
sb.append("calling enableFeatureIfNeeded");
|
||||
|
||||
listenerHolder.enableFeatureIfNeeded();
|
||||
if (nextScheduleFrequency == -1l) {
|
||||
nextScheduleFrequency = expiryDuration + offset;
|
||||
} else {
|
||||
nextScheduleFrequency = Math.min(expiryDuration + offset, nextScheduleFrequency);
|
||||
}
|
||||
} else {
|
||||
sb.append("calling disableFeatureIfNeeded");
|
||||
listenerHolder.disableFeatureIfNeeded();
|
||||
}
|
||||
sb.append(" )");
|
||||
}
|
||||
sb.append("]");
|
||||
// Change to debug
|
||||
logger.info(sb.toString());
|
||||
|
||||
lastObservedLicensesState.set(currentLicensesMetaData);
|
||||
|
||||
if (nextScheduleFrequency == -1l) {
|
||||
logger.info("no need to schedule next notification");
|
||||
} else {
|
||||
logger.info("next notification time: " + TimeValue.timeValueMillis(nextScheduleFrequency).toString());
|
||||
}
|
||||
|
||||
return nextScheduleFrequency;
|
||||
|
||||
}
|
||||
|
||||
public static class PutLicenseRequestHolder {
|
||||
private final PutLicenseRequest request;
|
||||
|
@ -708,9 +739,4 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
return ThreadPool.Names.SAME;
|
||||
}
|
||||
}
|
||||
|
||||
//Should not be exposed; used by testing only
|
||||
public void clear() {
|
||||
registeredListeners.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,36 +5,30 @@
|
|||
*/
|
||||
package org.elasticsearch.license.plugin;
|
||||
|
||||
import org.elasticsearch.action.ActionFuture;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.ClusterAdminClient;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.license.TestUtils;
|
||||
import org.elasticsearch.license.core.ESLicense;
|
||||
import org.elasticsearch.license.core.ESLicenses;
|
||||
import org.elasticsearch.license.plugin.action.get.GetLicenseRequestBuilder;
|
||||
import org.elasticsearch.license.plugin.action.get.GetLicenseResponse;
|
||||
import org.elasticsearch.license.plugin.action.put.PutLicenseRequestBuilder;
|
||||
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
|
||||
import org.elasticsearch.license.plugin.core.LicensesStatus;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.SUITE;
|
||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.TEST;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
|
||||
@ClusterScope(scope = SUITE, numDataNodes = 0)
|
||||
@ClusterScope(scope = TEST, numDataNodes = 0)
|
||||
public class LicensesServiceClusterRestartTest extends AbstractLicensesIntegrationTests {
|
||||
|
||||
static String priKeyPath;
|
||||
static String pubKeyPath;
|
||||
|
||||
@Override
|
||||
protected Settings transportClientSettings() {
|
||||
return super.transportClientSettings();
|
||||
|
@ -49,71 +43,47 @@ public class LicensesServiceClusterRestartTest extends AbstractLicensesIntegrati
|
|||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
priKeyPath = Paths.get(LicensesServiceClusterRestartTest.class.getResource("/private.key").toURI()).toAbsolutePath().toString();
|
||||
pubKeyPath = Paths.get(LicensesServiceClusterRestartTest.class.getResource("/public.key").toURI()).toAbsolutePath().toString();
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
wipeAllLicenses();
|
||||
}
|
||||
|
||||
logger.info("--> starting 1 nodes");
|
||||
String node1 = internalCluster().startNode();
|
||||
@Test
|
||||
public void testClusterRestart() throws Exception {
|
||||
logger.info("--> starting 1 node");
|
||||
internalCluster().startNode();
|
||||
ensureGreen();
|
||||
wipeAllLicenses();
|
||||
|
||||
final List<ESLicense> esLicenses = putLicense(node1);
|
||||
final Client startNodeClient = internalCluster().startNodeClient(settingsBuilder().build());
|
||||
//TODO: just pass node name instead
|
||||
getAndCheckLicense(startNodeClient, esLicenses);
|
||||
|
||||
logger.info("--> cluster state before full cluster restart");
|
||||
ClusterState clusterState = clusterService().state();
|
||||
logger.info("Cluster state: {}", clusterState);
|
||||
|
||||
final List<ESLicense> esLicenses = generateAndPutLicense();
|
||||
getAndCheckLicense(esLicenses);
|
||||
logger.info("--> restart all nodes");
|
||||
internalCluster().fullRestart();
|
||||
ensureYellow();
|
||||
|
||||
logger.info("--> cluster state after full cluster restart");
|
||||
clusterState = client().admin().cluster().prepareState().get().getState();
|
||||
logger.info("Cluster state: {}", clusterState);
|
||||
|
||||
getAndCheckLicense(internalCluster().startNodeClient(settingsBuilder().build()), esLicenses);
|
||||
getAndCheckLicense(esLicenses);
|
||||
}
|
||||
|
||||
private List<ESLicense> putLicense(String node) throws Exception {
|
||||
|
||||
final ClusterAdminClient cluster = internalCluster().client(node).admin().cluster();
|
||||
|
||||
Map<String, TestUtils.FeatureAttributes> map = new HashMap<>();
|
||||
TestUtils.FeatureAttributes featureAttributes =
|
||||
new TestUtils.FeatureAttributes("shield", "subscription", "platinum", "foo bar Inc.", "elasticsearch", 2, "2014-12-13", "2015-12-13");
|
||||
map.put(TestUtils.SHIELD, featureAttributes);
|
||||
String licenseString = TestUtils.generateESLicenses(map);
|
||||
String licenseOutput = TestUtils.runLicenseGenerationTool(licenseString, pubKeyPath, priKeyPath);
|
||||
|
||||
private List<ESLicense> generateAndPutLicense() throws Exception {
|
||||
ClusterAdminClient cluster = internalCluster().client().admin().cluster();
|
||||
ESLicense license = generateSignedLicense("shield", TimeValue.timeValueMinutes(1));
|
||||
PutLicenseRequestBuilder putLicenseRequestBuilder = new PutLicenseRequestBuilder(cluster);
|
||||
final List<ESLicense> putLicenses = ESLicenses.fromSource(licenseOutput);
|
||||
assertThat(putLicenses.size(), equalTo(1));
|
||||
final List<ESLicense> putLicenses = Arrays.asList(license);
|
||||
putLicenseRequestBuilder.setLicense(putLicenses);
|
||||
ensureGreen();
|
||||
|
||||
final ActionFuture<PutLicenseResponse> putLicenseFuture = putLicenseRequestBuilder.execute();
|
||||
final PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.execute().get();
|
||||
|
||||
final PutLicenseResponse putLicenseResponse = putLicenseFuture.get();
|
||||
assertTrue(putLicenseResponse.isAcknowledged());
|
||||
assertThat(putLicenseResponse.isAcknowledged(), equalTo(true));
|
||||
assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID));
|
||||
|
||||
return putLicenses;
|
||||
}
|
||||
|
||||
private void getAndCheckLicense(Client client, List<ESLicense> license) {
|
||||
final ClusterAdminClient cluster = client.admin().cluster();
|
||||
private void getAndCheckLicense(List<ESLicense> license) {
|
||||
ClusterAdminClient cluster = internalCluster().client().admin().cluster();
|
||||
final GetLicenseResponse response = new GetLicenseRequestBuilder(cluster).get();
|
||||
assertThat(response.licenses().size(), equalTo(1));
|
||||
TestUtils.isSame(license, response.licenses());
|
||||
}
|
||||
|
||||
private ImmutableSettings.Builder settingsBuilder() {
|
||||
return ImmutableSettings.settingsBuilder()
|
||||
.put("gateway.type", "local")
|
||||
.put("plugin.types", LicensePlugin.class.getName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public class LicensesServiceNodeTests extends AbstractLicensesIntegrationTests {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
}, 1, TimeUnit.MINUTES), equalTo(true));
|
||||
}, 10, TimeUnit.SECONDS), equalTo(true));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomFrom;
|
||||
import static org.elasticsearch.license.plugin.core.LicensesService.LicensesUpdateResponse;
|
||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.TEST;
|
||||
|
@ -41,7 +42,6 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
|
|||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
wipeAllLicenses();
|
||||
clear();
|
||||
|
||||
DiscoveryNodes discoveryNodes = LicensesServiceTests.masterClusterService().state().getNodes();
|
||||
Set<String> dataNodeSet = new HashSet<>();
|
||||
|
@ -117,21 +117,19 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
|
|||
// multiple client registration with null trial license and then different expiry signed license
|
||||
|
||||
final LicensesManagerService masterLicensesManagerService = masterLicensesManagerService();
|
||||
final List<LicensesService> licensesServices = licensesServices(2);
|
||||
assertThat(licensesServices.size(), equalTo(2));
|
||||
final LicensesService licensesService = randomLicensesService();
|
||||
final TestTrackingClientListener clientListener1 = new TestTrackingClientListener();
|
||||
final TestTrackingClientListener clientListener2 = new TestTrackingClientListener();
|
||||
|
||||
List<Action> firstClientActions = new ArrayList<>();
|
||||
List<Action> secondClientActions = new ArrayList<>();
|
||||
|
||||
final TimeValue firstExpiryDuration = TimeValue.timeValueSeconds(2);
|
||||
firstClientActions.add(registerWithoutTrialLicense(licensesServices.get(0), clientListener1, "feature1"));
|
||||
firstClientActions.add(registerWithoutTrialLicense(licensesService, clientListener1, "feature1"));
|
||||
firstClientActions.add(generateAndPutSignedLicenseAction(masterLicensesManagerService, "feature1", firstExpiryDuration));
|
||||
firstClientActions.add(assertExpiryAction("signed", firstExpiryDuration));
|
||||
|
||||
final TimeValue secondExpiryDuration = TimeValue.timeValueSeconds(1);
|
||||
secondClientActions.add(registerWithoutTrialLicense(licensesServices.get(1), clientListener2, "feature2"));
|
||||
secondClientActions.add(registerWithoutTrialLicense(licensesService, clientListener2, "feature2"));
|
||||
secondClientActions.add(generateAndPutSignedLicenseAction(masterLicensesManagerService, "feature2", secondExpiryDuration));
|
||||
secondClientActions.add(assertExpiryAction("signed", secondExpiryDuration));
|
||||
|
||||
|
@ -149,24 +147,19 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
|
|||
// multiple client registration: one with trial license and another with signed license (different expiry duration)
|
||||
|
||||
final LicensesManagerService masterLicensesManagerService = masterLicensesManagerService();
|
||||
final List<LicensesService> licensesServices = licensesServices(2);
|
||||
assertThat(licensesServices.size(), equalTo(2));
|
||||
final LicensesService licensesService = randomLicensesService();
|
||||
final TestTrackingClientListener clientListener1 = new TestTrackingClientListener();
|
||||
final TestTrackingClientListener clientListener2 = new TestTrackingClientListener();
|
||||
|
||||
List<Action> firstClientActions = new ArrayList<>();
|
||||
List<Action> secondClientActions = new ArrayList<>();
|
||||
|
||||
firstClientActions.add(registerWithoutTrialLicense(licensesServices.get(0), clientListener1, "feature1"));
|
||||
|
||||
final TimeValue firstExpiryDuration = TimeValue.timeValueSeconds(2);
|
||||
firstClientActions.add(registerWithoutTrialLicense(licensesService, clientListener1, "feature1"));
|
||||
firstClientActions.add(generateAndPutSignedLicenseAction(masterLicensesManagerService, "feature1", firstExpiryDuration));
|
||||
|
||||
firstClientActions.add(assertExpiryAction("signed", firstExpiryDuration));
|
||||
|
||||
final TimeValue secondExpiryDuration = TimeValue.timeValueSeconds(1);
|
||||
secondClientActions.add(registerWithTrialLicense(licensesServices.get(1), clientListener2, "feature2", secondExpiryDuration));
|
||||
|
||||
secondClientActions.add(registerWithTrialLicense(licensesService, clientListener2, "feature2", secondExpiryDuration));
|
||||
secondClientActions.add(assertExpiryAction("trial", secondExpiryDuration));
|
||||
|
||||
if (randomBoolean()) {
|
||||
|
@ -182,22 +175,18 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
|
|||
public void testMultipleClientTrialLicenseRegistration() throws Exception {
|
||||
// multiple client registration: both with trail license of different expiryDuration
|
||||
|
||||
final List<LicensesService> licensesServices = licensesServices(2);
|
||||
assertThat(licensesServices.size(), equalTo(2));
|
||||
final LicensesService licensesService = randomLicensesService();
|
||||
final TestTrackingClientListener clientListener1 = new TestTrackingClientListener();
|
||||
final TestTrackingClientListener clientListener2 = new TestTrackingClientListener();
|
||||
|
||||
List<Action> firstClientActions = new ArrayList<>();
|
||||
List<Action> secondClientActions = new ArrayList<>();
|
||||
|
||||
TimeValue firstExpiryDuration = TimeValue.timeValueSeconds(1);
|
||||
firstClientActions.add(registerWithTrialLicense(licensesServices.get(0), clientListener1, "feature1", firstExpiryDuration));
|
||||
|
||||
firstClientActions.add(registerWithTrialLicense(licensesService, clientListener1, "feature1", firstExpiryDuration));
|
||||
firstClientActions.add(assertExpiryAction("trial", firstExpiryDuration));
|
||||
|
||||
TimeValue secondExpiryDuration = TimeValue.timeValueSeconds(2);
|
||||
secondClientActions.add(registerWithTrialLicense(licensesServices.get(1), clientListener2, "feature2", secondExpiryDuration));
|
||||
|
||||
secondClientActions.add(registerWithTrialLicense(licensesService, clientListener2, "feature2", secondExpiryDuration));
|
||||
secondClientActions.add(assertExpiryAction("trial", secondExpiryDuration));
|
||||
|
||||
if (randomBoolean()) {
|
||||
|
@ -229,19 +218,22 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
|
|||
TimeValue expiryDuration = TimeValue.timeValueSeconds(2);
|
||||
actions.add(registerWithTrialLicense(clientService, clientListener, "feature1", expiryDuration));
|
||||
actions.add(assertExpiryAction("trial", expiryDuration));
|
||||
|
||||
assertClientListenerNotificationCount(clientListener, actions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRandomMultipleClientMultipleFeature() throws Exception {
|
||||
List<LicensesService> licensesServices = licensesServices(10);
|
||||
LicensesService licensesService = randomLicensesService();
|
||||
LicensesManagerService masterLicensesManagerService = masterLicensesManagerService();
|
||||
Map<TestTrackingClientListener, List<Action>> clientListenersWithActions = new HashMap<>();
|
||||
for (LicensesService licensesService : licensesServices) {
|
||||
|
||||
for (int i = 0; i < randomIntBetween(3, 10); i++) {
|
||||
final TestTrackingClientListener clientListener = new TestTrackingClientListener();
|
||||
String feature = randomRealisticUnicodeOfCodepointLengthBetween(2, 10);
|
||||
TimeValue expiryDuration = TimeValue.timeValueSeconds(randomIntBetween(1, 5));
|
||||
List<Action> actions = new ArrayList<>();
|
||||
|
||||
if (randomBoolean()) {
|
||||
actions.add(registerWithTrialLicense(licensesService, clientListener, feature, expiryDuration));
|
||||
actions.add(assertExpiryAction("trial", expiryDuration));
|
||||
|
@ -323,8 +315,7 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
|
|||
private Action assertExpiryAction(String licenseType, TimeValue expiryDuration) {
|
||||
return new Action(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
}
|
||||
public void run() {}
|
||||
}, 1, 0, TimeValue.timeValueMillis(expiryDuration.getMillis() * 2),
|
||||
"should trigger onDisable once [" + licenseType + " license expiry]");
|
||||
}
|
||||
|
@ -408,35 +399,13 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
|
|||
return internalCluster().getInstance(LicensesClientService.class, node);
|
||||
}
|
||||
|
||||
private List<LicensesService> licensesServices(int count) {
|
||||
List<LicensesService> licensesServices = new ArrayList<>(count);
|
||||
Set<String> selectedNodes = new HashSet<>();
|
||||
selectedNodes.add(node);
|
||||
licensesServices.add(internalCluster().getInstance(LicensesService.class, node));
|
||||
for (int i = 0; i < Math.min(count - 1, nodes.length - 1); i++) {
|
||||
while (true) {
|
||||
String newNode = randomFrom(nodes);
|
||||
if (!selectedNodes.contains(newNode)) {
|
||||
licensesServices.add(internalCluster().getInstance(LicensesService.class, newNode));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return licensesServices;
|
||||
private LicensesService randomLicensesService() {
|
||||
String randomNode = randomFrom(nodes);
|
||||
return internalCluster().getInstance(LicensesService.class, randomNode);
|
||||
}
|
||||
|
||||
private static ClusterService masterClusterService() {
|
||||
final InternalTestCluster clients = internalCluster();
|
||||
return clients.getInstance(ClusterService.class, clients.getMasterName());
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
final InternalTestCluster clients = internalCluster();
|
||||
LicensesService masterService = clients.getInstance(LicensesService.class, clients.getMasterName());
|
||||
masterService.clear();
|
||||
if (node != null) {
|
||||
LicensesService nodeService = clients.getInstance(LicensesService.class, node);
|
||||
nodeService.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue