Make LicensesService tests more robust
- split out LicensesManagerService & LicensesClientService tests - add removeLicenses tests - other refactoring Original commit: elastic/x-pack-elasticsearch@a47dc586d7
This commit is contained in:
parent
42d47a1bcc
commit
8e9574a925
2
pom.xml
2
pom.xml
|
@ -15,7 +15,7 @@
|
|||
</parent>
|
||||
|
||||
<properties>
|
||||
<elasticsearch.version>1.4.0-SNAPSHOT</elasticsearch.version>
|
||||
<elasticsearch.version>1.4.0</elasticsearch.version>
|
||||
<lucene.version>4.10.2</lucene.version>
|
||||
<!-- TODO: do we want to always enforce non-default keys -->
|
||||
<keys.path>${basedir}/src/test/resources</keys.path>
|
||||
|
|
|
@ -30,7 +30,7 @@ import java.util.Set;
|
|||
|
||||
public class ESLicenseSigner {
|
||||
|
||||
public static String DEFAULT_PASS_PHRASE = "elasticsearch-license";
|
||||
public final static String DEFAULT_PASS_PHRASE = "elasticsearch-license";
|
||||
|
||||
private final static int VERSION_START = 0;
|
||||
private final static int VERSION = VERSION_START;
|
||||
|
|
|
@ -43,7 +43,7 @@ public class KeyPairGeneratorTool extends CliTool {
|
|||
|
||||
private static class KeyPairGenerator extends Command {
|
||||
|
||||
public static String DEFAULT_PASS_PHRASE = "elasticsearch-license";
|
||||
public static final String DEFAULT_PASS_PHRASE = "elasticsearch-license";
|
||||
private static final String NAME = "key-pair-generator";
|
||||
private static final CliToolConfig.Cmd CMD = cmd(NAME, KeyPairGenerator.class)
|
||||
.options(
|
||||
|
|
|
@ -76,9 +76,9 @@ public class LicenseGeneratorTool extends CliTool {
|
|||
String[] licenseSpecSources = commandLine.getOptionValues("license");
|
||||
String[] licenseSpecSourceFiles = commandLine.getOptionValues("licenseFile");
|
||||
|
||||
if (!exists(privateKeyPath)) {
|
||||
if (doesNotExist(privateKeyPath)) {
|
||||
return exitCmd(ExitStatus.USAGE, terminal, privateKeyPath + " does not exist");
|
||||
} else if (!exists(publicKeyPath)) {
|
||||
} else if (doesNotExist(publicKeyPath)) {
|
||||
return exitCmd(ExitStatus.USAGE, terminal, publicKeyPath + " does not exist");
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ public class LicenseGeneratorTool extends CliTool {
|
|||
if (licenseSpecSourceFiles != null) {
|
||||
for (String licenseSpecFilePath : licenseSpecSourceFiles) {
|
||||
Path licenseSpecPath = Paths.get(licenseSpecFilePath);
|
||||
if (!exists(licenseSpecFilePath)) {
|
||||
if (doesNotExist(licenseSpecFilePath)) {
|
||||
return exitCmd(ExitStatus.USAGE, terminal, licenseSpecFilePath + " does not exist");
|
||||
}
|
||||
licenseSpecs.addAll(ESLicenses.fromSource(Files.readAllBytes(licenseSpecPath), false));
|
||||
|
@ -122,8 +122,8 @@ public class LicenseGeneratorTool extends CliTool {
|
|||
}
|
||||
|
||||
|
||||
private static boolean exists(String filePath) {
|
||||
return new File(filePath).exists();
|
||||
private static boolean doesNotExist(String filePath) {
|
||||
return !new File(filePath).exists();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
}
|
||||
|
||||
public static class LicensesUpdateResponse extends ClusterStateUpdateResponse {
|
||||
private LicensesStatus status;
|
||||
private final LicensesStatus status;
|
||||
|
||||
public LicensesUpdateResponse(boolean acknowledged, LicensesStatus status) {
|
||||
super(acknowledged);
|
||||
|
|
|
@ -12,7 +12,7 @@ public enum LicensesStatus {
|
|||
INVALID((byte) 1),
|
||||
EXPIRED((byte) 2);
|
||||
|
||||
private byte id;
|
||||
private final byte id;
|
||||
|
||||
LicensesStatus(byte id) {
|
||||
this.id = id;
|
||||
|
|
|
@ -30,6 +30,7 @@ import static org.elasticsearch.license.licensor.tools.LicenseGeneratorTool.Comm
|
|||
import static org.elasticsearch.license.licensor.tools.LicenseGeneratorTool.LicenseGenerator;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.core.IsEqual.equalTo;
|
||||
|
||||
public class LicenseGenerationToolTests extends CliToolTestCase {
|
||||
|
@ -134,13 +135,14 @@ public class LicenseGenerationToolTests extends CliToolTestCase {
|
|||
@Test
|
||||
public void testParsingMultipleLicense() throws Exception {
|
||||
int n = randomIntBetween(2, 5);
|
||||
List<LicenseSpec> inputLicenseSpecs = new ArrayList<>();
|
||||
Map<String, LicenseSpec> inputLicenseSpecs = new HashMap<>();
|
||||
for (int i = 0; i < n; i++) {
|
||||
inputLicenseSpecs.add(generateRandomLicenseSpec());
|
||||
LicenseSpec licenseSpec = generateRandomLicenseSpec();
|
||||
inputLicenseSpecs.put(licenseSpec.feature, licenseSpec);
|
||||
}
|
||||
LicenseGeneratorTool licenseGeneratorTool = new LicenseGeneratorTool();
|
||||
Command command = licenseGeneratorTool.parse(LicenseGeneratorTool.NAME,
|
||||
args("--license " + generateESLicenseSpecString(inputLicenseSpecs)
|
||||
args("--license " + generateESLicenseSpecString(new ArrayList<>(inputLicenseSpecs.values()))
|
||||
+ " --publicKeyPath " + pubKeyPath
|
||||
+ " --privateKeyPath " + priKeyPath));
|
||||
|
||||
|
@ -148,44 +150,33 @@ public class LicenseGenerationToolTests extends CliToolTestCase {
|
|||
LicenseGenerator licenseGenerator = (LicenseGenerator) command;
|
||||
assertThat(licenseGenerator.publicKeyFilePath, equalTo(pubKeyPath));
|
||||
assertThat(licenseGenerator.privateKeyFilePath, equalTo(priKeyPath));
|
||||
assertThat(licenseGenerator.licenseSpecs.size(), equalTo(n));
|
||||
assertThat(licenseGenerator.licenseSpecs.size(), equalTo(inputLicenseSpecs.size()));
|
||||
|
||||
for (LicenseSpec inputSpec : inputLicenseSpecs) {
|
||||
boolean found = false;
|
||||
for (ESLicense outputSpec : licenseGenerator.licenseSpecs) {
|
||||
if (inputSpec.uid.equals(outputSpec.uid())) {
|
||||
assertLicenseSpec(inputSpec, outputSpec);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertThat(found, equalTo(true));
|
||||
for (ESLicense outputLicenseSpec : licenseGenerator.licenseSpecs) {
|
||||
LicenseSpec inputLicenseSpec = inputLicenseSpecs.get(outputLicenseSpec.feature());
|
||||
assertThat(inputLicenseSpec, notNullValue());
|
||||
assertLicenseSpec(inputLicenseSpec, outputLicenseSpec);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTool() throws Exception {
|
||||
int n = randomIntBetween(1, 5);
|
||||
List<LicenseSpec> inputLicenseSpecs = new ArrayList<>();
|
||||
Map<String, LicenseSpec> inputLicenseSpecs = new HashMap<>();
|
||||
for (int i = 0; i < n; i++) {
|
||||
inputLicenseSpecs.add(generateRandomLicenseSpec());
|
||||
LicenseSpec licenseSpec = generateRandomLicenseSpec();
|
||||
inputLicenseSpecs.put(licenseSpec.feature, licenseSpec);
|
||||
}
|
||||
List<ESLicense> licenseSpecs = ESLicenses.fromSource(generateESLicenseSpecString(inputLicenseSpecs).getBytes(StandardCharsets.UTF_8), false);
|
||||
List<ESLicense> licenseSpecs = ESLicenses.fromSource(generateESLicenseSpecString(new ArrayList<>(inputLicenseSpecs.values())).getBytes(StandardCharsets.UTF_8), false);
|
||||
|
||||
String output = runLicenseGenerationTool(pubKeyPath, priKeyPath, new HashSet<>(licenseSpecs), ExitStatus.OK);
|
||||
List<ESLicense> outputLicenses = ESLicenses.fromSource(output.getBytes(StandardCharsets.UTF_8), true);
|
||||
assertThat(outputLicenses.size(), equalTo(n));
|
||||
assertThat(outputLicenses.size(), equalTo(inputLicenseSpecs.size()));
|
||||
|
||||
for (LicenseSpec inputSpec : inputLicenseSpecs) {
|
||||
boolean found = false;
|
||||
for (ESLicense license : outputLicenses) {
|
||||
if (inputSpec.uid.equals(license.uid())) {
|
||||
assertLicenseSpec(inputSpec, license);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertThat(found, equalTo(true));
|
||||
for (ESLicense outputLicense : outputLicenses) {
|
||||
LicenseSpec inputLicenseSpec = inputLicenseSpecs.get(outputLicense.feature());
|
||||
assertThat(inputLicenseSpec, notNullValue());
|
||||
assertLicenseSpec(inputLicenseSpec, outputLicense);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,16 +25,14 @@ import org.junit.rules.TemporaryFolder;
|
|||
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static org.elasticsearch.common.cli.CliTool.Command;
|
||||
import static org.elasticsearch.common.cli.CliTool.ExitStatus;
|
||||
import static org.elasticsearch.license.AbstractLicensingTestBase.generateSignedLicense;
|
||||
import static org.elasticsearch.license.licensor.tools.LicenseVerificationTool.LicenseVerifier;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.core.IsEqual.equalTo;
|
||||
|
||||
public class LicenseVerificationToolTests extends CliToolTestCase {
|
||||
|
@ -85,14 +83,15 @@ public class LicenseVerificationToolTests extends CliToolTestCase {
|
|||
@Test
|
||||
public void testParsingMultipleLicense() throws Exception {
|
||||
int n = randomIntBetween(2, 5);
|
||||
Set<ESLicense> inputLicenses = new HashSet<>();
|
||||
Map<String, ESLicense> inputLicenses = new HashMap<>();
|
||||
for (int i = 0; i < n; i++) {
|
||||
inputLicenses.add(generateSignedLicense(randomRealisticUnicodeOfCodepointLengthBetween(5, 15),
|
||||
TimeValue.timeValueHours(1)));
|
||||
ESLicense esLicense = generateSignedLicense(randomRealisticUnicodeOfCodepointLengthBetween(5, 15),
|
||||
TimeValue.timeValueHours(1));
|
||||
inputLicenses.put(esLicense.feature(), esLicense);
|
||||
}
|
||||
|
||||
StringBuilder argsBuilder = new StringBuilder();
|
||||
for (ESLicense inputLicense : inputLicenses) {
|
||||
for (ESLicense inputLicense : inputLicenses.values()) {
|
||||
argsBuilder.append(" --license ")
|
||||
.append(dumpLicense(inputLicense));
|
||||
}
|
||||
|
@ -101,44 +100,33 @@ public class LicenseVerificationToolTests extends CliToolTestCase {
|
|||
|
||||
assertThat(command, instanceOf(LicenseVerifier.class));
|
||||
LicenseVerifier licenseVerifier = (LicenseVerifier) command;
|
||||
assertThat(licenseVerifier.licenses.size(), equalTo(n));
|
||||
assertThat(licenseVerifier.licenses.size(), equalTo(inputLicenses.size()));
|
||||
|
||||
for (ESLicense inputLicense : inputLicenses) {
|
||||
boolean found = false;
|
||||
for (ESLicense outputLicense : licenseVerifier.licenses) {
|
||||
if (inputLicense.uid().equals(outputLicense.uid())) {
|
||||
ESLicense inputLicense = inputLicenses.get(outputLicense.feature());
|
||||
assertThat(inputLicense, notNullValue());
|
||||
TestUtils.isSame(inputLicense, outputLicense);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertThat(found, equalTo(true));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToolSimple() throws Exception {
|
||||
int n = randomIntBetween(2, 5);
|
||||
Set<ESLicense> inputLicenses = new HashSet<>();
|
||||
Map<String, ESLicense> inputLicenses = new HashMap<>();
|
||||
for (int i = 0; i < n; i++) {
|
||||
inputLicenses.add(generateSignedLicense(randomRealisticUnicodeOfCodepointLengthBetween(5, 15),
|
||||
TimeValue.timeValueHours(1)));
|
||||
ESLicense esLicense = generateSignedLicense(randomRealisticUnicodeOfCodepointLengthBetween(5, 15),
|
||||
TimeValue.timeValueHours(1));
|
||||
inputLicenses.put(esLicense.feature(), esLicense);
|
||||
}
|
||||
|
||||
String output = runLicenseVerificationTool(inputLicenses, ExitStatus.OK);
|
||||
String output = runLicenseVerificationTool(new HashSet<>(inputLicenses.values()), ExitStatus.OK);
|
||||
List<ESLicense> outputLicenses = ESLicenses.fromSource(output.getBytes(StandardCharsets.UTF_8), true);
|
||||
assertThat(outputLicenses.size(), equalTo(n));
|
||||
assertThat(outputLicenses.size(), equalTo(inputLicenses.size()));
|
||||
|
||||
for (ESLicense inputLicense : inputLicenses) {
|
||||
boolean found = false;
|
||||
for (ESLicense outputLicense : outputLicenses) {
|
||||
if (inputLicense.uid().equals(outputLicense.uid())) {
|
||||
ESLicense inputLicense = inputLicenses.get(outputLicense.feature());
|
||||
assertThat(inputLicense, notNullValue());
|
||||
TestUtils.isSame(inputLicense, outputLicense);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertThat(found, equalTo(true));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.license.plugin;
|
||||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.cluster.ClusterChangedEvent;
|
||||
import org.elasticsearch.cluster.ClusterService;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNodes;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.license.core.ESLicense;
|
||||
import org.elasticsearch.license.plugin.action.put.PutLicenseRequest;
|
||||
import org.elasticsearch.license.plugin.core.LicensesClientService;
|
||||
import org.elasticsearch.license.plugin.core.LicensesManagerService;
|
||||
import org.elasticsearch.license.plugin.core.LicensesService;
|
||||
import org.elasticsearch.license.plugin.core.LicensesStatus;
|
||||
import org.elasticsearch.test.InternalTestCluster;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.elasticsearch.license.plugin.core.LicensesService.LicensesUpdateResponse;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
public class AbstractLicensesServiceTests extends AbstractLicensesIntegrationTests {
|
||||
|
||||
private static String node = null;
|
||||
private static String[] nodes;
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
wipeAllLicenses();
|
||||
|
||||
DiscoveryNodes discoveryNodes = masterClusterService().state().getNodes();
|
||||
Set<String> dataNodeSet = new HashSet<>();
|
||||
for (DiscoveryNode discoveryNode : discoveryNodes) {
|
||||
if (discoveryNode.dataNode()) {
|
||||
dataNodeSet.add(discoveryNode.getName());
|
||||
}
|
||||
}
|
||||
nodes = dataNodeSet.toArray(new String[dataNodeSet.size()]);
|
||||
node = nodes[randomIntBetween(0, nodes.length - 1)];
|
||||
}
|
||||
|
||||
protected void registerAndAckSignedLicenses(final LicensesManagerService masterLicensesManagerService, final List<ESLicense> license, final LicensesStatus expectedStatus) {
|
||||
PutLicenseRequest putLicenseRequest = new PutLicenseRequest().licenses(license);
|
||||
LicensesService.PutLicenseRequestHolder requestHolder = new LicensesService.PutLicenseRequestHolder(putLicenseRequest, "test");
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final AtomicBoolean success = new AtomicBoolean(false);
|
||||
masterLicensesManagerService.registerLicenses(requestHolder, new ActionListener<LicensesUpdateResponse>() {
|
||||
@Override
|
||||
public void onResponse(LicensesUpdateResponse licensesUpdateResponse) {
|
||||
if (licensesUpdateResponse.isAcknowledged() && licensesUpdateResponse.status() == expectedStatus) {
|
||||
success.set(true);
|
||||
}
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable e) {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
assertThat("register license(s) failed", success.get(), equalTo(true));
|
||||
}
|
||||
|
||||
protected Action registerWithTrialLicense(final LicensesClientService clientService, final LicensesClientService.Listener clientListener, final String feature, final TimeValue expiryDuration) {
|
||||
return new Action(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
clientService.register(feature, new LicensesService.TrialLicenseOptions(expiryDuration, 10),
|
||||
clientListener);
|
||||
|
||||
// invoke clusterChanged event to flush out pendingRegistration
|
||||
LicensesService licensesService = (LicensesService) clientService;
|
||||
ClusterChangedEvent event = new ClusterChangedEvent("", clusterService().state(), clusterService().state());
|
||||
licensesService.clusterChanged(event);
|
||||
}
|
||||
}, 0, 1, "should trigger onEnable for " + feature + " once [trial license]");
|
||||
}
|
||||
|
||||
protected class TestTrackingClientListener implements LicensesClientService.Listener {
|
||||
CountDownLatch enableLatch;
|
||||
CountDownLatch disableLatch;
|
||||
|
||||
final boolean track;
|
||||
|
||||
public TestTrackingClientListener(boolean track) {
|
||||
this.track = track;
|
||||
}
|
||||
|
||||
public TestTrackingClientListener() {
|
||||
this(true);
|
||||
}
|
||||
|
||||
public synchronized void latch(CountDownLatch enableLatch, CountDownLatch disableLatch) {
|
||||
this.enableLatch = enableLatch;
|
||||
this.disableLatch = disableLatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled() {
|
||||
if (track) {
|
||||
this.enableLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisabled() {
|
||||
if (track) {
|
||||
this.disableLatch.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected class Action {
|
||||
final int expectedDisabledCount;
|
||||
final int expectedEnabledCount;
|
||||
final TimeValue timeout;
|
||||
final Runnable action;
|
||||
final String msg;
|
||||
|
||||
protected Action(Runnable action, int expectedEnabledCount, int expectedDisabledCount, String msg) {
|
||||
this(action, expectedEnabledCount, expectedDisabledCount, TimeValue.timeValueSeconds(1), msg);
|
||||
}
|
||||
|
||||
protected Action(Runnable action, int expectedDisabledCount, int expectedEnabledCount, TimeValue timeout, String msg) {
|
||||
this.expectedDisabledCount = expectedDisabledCount;
|
||||
this.expectedEnabledCount = expectedEnabledCount;
|
||||
this.action = action;
|
||||
this.timeout = timeout;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
action.run();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected LicensesManagerService masterLicensesManagerService() {
|
||||
final InternalTestCluster clients = internalCluster();
|
||||
return clients.getInstance(LicensesManagerService.class, clients.getMasterName());
|
||||
}
|
||||
|
||||
protected LicensesClientService licensesClientService() {
|
||||
return internalCluster().getInstance(LicensesClientService.class, node);
|
||||
}
|
||||
|
||||
protected LicensesService randomLicensesService() {
|
||||
String randomNode = randomFrom(nodes);
|
||||
return internalCluster().getInstance(LicensesService.class, randomNode);
|
||||
}
|
||||
|
||||
protected static ClusterService masterClusterService() {
|
||||
final InternalTestCluster clients = internalCluster();
|
||||
return clients.getInstance(ClusterService.class, clients.getMasterName());
|
||||
}
|
||||
}
|
|
@ -5,98 +5,26 @@
|
|||
*/
|
||||
package org.elasticsearch.license.plugin;
|
||||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.cluster.ClusterChangedEvent;
|
||||
import org.elasticsearch.cluster.ClusterService;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNodes;
|
||||
import org.elasticsearch.common.collect.ImmutableSet;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.license.TestUtils;
|
||||
import org.elasticsearch.license.core.ESLicense;
|
||||
import org.elasticsearch.license.manager.ESLicenseManager;
|
||||
import org.elasticsearch.license.plugin.action.put.PutLicenseRequest;
|
||||
import org.elasticsearch.license.plugin.core.*;
|
||||
import org.elasticsearch.test.InternalTestCluster;
|
||||
import org.junit.Before;
|
||||
import org.elasticsearch.license.plugin.core.LicensesClientService;
|
||||
import org.elasticsearch.license.plugin.core.LicensesManagerService;
|
||||
import org.elasticsearch.license.plugin.core.LicensesService;
|
||||
import org.elasticsearch.license.plugin.core.LicensesStatus;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import static org.elasticsearch.license.plugin.core.LicensesService.LicensesUpdateResponse;
|
||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.TEST;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
@ClusterScope(scope = TEST, numDataNodes = 10)
|
||||
public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
|
||||
|
||||
private static String node = null;
|
||||
private static String[] nodes;
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
wipeAllLicenses();
|
||||
|
||||
DiscoveryNodes discoveryNodes = LicensesServiceTests.masterClusterService().state().getNodes();
|
||||
Set<String> dataNodeSet = new HashSet<>();
|
||||
for (DiscoveryNode discoveryNode : discoveryNodes) {
|
||||
if (discoveryNode.dataNode()) {
|
||||
dataNodeSet.add(discoveryNode.getName());
|
||||
}
|
||||
}
|
||||
nodes = dataNodeSet.toArray(new String[dataNodeSet.size()]);
|
||||
node = nodes[randomIntBetween(0, nodes.length - 1)];
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoreAndGetLicenses() throws Exception {
|
||||
LicensesManagerService licensesManagerService = masterLicensesManagerService();
|
||||
ESLicense shieldShortLicense = generateSignedLicense("shield", TimeValue.timeValueHours(1));
|
||||
ESLicense shieldLongLicense = generateSignedLicense("shield", TimeValue.timeValueHours(2));
|
||||
ESLicense marvelShortLicense = generateSignedLicense("marvel", TimeValue.timeValueHours(1));
|
||||
ESLicense marvelLongLicense = generateSignedLicense("marvel", TimeValue.timeValueHours(2));
|
||||
|
||||
List<ESLicense> licenses = Arrays.asList(shieldLongLicense, shieldShortLicense, marvelLongLicense, marvelShortLicense);
|
||||
Collections.shuffle(licenses);
|
||||
putAndCheckSignedLicensesAction(licensesManagerService, licenses, LicensesStatus.VALID);
|
||||
|
||||
final ImmutableSet<String> licenseSignatures = masterLicenseManager().toSignatures(licenses);
|
||||
LicensesMetaData licensesMetaData = clusterService().state().metaData().custom(LicensesMetaData.TYPE);
|
||||
|
||||
// all licenses should be stored in the metaData
|
||||
assertThat(licenseSignatures, equalTo(licensesMetaData.getSignatures()));
|
||||
|
||||
// only the latest expiry date license for each feature should be returned by getLicenses()
|
||||
final List<ESLicense> getLicenses = licensesManagerService.getLicenses();
|
||||
TestUtils.isSame(getLicenses, Arrays.asList(shieldLongLicense, marvelLongLicense));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidLicenseStorage() throws Exception {
|
||||
LicensesManagerService licensesManagerService = masterLicensesManagerService();
|
||||
ESLicense signedLicense = generateSignedLicense("shield", TimeValue.timeValueMinutes(2));
|
||||
|
||||
// modify content of signed license
|
||||
ESLicense tamperedLicense = ESLicense.builder()
|
||||
.fromLicenseSpec(signedLicense, signedLicense.signature())
|
||||
.expiryDate(signedLicense.expiryDate() + 10 * 24 * 60 * 60 * 1000l)
|
||||
.verify()
|
||||
.build();
|
||||
|
||||
putAndCheckSignedLicensesAction(licensesManagerService, Arrays.asList(tamperedLicense), LicensesStatus.INVALID);
|
||||
|
||||
// ensure that the invalid license never made it to cluster state
|
||||
LicensesMetaData licensesMetaData = clusterService().state().metaData().custom(LicensesMetaData.TYPE);
|
||||
if (licensesMetaData != null) {
|
||||
assertThat(licensesMetaData.getSignatures().size(), equalTo(0));
|
||||
}
|
||||
}
|
||||
public class LicensesClientServiceTests extends AbstractLicensesServiceTests {
|
||||
|
||||
@Test
|
||||
public void testTrialLicenseEnforcement() throws Exception {
|
||||
|
@ -260,33 +188,6 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
|
|||
|
||||
}
|
||||
|
||||
private void putAndCheckSignedLicensesAction(final LicensesManagerService masterLicensesManagerService, final List<ESLicense> license, final LicensesStatus expectedStatus) {
|
||||
PutLicenseRequest putLicenseRequest = new PutLicenseRequest().licenses(license);
|
||||
LicensesService.PutLicenseRequestHolder requestHolder = new LicensesService.PutLicenseRequestHolder(putLicenseRequest, "test");
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final AtomicBoolean success = new AtomicBoolean(false);
|
||||
masterLicensesManagerService.registerLicenses(requestHolder, new ActionListener<LicensesUpdateResponse>() {
|
||||
@Override
|
||||
public void onResponse(LicensesUpdateResponse licensesUpdateResponse) {
|
||||
if (licensesUpdateResponse.isAcknowledged() && licensesUpdateResponse.status() == expectedStatus) {
|
||||
success.set(true);
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable e) {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
assertThat(success.get(), equalTo(true));
|
||||
}
|
||||
|
||||
private Action generateAndPutSignedLicenseAction(final LicensesManagerService masterLicensesManagerService, final String feature, final TimeValue expiryDuration) throws Exception {
|
||||
return new Action(new Runnable() {
|
||||
@Override
|
||||
|
@ -298,7 +199,7 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
|
|||
fail(e.getMessage());
|
||||
return;
|
||||
}
|
||||
putAndCheckSignedLicensesAction(masterLicensesManagerService, Arrays.asList(license), LicensesStatus.VALID);
|
||||
registerAndAckSignedLicenses(masterLicensesManagerService, Arrays.asList(license), LicensesStatus.VALID);
|
||||
}
|
||||
}, 0, 1, "should trigger onEnable for " + feature + " once [signed license]");
|
||||
}
|
||||
|
@ -312,21 +213,6 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
|
|||
}, 0, 0, "should not trigger any notification [disabled by default]");
|
||||
}
|
||||
|
||||
private Action registerWithTrialLicense(final LicensesClientService clientService, final LicensesClientService.Listener clientListener, final String feature, final TimeValue expiryDuration) {
|
||||
return new Action(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
clientService.register(feature, new LicensesService.TrialLicenseOptions(expiryDuration, 10),
|
||||
clientListener);
|
||||
|
||||
// invoke clusterChanged event to flush out pendingRegistration
|
||||
LicensesService licensesService = (LicensesService) clientService;
|
||||
ClusterChangedEvent event = new ClusterChangedEvent("", clusterService().state(), clusterService().state());
|
||||
licensesService.clusterChanged(event);
|
||||
}
|
||||
}, 0, 1, "should trigger onEnable for " + feature + " once [trial license]");
|
||||
}
|
||||
|
||||
private Action assertExpiryAction(String feature, String licenseType, TimeValue expiryDuration) {
|
||||
return new Action(new Runnable() {
|
||||
@Override
|
||||
|
@ -372,73 +258,4 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
|
|||
}
|
||||
return "there should be no errors";
|
||||
}
|
||||
|
||||
private class TestTrackingClientListener implements LicensesClientService.Listener {
|
||||
CountDownLatch enableLatch;
|
||||
CountDownLatch disableLatch;
|
||||
|
||||
public synchronized void latch(CountDownLatch enableLatch, CountDownLatch disableLatch) {
|
||||
this.enableLatch = enableLatch;
|
||||
this.disableLatch = disableLatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled() {
|
||||
this.enableLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisabled() {
|
||||
this.disableLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
private class Action {
|
||||
final int expectedDisabledCount;
|
||||
final int expectedEnabledCount;
|
||||
final TimeValue timeout;
|
||||
final Runnable action;
|
||||
final String msg;
|
||||
|
||||
private Action(Runnable action, int expectedEnabledCount, int expectedDisabledCount, String msg) {
|
||||
this(action, expectedEnabledCount, expectedDisabledCount, TimeValue.timeValueSeconds(1), msg);
|
||||
}
|
||||
|
||||
private Action(Runnable action, int expectedDisabledCount, int expectedEnabledCount, TimeValue timeout, String msg) {
|
||||
this.expectedDisabledCount = expectedDisabledCount;
|
||||
this.expectedEnabledCount = expectedEnabledCount;
|
||||
this.action = action;
|
||||
this.timeout = timeout;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
action.run();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private LicensesManagerService masterLicensesManagerService() {
|
||||
final InternalTestCluster clients = internalCluster();
|
||||
return clients.getInstance(LicensesManagerService.class, clients.getMasterName());
|
||||
}
|
||||
|
||||
private ESLicenseManager masterLicenseManager() {
|
||||
final InternalTestCluster clients = internalCluster();
|
||||
return clients.getInstance(ESLicenseManager.class, clients.getMasterName());
|
||||
}
|
||||
|
||||
private LicensesClientService licensesClientService() {
|
||||
return internalCluster().getInstance(LicensesClientService.class, node);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.license.plugin;
|
||||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.cluster.ack.ClusterStateUpdateResponse;
|
||||
import org.elasticsearch.common.collect.ImmutableSet;
|
||||
import org.elasticsearch.common.collect.Sets;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.license.TestUtils;
|
||||
import org.elasticsearch.license.core.ESLicense;
|
||||
import org.elasticsearch.license.manager.ESLicenseManager;
|
||||
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseRequest;
|
||||
import org.elasticsearch.license.plugin.core.*;
|
||||
import org.elasticsearch.test.InternalTestCluster;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.TEST;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
@ClusterScope(scope = TEST, numDataNodes = 10)
|
||||
public class LicensesManagerServiceTests extends AbstractLicensesServiceTests {
|
||||
|
||||
@Test
|
||||
public void testStoreAndGetLicenses() throws Exception {
|
||||
LicensesManagerService licensesManagerService = masterLicensesManagerService();
|
||||
ESLicense shieldShortLicense = generateSignedLicense("shield", TimeValue.timeValueHours(1));
|
||||
ESLicense shieldLongLicense = generateSignedLicense("shield", TimeValue.timeValueHours(2));
|
||||
ESLicense marvelShortLicense = generateSignedLicense("marvel", TimeValue.timeValueHours(1));
|
||||
ESLicense marvelLongLicense = generateSignedLicense("marvel", TimeValue.timeValueHours(2));
|
||||
|
||||
List<ESLicense> licenses = Arrays.asList(shieldLongLicense, shieldShortLicense, marvelLongLicense, marvelShortLicense);
|
||||
Collections.shuffle(licenses);
|
||||
registerAndAckSignedLicenses(licensesManagerService, licenses, LicensesStatus.VALID);
|
||||
|
||||
final ImmutableSet<String> licenseSignatures = masterLicenseManager().toSignatures(licenses);
|
||||
LicensesMetaData licensesMetaData = clusterService().state().metaData().custom(LicensesMetaData.TYPE);
|
||||
|
||||
// all licenses should be stored in the metaData
|
||||
assertThat(licenseSignatures, equalTo(licensesMetaData.getSignatures()));
|
||||
|
||||
// only the latest expiry date license for each feature should be returned by getLicenses()
|
||||
final List<ESLicense> getLicenses = licensesManagerService.getLicenses();
|
||||
TestUtils.isSame(getLicenses, Arrays.asList(shieldLongLicense, marvelLongLicense));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidLicenseStorage() throws Exception {
|
||||
LicensesManagerService licensesManagerService = masterLicensesManagerService();
|
||||
ESLicense signedLicense = generateSignedLicense("shield", TimeValue.timeValueMinutes(2));
|
||||
|
||||
// modify content of signed license
|
||||
ESLicense tamperedLicense = ESLicense.builder()
|
||||
.fromLicenseSpec(signedLicense, signedLicense.signature())
|
||||
.expiryDate(signedLicense.expiryDate() + 10 * 24 * 60 * 60 * 1000l)
|
||||
.verify()
|
||||
.build();
|
||||
|
||||
registerAndAckSignedLicenses(licensesManagerService, Arrays.asList(tamperedLicense), LicensesStatus.INVALID);
|
||||
|
||||
// ensure that the invalid license never made it to cluster state
|
||||
LicensesMetaData licensesMetaData = clusterService().state().metaData().custom(LicensesMetaData.TYPE);
|
||||
if (licensesMetaData != null) {
|
||||
assertThat(licensesMetaData.getSignatures().size(), equalTo(0));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveLicenses() throws Exception {
|
||||
LicensesManagerService licensesManagerService = masterLicensesManagerService();
|
||||
|
||||
// generate a trial license for one feature
|
||||
final LicensesClientService clientService = licensesClientService();
|
||||
final TestTrackingClientListener clientListener = new TestTrackingClientListener(false);
|
||||
registerWithTrialLicense(clientService, clientListener, "shield", TimeValue.timeValueHours(1)).run();
|
||||
|
||||
// generate signed licenses for multiple features
|
||||
ESLicense shieldShortLicense = generateSignedLicense("shield", TimeValue.timeValueHours(1));
|
||||
ESLicense shieldLongLicense = generateSignedLicense("shield", TimeValue.timeValueHours(2));
|
||||
ESLicense marvelShortLicense = generateSignedLicense("marvel", TimeValue.timeValueHours(1));
|
||||
ESLicense marvelLongLicense = generateSignedLicense("marvel", TimeValue.timeValueHours(2));
|
||||
|
||||
List<ESLicense> licenses = Arrays.asList(shieldLongLicense, shieldShortLicense, marvelLongLicense, marvelShortLicense);
|
||||
Collections.shuffle(licenses);
|
||||
registerAndAckSignedLicenses(licensesManagerService, licenses, LicensesStatus.VALID);
|
||||
|
||||
// remove license(s) for one feature out of two
|
||||
removeAndAckSignedLicenses(licensesManagerService, Sets.newHashSet("shield"));
|
||||
final ImmutableSet<String> licenseSignatures = masterLicenseManager().toSignatures(Arrays.asList(marvelLongLicense, marvelShortLicense));
|
||||
LicensesMetaData licensesMetaData = clusterService().state().metaData().custom(LicensesMetaData.TYPE);
|
||||
assertThat(licenseSignatures, equalTo(licensesMetaData.getSignatures()));
|
||||
// check that trial license is not removed
|
||||
assertThat(licensesMetaData.getEncodedTrialLicenses().size(), equalTo(1));
|
||||
|
||||
// remove license(s) for all features
|
||||
removeAndAckSignedLicenses(licensesManagerService, Sets.newHashSet("shield", "marvel"));
|
||||
licensesMetaData = clusterService().state().metaData().custom(LicensesMetaData.TYPE);
|
||||
assertThat(licensesMetaData.getSignatures().size(), equalTo(0));
|
||||
// check that trial license is not removed
|
||||
assertThat(licensesMetaData.getEncodedTrialLicenses().size(), equalTo(1));
|
||||
}
|
||||
|
||||
private void removeAndAckSignedLicenses(final LicensesManagerService masterLicensesManagerService, final Set<String> featuresToDelete) {
|
||||
DeleteLicenseRequest deleteLicenseRequest = new DeleteLicenseRequest(featuresToDelete.toArray(new String[featuresToDelete.size()]));
|
||||
LicensesService.DeleteLicenseRequestHolder requestHolder = new LicensesService.DeleteLicenseRequestHolder(deleteLicenseRequest, "test");
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final AtomicBoolean success = new AtomicBoolean(false);
|
||||
masterLicensesManagerService.removeLicenses(requestHolder, new ActionListener<ClusterStateUpdateResponse>() {
|
||||
@Override
|
||||
public void onResponse(ClusterStateUpdateResponse clusterStateUpdateResponse) {
|
||||
if (clusterStateUpdateResponse.isAcknowledged()) {
|
||||
success.set(true);
|
||||
}
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable throwable) {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
assertThat("remove license(s) failed", success.get(), equalTo(true));
|
||||
}
|
||||
|
||||
private ESLicenseManager masterLicenseManager() {
|
||||
InternalTestCluster clients = internalCluster();
|
||||
return clients.getInstance(ESLicenseManager.class, clients.getMasterName());
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue