From ad6b86481e473b01793d70e966b4c99a49898096 Mon Sep 17 00:00:00 2001 From: Igor Motov Date: Fri, 12 May 2017 17:14:02 -0400 Subject: [PATCH] Make Upgrade API license aware (elastic/x-pack-elasticsearch#1401) Upgrade API should only work with non-trial licenses Relates to elastic/x-pack-elasticsearch#1214 Original commit: elastic/x-pack-elasticsearch@28fef0feeb1db8e8e9e162c498ac9d78358b5c1c --- .../license/XPackLicenseState.java | 24 ++++++++ .../org/elasticsearch/xpack/XPackPlugin.java | 3 + .../actions/IndexUpgradeInfoAction.java | 19 +++++-- .../AbstractLicensesIntegrationTestCase.java | 4 ++ .../xpack/upgrade/IndexUpgradeIT.java | 55 ++++++++++++++++++- .../rest-api-spec/test/upgrade/10_basic.yaml | 17 ++++++ 6 files changed, 115 insertions(+), 7 deletions(-) diff --git a/plugin/src/main/java/org/elasticsearch/license/XPackLicenseState.java b/plugin/src/main/java/org/elasticsearch/license/XPackLicenseState.java index 58ce641d6d0..5bebff07b7a 100644 --- a/plugin/src/main/java/org/elasticsearch/license/XPackLicenseState.java +++ b/plugin/src/main/java/org/elasticsearch/license/XPackLicenseState.java @@ -54,6 +54,9 @@ public class XPackLicenseState { messages.put(XPackPlugin.DEPRECATION, new String[] { "Deprecation APIs are disabled" }); + messages.put(XPackPlugin.UPGRADE, new String[] { + "Upgrade API is disabled" + }); EXPIRATION_MESSAGES = Collections.unmodifiableMap(messages); } @@ -457,4 +460,25 @@ public class XPackLicenseState { public boolean isDeprecationAllowed() { return status.active; } + + /** + * Determine if Upgrade API should be enabled. + *

+ * Upgrade API is not available in for all license types except {@link OperationMode#TRIAL} + * + * @return {@code true} as long as the license is valid. Otherwise + * {@code false}. + */ + public boolean isUpgradeAllowed() { + // status is volatile + Status localStatus = status; + OperationMode operationMode = localStatus.mode; + + boolean licensed = operationMode == OperationMode.BASIC || operationMode == OperationMode.STANDARD || + operationMode == OperationMode.GOLD || operationMode == OperationMode.PLATINUM; + + return licensed && localStatus.active; + + } + } diff --git a/plugin/src/main/java/org/elasticsearch/xpack/XPackPlugin.java b/plugin/src/main/java/org/elasticsearch/xpack/XPackPlugin.java index 6351cf0aa26..871588a0103 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/XPackPlugin.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/XPackPlugin.java @@ -150,6 +150,9 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I /** Name constant for the Deprecation API feature. */ public static final String DEPRECATION = "deprecation"; + /** Name constant for the upgrade feature. */ + public static final String UPGRADE = "upgrade"; + // inside of YAML settings we still use xpack do not having handle issues with dashes private static final String SETTINGS_NAME = "xpack"; diff --git a/plugin/src/main/java/org/elasticsearch/xpack/upgrade/actions/IndexUpgradeInfoAction.java b/plugin/src/main/java/org/elasticsearch/xpack/upgrade/actions/IndexUpgradeInfoAction.java index 750fdf294b5..4ba2b001c83 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/upgrade/actions/IndexUpgradeInfoAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/upgrade/actions/IndexUpgradeInfoAction.java @@ -27,8 +27,11 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.license.LicenseUtils; +import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.upgrade.IndexUpgradeService; import org.elasticsearch.xpack.upgrade.UpgradeActionRequired; @@ -234,15 +237,19 @@ public class IndexUpgradeInfoAction extends Action { private final IndexUpgradeService indexUpgradeService; + private final XPackLicenseState licenseState; + @Inject public TransportAction(Settings settings, TransportService transportService, ClusterService clusterService, ThreadPool threadPool, ActionFilters actionFilters, IndexUpgradeService indexUpgradeService, - IndexNameExpressionResolver indexNameExpressionResolver) { + IndexNameExpressionResolver indexNameExpressionResolver, + XPackLicenseState licenseState) { super(settings, IndexUpgradeInfoAction.NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, Request::new); this.indexUpgradeService = indexUpgradeService; + this.licenseState = licenseState; } @Override @@ -263,9 +270,13 @@ public class IndexUpgradeInfoAction extends Action listener) { - Map results = - indexUpgradeService.upgradeInfo(request.indices(), request.indicesOptions(), request.extraParams(), state); - listener.onResponse(new Response(results)); + if (licenseState.isUpgradeAllowed()) { + Map results = + indexUpgradeService.upgradeInfo(request.indices(), request.indicesOptions(), request.extraParams(), state); + listener.onResponse(new Response(results)); + } else { + listener.onFailure(LicenseUtils.newComplianceException(XPackPlugin.UPGRADE)); + } } } } \ No newline at end of file diff --git a/plugin/src/test/java/org/elasticsearch/license/AbstractLicensesIntegrationTestCase.java b/plugin/src/test/java/org/elasticsearch/license/AbstractLicensesIntegrationTestCase.java index ace2bbea51c..e7b990723a6 100644 --- a/plugin/src/test/java/org/elasticsearch/license/AbstractLicensesIntegrationTestCase.java +++ b/plugin/src/test/java/org/elasticsearch/license/AbstractLicensesIntegrationTestCase.java @@ -75,6 +75,10 @@ public abstract class AbstractLicensesIntegrationTestCase extends ESIntegTestCas latch.await(); } + protected void putLicenseTombstone() throws InterruptedException { + putLicense(LicensesMetaData.LICENSE_TOMBSTONE); + } + protected void wipeAllLicenses() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); ClusterService clusterService = internalCluster().getInstance(ClusterService.class, internalCluster().getMasterName()); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/upgrade/IndexUpgradeIT.java b/plugin/src/test/java/org/elasticsearch/xpack/upgrade/IndexUpgradeIT.java index 26f2ea258c5..986d94fe0ae 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/upgrade/IndexUpgradeIT.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/upgrade/IndexUpgradeIT.java @@ -5,24 +5,35 @@ */ package org.elasticsearch.xpack.upgrade; +import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.common.Strings; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.license.AbstractLicensesIntegrationTestCase; +import org.elasticsearch.license.License; +import org.elasticsearch.license.TestUtils; import org.elasticsearch.plugins.Plugin; -import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.ml.MachineLearning; import org.elasticsearch.xpack.upgrade.actions.IndexUpgradeInfoAction; import org.elasticsearch.xpack.upgrade.actions.IndexUpgradeInfoAction.Response; +import org.junit.Before; import java.util.Collection; import java.util.Collections; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.empty; import static org.hamcrest.core.IsEqual.equalTo; -public class IndexUpgradeIT extends ESIntegTestCase { +public class IndexUpgradeIT extends AbstractLicensesIntegrationTestCase { + + @Before + public void resetLicensing() throws Exception { + enableLicensing(); + } @Override protected boolean ignoreExternalCluster() { @@ -67,7 +78,7 @@ public class IndexUpgradeIT extends ESIntegTestCase { public void testIndexUpgradeInfo() { assertAcked(client().admin().indices().prepareCreate("test").get()); assertAcked(client().admin().indices().prepareCreate("kibana_test").get()); - ensureYellow("test"); + ensureYellow("test", "kibana_test"); Response response = client().prepareExecute(IndexUpgradeInfoAction.INSTANCE).setIndices("test", "kibana_test") .setExtraParams(Collections.singletonMap("kibana_indices", "kibana_test")).get(); logger.info("Got response [{}]", Strings.toString(response)); @@ -75,4 +86,42 @@ public class IndexUpgradeIT extends ESIntegTestCase { assertThat(response.getActions().get("kibana_test"), equalTo(UpgradeActionRequired.UPGRADE)); assertThat(Strings.toString(response), containsString("kibana_test")); } + + public void testIndexUpgradeInfoLicense() throws Exception { + assertAcked(client().admin().indices().prepareCreate("test").get()); + ensureYellow("test"); + disableLicensing(); + ElasticsearchSecurityException e = expectThrows(ElasticsearchSecurityException.class, + () -> client().prepareExecute(IndexUpgradeInfoAction.INSTANCE).setIndices("test").get()); + assertThat(e.getMessage(), equalTo("current license is non-compliant for [upgrade]")); + enableLicensing(); + Response response = client().prepareExecute(IndexUpgradeInfoAction.INSTANCE).setIndices("test").get(); + assertThat(response.getActions().entrySet(), empty()); + } + + private static String randomValidLicenseType() { + return randomFrom("platinum", "gold", "standard", "basic"); + } + + private static String randomInvalidLicenseType() { + return randomFrom("missing", "trial"); + } + + public void disableLicensing() throws Exception { + updateLicensing(randomInvalidLicenseType()); + } + + public void enableLicensing() throws Exception { + updateLicensing(randomValidLicenseType()); + } + + public void updateLicensing(String licenseType) throws Exception { + wipeAllLicenses(); + if (licenseType.equals("missing")) { + putLicenseTombstone(); + } else { + License license = TestUtils.generateSignedLicense(licenseType, TimeValue.timeValueMinutes(1)); + putLicense(license); + } + } } diff --git a/plugin/src/test/resources/rest-api-spec/test/upgrade/10_basic.yaml b/plugin/src/test/resources/rest-api-spec/test/upgrade/10_basic.yaml index 5920b0d20dc..9b3bfbf227b 100644 --- a/plugin/src/test/resources/rest-api-spec/test/upgrade/10_basic.yaml +++ b/plugin/src/test/resources/rest-api-spec/test/upgrade/10_basic.yaml @@ -1,5 +1,22 @@ --- setup: + - do: + xpack.license.post: + body: > + { + "license": { + "uid": "b8520184-985d-4b04-8a89-b52da6e0aad1", + "type": "platinum", + "issue_date_in_millis": 1494510840000, + "expiry_date_in_millis": 2756814840000, + "max_nodes": 1, + "issued_to": "upgrade_api_test", + "issuer": "elasticsearch", + "signature": "AAAAAwAAAA0hsB+mfk9EqWiY6e1KAAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQA6NkNF3Z219ptzRwZwGzgIwaXn5rXvOWSB9KK86xBqeYQMlO1ahCd4eW3FHWTuginPuqMX8okzN+UEMANPE3l0QxvrgCcTzNYPGqCJDwBb0ghuQ4Y5Cezn806sBnXLVF35B1HU2C1PYc1mZvisD63NqasrAVYb3GS6vwq8a7PYfKpfZfFCqG2SZIkSHACPGBTUiPbVEVv1iiOC04x/pjF4Kn26MPbFD5jbQBSY2V8TxoapMHf11EDpOTlMYkXgerbMg7VWtVCypTMJJrhoVguCrZvM8U/+sSnbodtnZUeAImnFbYeV10Rcw62dtrpka0yuo7h6Qtrvy9YqVHZDtyrM", + "start_date_in_millis": -1 + } + } + - do: indices.create: index: test1