diff --git a/src/main/java/org/elasticsearch/license/plugin/core/LicensesService.java b/src/main/java/org/elasticsearch/license/plugin/core/LicensesService.java index 4813928e0a8..794da67458c 100644 --- a/src/main/java/org/elasticsearch/license/plugin/core/LicensesService.java +++ b/src/main/java/org/elasticsearch/license/plugin/core/LicensesService.java @@ -96,35 +96,35 @@ public class LicensesService extends AbstractLifecycleComponent LicensesStatus status = checkLicenses(newLicenses); switch (status) { case VALID: + clusterService.submitStateUpdateTask(requestHolder.source, new AckedClusterStateUpdateTask(request, listener) { + @Override + protected LicensesUpdateResponse newResponse(boolean acknowledged) { + return new LicensesUpdateResponse(acknowledged, LicensesStatus.VALID); + } + + @Override + public ClusterState execute(ClusterState currentState) throws Exception { + MetaData metaData = currentState.metaData(); + MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData()); + LicensesMetaData currentLicenses = metaData.custom(LicensesMetaData.TYPE); + final LicensesWrapper licensesWrapper = LicensesWrapper.wrap(currentLicenses); + Set newSignatures = licenseManager.toSignatures(newLicenses); + if (newSignatures.size() > 0) { + Set newLicenseSignatures = Sets.union(licensesWrapper.signatures, newSignatures); + LicensesMetaData newLicensesMetaData = new LicensesMetaData(newLicenseSignatures, licensesWrapper.encodedTrialLicenses); + mdBuilder.putCustom(LicensesMetaData.TYPE, newLicensesMetaData); + } else { + mdBuilder.putCustom(LicensesMetaData.TYPE, currentLicenses); + } + return ClusterState.builder(currentState).metaData(mdBuilder).build(); + } + }); break; case INVALID: case EXPIRED: listener.onResponse(new LicensesUpdateResponse(true, status)); + break; } - clusterService.submitStateUpdateTask(requestHolder.source, new AckedClusterStateUpdateTask(request, listener) { - @Override - protected LicensesUpdateResponse newResponse(boolean acknowledged) { - return new LicensesUpdateResponse(acknowledged, LicensesStatus.VALID); - } - - @Override - public ClusterState execute(ClusterState currentState) throws Exception { - MetaData metaData = currentState.metaData(); - MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData()); - LicensesMetaData currentLicenses = metaData.custom(LicensesMetaData.TYPE); - final LicensesWrapper licensesWrapper = LicensesWrapper.wrap(currentLicenses); - Set newSignatures = licenseManager.toSignatures(newLicenses); - if (newSignatures.size() > 0) { - Set newLicenseSignatures = Sets.union(licensesWrapper.signatures, newSignatures); - LicensesMetaData newLicensesMetaData = new LicensesMetaData(newLicenseSignatures, licensesWrapper.encodedTrialLicenses); - mdBuilder.putCustom(LicensesMetaData.TYPE, newLicensesMetaData); - } else { - mdBuilder.putCustom(LicensesMetaData.TYPE, currentLicenses); - } - return ClusterState.builder(currentState).metaData(mdBuilder).build(); - } - - }); } public static class LicensesUpdateResponse extends ClusterStateUpdateResponse { diff --git a/src/test/java/org/elasticsearch/license/plugin/AbstractLicensesIntegrationTests.java b/src/test/java/org/elasticsearch/license/plugin/AbstractLicensesIntegrationTests.java index c89bfdb9e75..a1beacb4b7c 100644 --- a/src/test/java/org/elasticsearch/license/plugin/AbstractLicensesIntegrationTests.java +++ b/src/test/java/org/elasticsearch/license/plugin/AbstractLicensesIntegrationTests.java @@ -12,11 +12,18 @@ import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.license.core.ESLicense; +import org.elasticsearch.license.licensor.ESLicenseSigner; import org.elasticsearch.license.plugin.core.LicensesMetaData; import org.elasticsearch.test.ElasticsearchIntegrationTest; +import java.util.UUID; import java.util.concurrent.CountDownLatch; +import static org.elasticsearch.license.AbstractLicensingTestBase.getTestPriKeyPath; +import static org.elasticsearch.license.AbstractLicensingTestBase.getTestPubKeyPath; + /** */ public abstract class AbstractLicensesIntegrationTests extends ElasticsearchIntegrationTest { @@ -59,4 +66,20 @@ public abstract class AbstractLicensesIntegrationTests extends ElasticsearchInte latch.await(); } + public static ESLicense generateSignedLicense(String feature, TimeValue expiryDate) throws Exception { + final ESLicense licenseSpec = ESLicense.builder() + .uid(UUID.randomUUID().toString()) + .feature(feature) + .expiryDate(System.currentTimeMillis() + expiryDate.getMillis()) + .issueDate(System.currentTimeMillis()) + .type("subscription") + .subscriptionType("gold") + .issuedTo("customer") + .issuer("elasticsearch") + .maxNodes(randomIntBetween(5, 100)) + .build(); + + ESLicenseSigner signer = new ESLicenseSigner(getTestPriKeyPath(), getTestPubKeyPath()); + return signer.sign(licenseSpec); + } } diff --git a/src/test/java/org/elasticsearch/license/plugin/LicenseTransportTests.java b/src/test/java/org/elasticsearch/license/plugin/LicenseTransportTests.java index a5620e6f3cb..454a8e92bd1 100644 --- a/src/test/java/org/elasticsearch/license/plugin/LicenseTransportTests.java +++ b/src/test/java/org/elasticsearch/license/plugin/LicenseTransportTests.java @@ -6,26 +6,21 @@ package org.elasticsearch.license.plugin; import org.elasticsearch.action.ActionFuture; -import org.elasticsearch.action.ListenableActionFuture; -import org.elasticsearch.common.collect.ImmutableSet; +import org.elasticsearch.common.collect.Lists; +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.delete.DeleteLicenseRequestBuilder; -import org.elasticsearch.license.plugin.action.delete.DeleteLicenseResponse; 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.junit.BeforeClass; +import org.elasticsearch.license.plugin.core.LicensesStatus; +import org.junit.After; import org.junit.Test; -import java.io.IOException; -import java.net.URISyntaxException; -import java.nio.file.Paths; -import java.text.ParseException; -import java.util.*; -import java.util.concurrent.ExecutionException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope; import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.TEST; @@ -35,111 +30,124 @@ import static org.hamcrest.CoreMatchers.notNullValue; @ClusterScope(scope = TEST, numDataNodes = 10) public class LicenseTransportTests extends AbstractLicensesIntegrationTests { - private static String pubKeyPath = null; - private static String priKeyPath = null; - - @BeforeClass - public static void setup() throws IOException, URISyntaxException { - priKeyPath = Paths.get(LicenseTransportTests.class.getResource("/private.key").toURI()).toAbsolutePath().toString(); - pubKeyPath = Paths.get(LicenseTransportTests.class.getResource("/public.key").toURI()).toAbsolutePath().toString(); + @After + public void beforeTest() throws Exception { + wipeAllLicenses(); } - /* - * TODO: - * - add more delete tests - * - add put invalid licenses tests - * - add multiple licenses of the same feature tests - */ - @Test public void testEmptyGetLicense() throws Exception { - DeleteLicenseRequestBuilder deleteLicenseRequestBuilder = new DeleteLicenseRequestBuilder(client().admin().cluster()).setFeatures(ImmutableSet.of("marvel", "shield")); - final ActionFuture deleteFuture = deleteLicenseRequestBuilder.execute(); - final DeleteLicenseResponse deleteLicenseResponse = deleteFuture.get(); - assertTrue(deleteLicenseResponse.isAcknowledged()); - final ActionFuture getLicenseFuture = new GetLicenseRequestBuilder(client().admin().cluster()).execute(); - final GetLicenseResponse getLicenseResponse = getLicenseFuture.get(); - assertThat("expected 0 licenses; but got: " + getLicenseResponse.licenses().size(), getLicenseResponse.licenses().size(), equalTo(0)); } @Test - public void testPutLicense() throws ParseException, ExecutionException, InterruptedException, IOException { - - Map 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); - - PutLicenseRequestBuilder putLicenseRequestBuilder = new PutLicenseRequestBuilder(client().admin().cluster()); - //putLicenseRequest.license(licenseString); - final List putLicenses = ESLicenses.fromSource(licenseOutput); - putLicenseRequestBuilder.setLicense(putLicenses); - //LicenseUtils.printLicense(putLicenses); - ensureGreen(); - - final ActionFuture putLicenseFuture = putLicenseRequestBuilder.execute(); - - final PutLicenseResponse putLicenseResponse = putLicenseFuture.get(); + public void testPutLicense() throws Exception { + ESLicense signedLicense = generateSignedLicense(TestUtils.SHIELD, TimeValue.timeValueMinutes(2)); + List actualLicenses = Collections.singletonList(signedLicense); + // put license + PutLicenseRequestBuilder putLicenseRequestBuilder = new PutLicenseRequestBuilder(client().admin().cluster()) + .setLicense(actualLicenses); + PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.execute().get(); assertThat(putLicenseResponse.isAcknowledged(), equalTo(true)); + assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); - ActionFuture getLicenseFuture = new GetLicenseRequestBuilder(client().admin().cluster()).execute(); - - GetLicenseResponse getLicenseResponse = getLicenseFuture.get(); - + // get license + GetLicenseResponse getLicenseResponse = new GetLicenseRequestBuilder(client().admin().cluster()).get(); assertThat(getLicenseResponse.licenses(), notNullValue()); - //LicenseUtils.printLicense(getLicenseResponse.licenses()); - TestUtils.isSame(new HashSet<>(putLicenses), new HashSet<>(getLicenseResponse.licenses())); - - - final ActionFuture deleteFuture = new DeleteLicenseRequestBuilder(client().admin().cluster()) - .setFeatures(ImmutableSet.of("marvel", "shield")).execute(); - final DeleteLicenseResponse deleteLicenseResponse = deleteFuture.get(); - assertTrue(deleteLicenseResponse.isAcknowledged()); - - //getLicenseResponse = new GetLicenseRequestBuilder(client().admin().cluster()).execute().get(); - //TestUtils.isSame(getLicenseResponse.licenses(), LicenseBuilders.licensesBuilder().verifyAndBuild()); + // check license + TestUtils.isSame(actualLicenses, getLicenseResponse.licenses()); } @Test public void testPutInvalidLicense() throws Exception { - Map 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); + ESLicense signedLicense = generateSignedLicense(TestUtils.SHIELD, TimeValue.timeValueMinutes(2)); - Set esLicenses = new HashSet<>(ESLicenses.fromSource(licenseOutput)); - - ESLicense esLicense = ESLicenses.reduceAndMap(esLicenses).get(TestUtils.SHIELD); - - final ESLicense tamperedLicense = ESLicense.builder() - .fromLicenseSpec(esLicense, esLicense.signature()) - .expiryDate(esLicense.expiryDate() + 10 * 24 * 60 * 60 * 1000l) + // modify content of signed license + ESLicense tamperedLicense = ESLicense.builder() + .fromLicenseSpec(signedLicense, signedLicense.signature()) + .expiryDate(signedLicense.expiryDate() + 10 * 24 * 60 * 60 * 1000l) .verify() .build(); PutLicenseRequestBuilder builder = new PutLicenseRequestBuilder(client().admin().cluster()); builder.setLicense(Collections.singletonList(tamperedLicense)); - final ListenableActionFuture execute = builder.execute(); + // try to put license (should be invalid) + final PutLicenseResponse putLicenseResponse = builder.execute().get(); + assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.INVALID)); - try { - execute.get(); - fail("Invalid License should throw exception"); - } catch (Throwable e) { - /* TODO: figure out error handling - String msg =e.getCause().getCause().getCause().getMessage();//e.getCause().getCause().getMessage();// e.getCause().getCause().getCause().getMessage(); - assertTrue("Error message: " + msg, msg.contains("Invalid License(s)")); - */ - } + + // try to get invalid license + GetLicenseResponse getLicenseResponse = new GetLicenseRequestBuilder(client().admin().cluster()).get(); + assertThat(getLicenseResponse.licenses().size(), equalTo(0)); + } + + @Test + public void testPutLicensesForSameFeature() throws Exception { + ESLicense shortedSignedLicense = generateSignedLicense(TestUtils.SHIELD, TimeValue.timeValueMinutes(2)); + ESLicense longerSignedLicense = generateSignedLicense(TestUtils.SHIELD, TimeValue.timeValueMinutes(5)); + List actualLicenses = Arrays.asList(longerSignedLicense, shortedSignedLicense); + + // put license + PutLicenseRequestBuilder putLicenseRequestBuilder = new PutLicenseRequestBuilder(client().admin().cluster()) + .setLicense(actualLicenses); + PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.execute().get(); + assertThat(putLicenseResponse.isAcknowledged(), equalTo(true)); + assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); + + // get should return only one license (with longer expiry date) + GetLicenseResponse getLicenseResponse = new GetLicenseRequestBuilder(client().admin().cluster()).get(); + assertThat(getLicenseResponse.licenses(), notNullValue()); + + // check license + TestUtils.isSame(Collections.singletonList(longerSignedLicense), getLicenseResponse.licenses()); + } + + @Test + public void testPutLicensesForMultipleFeatures() throws Exception { + ESLicense shieldLicense = generateSignedLicense(TestUtils.SHIELD, TimeValue.timeValueMinutes(2)); + ESLicense marvelLicense = generateSignedLicense(TestUtils.MARVEL, TimeValue.timeValueMinutes(5)); + List actualLicenses = Arrays.asList(marvelLicense, shieldLicense); + + // put license + PutLicenseRequestBuilder putLicenseRequestBuilder = new PutLicenseRequestBuilder(client().admin().cluster()) + .setLicense(actualLicenses); + PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.execute().get(); + assertThat(putLicenseResponse.isAcknowledged(), equalTo(true)); + assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); + + // get should return both the licenses + GetLicenseResponse getLicenseResponse = new GetLicenseRequestBuilder(client().admin().cluster()).get(); + assertThat(getLicenseResponse.licenses(), notNullValue()); + + // check license + TestUtils.isSame(actualLicenses, getLicenseResponse.licenses()); + } + + @Test + public void testPutMultipleLicensesForMultipleFeatures() throws Exception { + ESLicense shortedSignedLicense = generateSignedLicense(TestUtils.SHIELD, TimeValue.timeValueMinutes(2)); + ESLicense longerSignedLicense = generateSignedLicense(TestUtils.SHIELD, TimeValue.timeValueMinutes(5)); + ESLicense marvelLicense = generateSignedLicense(TestUtils.MARVEL, TimeValue.timeValueMinutes(5)); + List actualLicenses = Arrays.asList(marvelLicense, shortedSignedLicense, longerSignedLicense); + + // put license + PutLicenseRequestBuilder putLicenseRequestBuilder = new PutLicenseRequestBuilder(client().admin().cluster()) + .setLicense(actualLicenses); + PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.execute().get(); + assertThat(putLicenseResponse.isAcknowledged(), equalTo(true)); + assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); + + // get should return both the licenses + GetLicenseResponse getLicenseResponse = new GetLicenseRequestBuilder(client().admin().cluster()).get(); + assertThat(getLicenseResponse.licenses(), notNullValue()); + + // check license (should get the longest expiry time for all unique features) + TestUtils.isSame(Arrays.asList(marvelLicense, longerSignedLicense), getLicenseResponse.licenses()); } } diff --git a/src/test/java/org/elasticsearch/license/plugin/LicensesPluginIntegrationTests.java b/src/test/java/org/elasticsearch/license/plugin/LicensesPluginIntegrationTests.java index 2da5cb876c0..7596a7385a5 100644 --- a/src/test/java/org/elasticsearch/license/plugin/LicensesPluginIntegrationTests.java +++ b/src/test/java/org/elasticsearch/license/plugin/LicensesPluginIntegrationTests.java @@ -11,21 +11,16 @@ import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.license.core.ESLicense; -import org.elasticsearch.license.licensor.ESLicenseSigner; import org.elasticsearch.license.plugin.core.LicensesManagerService; 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.elasticsearch.test.InternalTestCluster; import org.junit.After; -import org.junit.Before; import org.junit.Test; -import java.util.UUID; import java.util.concurrent.TimeUnit; -import static org.elasticsearch.license.AbstractLicensingTestBase.getTestPriKeyPath; -import static org.elasticsearch.license.AbstractLicensingTestBase.getTestPubKeyPath; import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope; import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.TEST; import static org.hamcrest.CoreMatchers.equalTo; @@ -172,23 +167,6 @@ public class LicensesPluginIntegrationTests extends AbstractLicensesIntegrationT }, timeoutInSec, TimeUnit.SECONDS), equalTo(true)); } - private ESLicense generateSignedLicense(String feature, TimeValue expiryDate) throws Exception { - final ESLicense licenseSpec = ESLicense.builder() - .uid(UUID.randomUUID().toString()) - .feature(feature) - .expiryDate(System.currentTimeMillis() + expiryDate.getMillis()) - .issueDate(System.currentTimeMillis()) - .type("subscription") - .subscriptionType("gold") - .issuedTo("customer") - .issuer("elasticsearch") - .maxNodes(10) - .build(); - - ESLicenseSigner signer = new ESLicenseSigner(getTestPriKeyPath(), getTestPubKeyPath()); - return signer.sign(licenseSpec); - } - private Iterable consumerPluginServices() { final InternalTestCluster clients = internalCluster(); return clients.getDataNodeInstances(TestPluginService.class);