From 9120bc279872765a0c47c2ca30c0e451aea5ff62 Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Thu, 20 Jun 2019 11:48:12 -0700 Subject: [PATCH 01/12] Use transport actions instead of guice for xpack info The Xpack info API internally gathers all xpack feature sets by using guice to bind many implementations. The info api then iterates over these feature sets to gather usage information for each. However, since each of these implementations are in different plugins, there is no direct, non-guice way for them to register the implementations. This commit removes the dependence on guice for the info api by having the core xpack jar contain an action instance for each plugin, and the implementation of those actions are then registered within each xpack feature plugin. The info api then iterates over each of these actions and calls them with the NodeClient. --- .../java/org/elasticsearch/xpack/ccr/Ccr.java | 16 +- .../xpack/ccr/CCRFeatureSetUsageTests.java | 10 +- ....java => CCRInfoTransportActionTests.java} | 20 +- ...reSet.java => CCRInfoTransportAction.java} | 69 +---- .../xpack/ccr/CCRUsageTransportAction.java | 73 +++++ .../xpack/core/XPackClientPlugin.java | 4 +- .../core/action/TransportXPackInfoAction.java | 45 ++- .../action/TransportXPackUsageAction.java | 1 + .../core/action/XPackInfoFeatureAction.java | 55 ++++ .../core/action/XPackInfoFeatureResponse.java | 42 +++ .../XPackInfoFeatureTransportAction.java | 32 +++ .../action/TransportXPackInfoActionTests.java | 3 +- .../integration/DataFrameUsageIT.java | 2 +- .../xpack/dataframe/DataFrame.java | 20 +- .../xpack/dataframe/DataFrameFeatureSet.java | 246 ---------------- .../DataFrameInfoTransportAction.java | 145 ++++++++++ .../DataFrameUsageTransportAction.java | 128 +++++++++ ...=> DataFrameInfoTransportActionTests.java} | 20 +- .../org/elasticsearch/xpack/graph/Graph.java | 21 +- .../xpack/graph/GraphFeatureSet.java | 75 ----- .../xpack/graph/GraphInfoTransportAction.java | 46 +++ .../graph/GraphUsageTransportAction.java | 46 +++ ...ava => GraphInfoTransportActionTests.java} | 12 +- .../xpack/indexlifecycle/IndexLifecycle.java | 22 +- .../IndexLifecycleFeatureSet.java | 110 -------- .../IndexLifecycleInfoTransportAction.java | 46 +++ .../IndexLifecycleUsageTransportAction.java | 79 ++++++ ...dexLifecycleInfoTransportActionTests.java} | 19 +- .../xpack/logstash/Logstash.java | 24 +- .../xpack/logstash/LogstashFeatureSet.java | 76 ----- .../logstash/LogstashInfoTransportAction.java | 46 +++ .../LogstashUsageTransportAction.java | 47 ++++ ... => LogstashInfoTransportActionTests.java} | 17 +- .../xpack/ml/MachineLearning.java | 25 +- .../xpack/ml/MachineLearningFeatureSet.java | 264 ------------------ .../MachineLearningInfoTransportAction.java | 75 +++++ .../MachineLearningUsageTransportAction.java | 207 ++++++++++++++ .../xpack/ml/MlLifeCycleService.java | 2 +- .../ml/process/NativeControllerHolder.java | 2 +- ...hineLearningInfoTransportActionTests.java} | 30 +- .../xpack/monitoring/Monitoring.java | 10 +- .../MonitoringInfoTransportAction.java | 45 +++ ...va => MonitoringUsageTransportAction.java} | 62 ++-- ...> MonitoringInfoTransportActionTests.java} | 13 +- .../elasticsearch/xpack/rollup/Rollup.java | 25 +- .../xpack/rollup/RollupFeatureSet.java | 78 ------ .../rollup/RollupInfoTransportAction.java | 46 +++ .../rollup/RollupUsageTransportAction.java | 48 ++++ ...va => RollupInfoTransportActionTests.java} | 13 +- .../xpack/security/Security.java | 18 +- .../xpack/security/SecurityFeatureSet.java | 216 -------------- .../security/SecurityInfoTransportAction.java | 48 ++++ .../SecurityUsageTransportAction.java | 171 ++++++++++++ ... => SecurityInfoTransportActionTests.java} | 15 +- .../xpack/sql/SqlFeatureSet.java | 105 ------- .../xpack/sql/SqlInfoTransportAction.java | 46 +++ .../xpack/sql/SqlUsageTransportAction.java | 72 +++++ .../xpack/sql/plugin/SqlPlugin.java | 22 +- ....java => SqlInfoTransportActionTests.java} | 10 +- .../elasticsearch/xpack/vectors/Vectors.java | 17 +- .../xpack/vectors/VectorsFeatureSet.java | 75 ----- .../vectors/VectorsInfoTransportAction.java | 46 +++ .../vectors/VectorsUsageTransportAction.java | 46 +++ ...a => VectorsInfoTransportActionTests.java} | 12 +- .../elasticsearch/xpack/watcher/Watcher.java | 11 +- .../xpack/watcher/WatcherFeatureSet.java | 108 ------- .../watcher/WatcherInfoTransportAction.java | 46 +++ .../watcher/WatcherUsageTransportAction.java | 79 ++++++ ...a => WatcherInfoTransportActionTests.java} | 10 +- 69 files changed, 2023 insertions(+), 1712 deletions(-) rename x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/{CCRFeatureSetTests.java => CCRInfoTransportActionTests.java} (82%) rename x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/ccr/{CCRFeatureSet.java => CCRInfoTransportAction.java} (57%) create mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/ccr/CCRUsageTransportAction.java create mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureAction.java create mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureResponse.java create mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureTransportAction.java delete mode 100644 x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrameFeatureSet.java create mode 100644 x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrameInfoTransportAction.java create mode 100644 x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrameUsageTransportAction.java rename x-pack/plugin/data-frame/src/test/java/org/elasticsearch/xpack/dataframe/{DataFrameFeatureSetTests.java => DataFrameInfoTransportActionTests.java} (82%) delete mode 100644 x-pack/plugin/graph/src/main/java/org/elasticsearch/xpack/graph/GraphFeatureSet.java create mode 100644 x-pack/plugin/graph/src/main/java/org/elasticsearch/xpack/graph/GraphInfoTransportAction.java create mode 100644 x-pack/plugin/graph/src/main/java/org/elasticsearch/xpack/graph/GraphUsageTransportAction.java rename x-pack/plugin/graph/src/test/java/org/elasticsearch/xpack/graph/{GraphFeatureSetTests.java => GraphInfoTransportActionTests.java} (82%) delete mode 100644 x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleFeatureSet.java create mode 100644 x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleInfoTransportAction.java create mode 100644 x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleUsageTransportAction.java rename x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/{IndexLifecycleFeatureSetTests.java => IndexLifecycleInfoTransportActionTests.java} (85%) delete mode 100644 x-pack/plugin/logstash/src/main/java/org/elasticsearch/xpack/logstash/LogstashFeatureSet.java create mode 100644 x-pack/plugin/logstash/src/main/java/org/elasticsearch/xpack/logstash/LogstashInfoTransportAction.java create mode 100644 x-pack/plugin/logstash/src/main/java/org/elasticsearch/xpack/logstash/LogstashUsageTransportAction.java rename x-pack/plugin/logstash/src/test/java/org/elasticsearch/xpack/logstash/{LogstashFeatureSetTests.java => LogstashInfoTransportActionTests.java} (78%) delete mode 100644 x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MachineLearningFeatureSet.java create mode 100644 x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MachineLearningInfoTransportAction.java create mode 100644 x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MachineLearningUsageTransportAction.java rename x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/{MachineLearningFeatureSetTests.java => MachineLearningInfoTransportActionTests.java} (93%) create mode 100644 x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/MonitoringInfoTransportAction.java rename x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/{MonitoringFeatureSet.java => MonitoringUsageTransportAction.java} (50%) rename x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/{MonitoringFeatureSetTests.java => MonitoringInfoTransportActionTests.java} (89%) delete mode 100644 x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/RollupFeatureSet.java create mode 100644 x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/RollupInfoTransportAction.java create mode 100644 x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/RollupUsageTransportAction.java rename x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/{RollupFeatureSetTests.java => RollupInfoTransportActionTests.java} (78%) delete mode 100644 x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityFeatureSet.java create mode 100644 x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityInfoTransportAction.java create mode 100644 x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityUsageTransportAction.java rename x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/{SecurityFeatureSetTests.java => SecurityInfoTransportActionTests.java} (95%) delete mode 100644 x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/SqlFeatureSet.java create mode 100644 x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/SqlInfoTransportAction.java create mode 100644 x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/SqlUsageTransportAction.java rename x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/{SqlFeatureSetTests.java => SqlInfoTransportActionTests.java} (90%) delete mode 100644 x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/VectorsFeatureSet.java create mode 100644 x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/VectorsInfoTransportAction.java create mode 100644 x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/VectorsUsageTransportAction.java rename x-pack/plugin/vectors/src/test/java/org/elasticsearch/xpack/vectors/{VectorsFeatureSetTests.java => VectorsInfoTransportActionTests.java} (82%) delete mode 100644 x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherFeatureSet.java create mode 100644 x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherInfoTransportAction.java create mode 100644 x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherUsageTransportAction.java rename x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/{WatcherFeatureSetTests.java => WatcherInfoTransportActionTests.java} (92%) diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/Ccr.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/Ccr.java index a9d0efbd14c54..b926bc986510b 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/Ccr.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/Ccr.java @@ -18,7 +18,6 @@ import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.ParseField; -import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.IndexScopedSettings; @@ -87,6 +86,7 @@ import org.elasticsearch.xpack.ccr.rest.RestResumeFollowAction; import org.elasticsearch.xpack.ccr.rest.RestUnfollowAction; import org.elasticsearch.xpack.core.XPackPlugin; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; import org.elasticsearch.xpack.core.ccr.AutoFollowMetadata; import org.elasticsearch.xpack.core.ccr.ShardFollowNodeTaskStatus; @@ -112,7 +112,6 @@ import java.util.function.Supplier; import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; import static org.elasticsearch.xpack.ccr.CcrSettings.CCR_FOLLOWING_INDEX_SETTING; import static org.elasticsearch.xpack.core.XPackSettings.CCR_ENABLED_SETTING; @@ -201,9 +200,10 @@ public List> getPersistentTasksExecutor(ClusterServic } public List> getActions() { - var usageAction = new ActionHandler<>(XPackUsageFeatureAction.CCR, CCRFeatureSet.UsageTransportAction.class); + var usageAction = new ActionHandler<>(XPackUsageFeatureAction.CCR, CCRUsageTransportAction.class); + var infoAction = new ActionHandler<>(XPackInfoFeatureAction.CCR, CCRInfoTransportAction.class); if (enabled == false) { - return singletonList(usageAction); + return Arrays.asList(usageAction, infoAction); } return Arrays.asList( @@ -235,7 +235,8 @@ public List> getPersistentTasksExecutor(ClusterServic new ActionHandler<>(GetAutoFollowPatternAction.INSTANCE, TransportGetAutoFollowPatternAction.class), // forget follower action new ActionHandler<>(ForgetFollowerAction.INSTANCE, TransportForgetFollowerAction.class), - usageAction); + usageAction, + infoAction); } public List getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings, @@ -341,11 +342,6 @@ public void onIndexModule(IndexModule indexModule) { } } - @Override - public Collection createGuiceModules() { - return Collections.singleton(b -> XPackPlugin.bindFeatureSet(b, CCRFeatureSet.class)); - } - protected XPackLicenseState getLicenseState() { return XPackPlugin.getSharedLicenseState(); } @Override diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRFeatureSetUsageTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRFeatureSetUsageTests.java index 9422642d9f73d..4242c2fde04bc 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRFeatureSetUsageTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRFeatureSetUsageTests.java @@ -9,16 +9,16 @@ import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.test.AbstractWireSerializingTestCase; -public class CCRFeatureSetUsageTests extends AbstractWireSerializingTestCase { +public class CCRFeatureSetUsageTests extends AbstractWireSerializingTestCase { @Override - protected CCRFeatureSet.Usage createTestInstance() { - return new CCRFeatureSet.Usage(randomBoolean(), randomBoolean(), randomIntBetween(0, Integer.MAX_VALUE), + protected CCRInfoTransportAction.Usage createTestInstance() { + return new CCRInfoTransportAction.Usage(randomBoolean(), randomBoolean(), randomIntBetween(0, Integer.MAX_VALUE), randomIntBetween(0, Integer.MAX_VALUE), randomNonNegativeLong()); } @Override - protected Writeable.Reader instanceReader() { - return CCRFeatureSet.Usage::new; + protected Writeable.Reader instanceReader() { + return CCRInfoTransportAction.Usage::new; } } diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRFeatureSetTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRInfoTransportActionTests.java similarity index 82% rename from x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRFeatureSetTests.java rename to x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRInfoTransportActionTests.java index 9de0efa31cb55..80a2fb35c318a 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRFeatureSetTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRInfoTransportActionTests.java @@ -32,7 +32,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class CCRFeatureSetTests extends ESTestCase { +public class CCRInfoTransportActionTests extends ESTestCase { private XPackLicenseState licenseState; private ClusterService clusterService; @@ -44,7 +44,8 @@ public void init() { } public void testAvailable() { - CCRFeatureSet featureSet = new CCRFeatureSet(Settings.EMPTY, licenseState); + CCRInfoTransportAction featureSet = new CCRInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, licenseState); when(licenseState.isCcrAllowed()).thenReturn(false); assertThat(featureSet.available(), equalTo(false)); @@ -52,22 +53,25 @@ public void testAvailable() { when(licenseState.isCcrAllowed()).thenReturn(true); assertThat(featureSet.available(), equalTo(true)); - featureSet = new CCRFeatureSet(Settings.EMPTY, null); + featureSet = new CCRInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, null); assertThat(featureSet.available(), equalTo(false)); } public void testEnabled() { Settings.Builder settings = Settings.builder().put("xpack.ccr.enabled", false); - CCRFeatureSet featureSet = new CCRFeatureSet(settings.build(), licenseState); + CCRInfoTransportAction featureSet = new CCRInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), settings.build(), licenseState); assertThat(featureSet.enabled(), equalTo(false)); settings = Settings.builder().put("xpack.ccr.enabled", true); - featureSet = new CCRFeatureSet(settings.build(), licenseState); + featureSet = new CCRInfoTransportAction(mock(TransportService.class), null, settings.build(), licenseState); assertThat(featureSet.enabled(), equalTo(true)); } public void testName() { - CCRFeatureSet featureSet = new CCRFeatureSet(Settings.EMPTY, licenseState); + CCRInfoTransportAction featureSet = new CCRInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, licenseState); assertThat(featureSet.name(), equalTo("ccr")); } @@ -105,11 +109,11 @@ public void testUsageStats() throws Exception { ClusterState clusterState = ClusterState.builder(new ClusterName("_name")).metaData(metaData).build(); Mockito.when(clusterService.state()).thenReturn(clusterState); - var usageAction = new CCRFeatureSet.UsageTransportAction(mock(TransportService.class), null, null, + var usageAction = new CCRUsageTransportAction(mock(TransportService.class), null, null, mock(ActionFilters.class), null, Settings.EMPTY, licenseState); PlainActionFuture future = new PlainActionFuture<>(); usageAction.masterOperation(null, clusterState, future); - CCRFeatureSet.Usage ccrUsage = (CCRFeatureSet.Usage) future.get().getUsage(); + CCRInfoTransportAction.Usage ccrUsage = (CCRInfoTransportAction.Usage) future.get().getUsage(); assertThat(ccrUsage.enabled(), equalTo(true)); assertThat(ccrUsage.available(), equalTo(false)); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/ccr/CCRFeatureSet.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/ccr/CCRInfoTransportAction.java similarity index 57% rename from x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/ccr/CCRFeatureSet.java rename to x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/ccr/CCRInfoTransportAction.java index 128b191ad34db..9f6c3b1467e8d 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/ccr/CCRFeatureSet.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/ccr/CCRInfoTransportAction.java @@ -5,41 +5,32 @@ */ package org.elasticsearch.xpack.ccr; -import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.ActionFilters; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.metadata.IndexMetaData; -import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; -import org.elasticsearch.cluster.metadata.MetaData; -import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.license.XPackLicenseState; -import org.elasticsearch.protocol.xpack.XPackUsageRequest; -import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; import org.elasticsearch.xpack.core.XPackFeatureSet; import org.elasticsearch.xpack.core.XPackField; import org.elasticsearch.xpack.core.XPackSettings; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; -import org.elasticsearch.xpack.core.ccr.AutoFollowMetadata; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureTransportAction; import java.io.IOException; -import java.time.Instant; import java.util.Objects; -public class CCRFeatureSet implements XPackFeatureSet { +public class CCRInfoTransportAction extends XPackInfoFeatureTransportAction { private final boolean enabled; private final XPackLicenseState licenseState; @Inject - public CCRFeatureSet(Settings settings, XPackLicenseState licenseState) { + public CCRInfoTransportAction(TransportService transportService, ActionFilters actionFilters, + Settings settings, XPackLicenseState licenseState) { + super(XPackInfoFeatureAction.CCR.name(), transportService, actionFilters); this.enabled = XPackSettings.CCR_ENABLED_SETTING.get(settings); this.licenseState = licenseState; } @@ -51,7 +42,7 @@ public String name() { @Override public boolean available() { - return licenseState != null && licenseState.isCcrAllowed(); + return licenseState.isCcrAllowed(); } @Override @@ -59,52 +50,6 @@ public boolean enabled() { return enabled; } - public static class UsageTransportAction extends XPackUsageFeatureTransportAction { - - private final Settings settings; - private final XPackLicenseState licenseState; - - @Inject - public UsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, - ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, - Settings settings, XPackLicenseState licenseState) { - super(XPackUsageFeatureAction.CCR.name(), transportService, clusterService, - threadPool, actionFilters, indexNameExpressionResolver); - this.settings = settings; - this.licenseState = licenseState; - } - - @Override - protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { - MetaData metaData = state.metaData(); - - int numberOfFollowerIndices = 0; - long lastFollowerIndexCreationDate = 0L; - for (IndexMetaData imd : metaData) { - if (imd.getCustomData("ccr") != null) { - numberOfFollowerIndices++; - if (lastFollowerIndexCreationDate < imd.getCreationDate()) { - lastFollowerIndexCreationDate = imd.getCreationDate(); - } - } - } - AutoFollowMetadata autoFollowMetadata = metaData.custom(AutoFollowMetadata.TYPE); - int numberOfAutoFollowPatterns = autoFollowMetadata != null ? autoFollowMetadata.getPatterns().size() : 0; - - Long lastFollowTimeInMillis; - if (numberOfFollowerIndices == 0) { - // Otherwise we would return a value that makes no sense. - lastFollowTimeInMillis = null; - } else { - lastFollowTimeInMillis = Math.max(0, Instant.now().toEpochMilli() - lastFollowerIndexCreationDate); - } - - Usage usage = new Usage(licenseState.isCcrAllowed(), XPackSettings.CCR_ENABLED_SETTING.get(settings), - numberOfFollowerIndices, numberOfAutoFollowPatterns, lastFollowTimeInMillis); - listener.onResponse(new XPackUsageFeatureResponse(usage)); - } - } - public static class Usage extends XPackFeatureSet.Usage { private final int numberOfFollowerIndices; diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/ccr/CCRUsageTransportAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/ccr/CCRUsageTransportAction.java new file mode 100644 index 0000000000000..6e69aca503fe2 --- /dev/null +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/ccr/CCRUsageTransportAction.java @@ -0,0 +1,73 @@ +/* + * 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.xpack.ccr; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.IndexMetaData; +import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.cluster.metadata.MetaData; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.protocol.xpack.XPackUsageRequest; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; +import org.elasticsearch.xpack.core.ccr.AutoFollowMetadata; + +import java.time.Instant; + +public class CCRUsageTransportAction extends XPackUsageFeatureTransportAction { + + private final Settings settings; + private final XPackLicenseState licenseState; + + @Inject + public CCRUsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, + ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, + Settings settings, XPackLicenseState licenseState) { + super(XPackUsageFeatureAction.CCR.name(), transportService, clusterService, + threadPool, actionFilters, indexNameExpressionResolver); + this.settings = settings; + this.licenseState = licenseState; + } + + @Override + protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { + MetaData metaData = state.metaData(); + + int numberOfFollowerIndices = 0; + long lastFollowerIndexCreationDate = 0L; + for (IndexMetaData imd : metaData) { + if (imd.getCustomData("ccr") != null) { + numberOfFollowerIndices++; + if (lastFollowerIndexCreationDate < imd.getCreationDate()) { + lastFollowerIndexCreationDate = imd.getCreationDate(); + } + } + } + AutoFollowMetadata autoFollowMetadata = metaData.custom(AutoFollowMetadata.TYPE); + int numberOfAutoFollowPatterns = autoFollowMetadata != null ? autoFollowMetadata.getPatterns().size() : 0; + + Long lastFollowTimeInMillis; + if (numberOfFollowerIndices == 0) { + // Otherwise we would return a value that makes no sense. + lastFollowTimeInMillis = null; + } else { + lastFollowTimeInMillis = Math.max(0, Instant.now().toEpochMilli() - lastFollowerIndexCreationDate); + } + + CCRInfoTransportAction.Usage usage = new CCRInfoTransportAction.Usage(licenseState.isCcrAllowed(), + XPackSettings.CCR_ENABLED_SETTING.get(settings), numberOfFollowerIndices, numberOfAutoFollowPatterns, lastFollowTimeInMillis); + listener.onResponse(new XPackUsageFeatureResponse(usage)); + } +} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java index 1930c05bc38eb..eb05b3f013b81 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java @@ -35,7 +35,7 @@ import org.elasticsearch.xpack.core.action.XPackUsageAction; import org.elasticsearch.xpack.core.beats.BeatsFeatureSetUsage; import org.elasticsearch.xpack.core.ccr.AutoFollowMetadata; -import org.elasticsearch.xpack.ccr.CCRFeatureSet; +import org.elasticsearch.xpack.ccr.CCRInfoTransportAction; import org.elasticsearch.xpack.core.dataframe.DataFrameFeatureSetUsage; import org.elasticsearch.xpack.core.dataframe.DataFrameField; import org.elasticsearch.xpack.core.dataframe.action.DeleteDataFrameTransformAction; @@ -413,7 +413,7 @@ public List getNamedWriteables() { new NamedWriteableRegistry.Entry(MetaData.Custom.class, AutoFollowMetadata.TYPE, AutoFollowMetadata::new), new NamedWriteableRegistry.Entry(NamedDiff.class, AutoFollowMetadata.TYPE, in -> AutoFollowMetadata.readDiffFrom(MetaData.Custom.class, AutoFollowMetadata.TYPE, in)), - new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, XPackField.CCR, CCRFeatureSet.Usage::new), + new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, XPackField.CCR, CCRInfoTransportAction.Usage::new), // ILM new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, XPackField.INDEX_LIFECYCLE, IndexLifecycleFeatureSetUsage::new), diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackInfoAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackInfoAction.java index 51b1464f8a0e0..00a81051a6478 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackInfoAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackInfoAction.java @@ -8,6 +8,7 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.ActionFilters; import org.elasticsearch.action.support.HandledTransportAction; +import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.license.License; import org.elasticsearch.license.LicenseService; @@ -16,25 +17,29 @@ import org.elasticsearch.protocol.xpack.XPackInfoResponse.FeatureSetsInfo.FeatureSet; import org.elasticsearch.protocol.xpack.XPackInfoResponse.LicenseInfo; import org.elasticsearch.tasks.Task; +import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; import org.elasticsearch.xpack.core.XPackBuild; -import org.elasticsearch.xpack.core.XPackFeatureSet; +import org.elasticsearch.xpack.core.common.IteratingActionListener; -import java.util.Set; -import java.util.stream.Collectors; +import java.util.HashSet; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReferenceArray; public class TransportXPackInfoAction extends HandledTransportAction { private final LicenseService licenseService; - private final Set featureSets; + private final NodeClient client; + private final ThreadPool threadPool; @Inject public TransportXPackInfoAction(TransportService transportService, ActionFilters actionFilters, LicenseService licenseService, - Set featureSets) { + NodeClient client, ThreadPool threadPool) { super(XPackInfoAction.NAME, transportService, actionFilters, XPackInfoRequest::new); this.licenseService = licenseService; - this.featureSets = featureSets; + this.client = client; + this.threadPool = threadPool; } @Override @@ -55,14 +60,28 @@ protected void doExecute(Task task, XPackInfoRequest request, ActionListener featureSets = this.featureSets.stream().map(fs -> - new FeatureSet(fs.name(), fs.available(), fs.enabled())) - .collect(Collectors.toSet()); - featureSetsInfo = new XPackInfoResponse.FeatureSetsInfo(featureSets); - } + final var position = new AtomicInteger(0); + var featureSets = new AtomicReferenceArray(XPackInfoFeatureAction.ALL.size()); + final XPackInfoResponse.BuildInfo finalBuildInfo = buildInfo; + final LicenseInfo finalLicenseInfo = licenseInfo; + + ActionListener finalListener = ActionListener.wrap(ignore -> { + var featureSetsSet = new HashSet(featureSets.length()); + for (int i = 0; i < featureSets.length(); i++) { + featureSetsSet.add(featureSets.get(i)); + } + var featureSetsInfo = new XPackInfoResponse.FeatureSetsInfo(featureSetsSet); + listener.onResponse(new XPackInfoResponse(finalBuildInfo, finalLicenseInfo, featureSetsInfo)); + }, listener::onFailure); - listener.onResponse(new XPackInfoResponse(buildInfo, licenseInfo, featureSetsInfo)); + new IteratingActionListener<>(finalListener, (infoAction, iteratingListener) -> + client.executeLocally(infoAction, request, ActionListener.wrap(response -> + featureSets.set(position.getAndIncrement(), response.getInfo()), iteratingListener::onFailure)), + XPackInfoFeatureAction.ALL, + threadPool.getThreadContext()).run(); + } else { + listener.onResponse(new XPackInfoResponse(buildInfo, licenseInfo, null)); + } } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackUsageAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackUsageAction.java index 42f14ee7cba2a..02927c48e4ae6 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackUsageAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackUsageAction.java @@ -59,6 +59,7 @@ protected XPackUsageResponse newResponse() { } @Override + protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { final ActionListener> usageActionListener = new ActionListener<>() { @Override diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureAction.java new file mode 100644 index 0000000000000..8c7ee957bd5bc --- /dev/null +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureAction.java @@ -0,0 +1,55 @@ +/* + * 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.xpack.core.action; + +import org.elasticsearch.action.Action; +import org.elasticsearch.xpack.core.XPackField; + +import java.util.Arrays; +import java.util.List; + +/** + * A base action for for usage of a feature plugin. + * + * This action is implemented by each feature plugin, bound to the public constants here. The + * {@link XPackUsageAction} implementationn iterates over the {@link #ALL} list of actions to form + * the complete usage result. + */ +public class XPackInfoFeatureAction extends Action { + + private static final String BASE_NAME = "cluster:monitor/xpack/info/"; + + public static final XPackInfoFeatureAction SECURITY = new XPackInfoFeatureAction(XPackField.SECURITY); + public static final XPackInfoFeatureAction MONITORING = new XPackInfoFeatureAction(XPackField.MONITORING); + public static final XPackInfoFeatureAction WATCHER = new XPackInfoFeatureAction(XPackField.WATCHER); + public static final XPackInfoFeatureAction GRAPH = new XPackInfoFeatureAction(XPackField.GRAPH); + public static final XPackInfoFeatureAction MACHINE_LEARNING = new XPackInfoFeatureAction(XPackField.MACHINE_LEARNING); + public static final XPackInfoFeatureAction LOGSTASH = new XPackInfoFeatureAction(XPackField.LOGSTASH); + public static final XPackInfoFeatureAction SQL = new XPackInfoFeatureAction(XPackField.SQL); + public static final XPackInfoFeatureAction ROLLUP = new XPackInfoFeatureAction(XPackField.ROLLUP); + public static final XPackInfoFeatureAction INDEX_LIFECYCLE = new XPackInfoFeatureAction(XPackField.INDEX_LIFECYCLE); + public static final XPackInfoFeatureAction CCR = new XPackInfoFeatureAction(XPackField.CCR); + public static final XPackInfoFeatureAction DATA_FRAME = new XPackInfoFeatureAction(XPackField.DATA_FRAME); + public static final XPackInfoFeatureAction VECTORS = new XPackInfoFeatureAction(XPackField.VECTORS); + + public static final List ALL = Arrays.asList( + SECURITY, MONITORING, WATCHER, GRAPH, MACHINE_LEARNING, LOGSTASH, SQL, ROLLUP, INDEX_LIFECYCLE, CCR, DATA_FRAME, VECTORS + ); + + private XPackInfoFeatureAction(String name) { + super(BASE_NAME + name); + } + + @Override + public XPackInfoFeatureResponse newResponse() { + return new XPackInfoFeatureResponse(); + } + + @Override + public String toString() { + return "Action [" + name() + "]"; + } +} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureResponse.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureResponse.java new file mode 100644 index 0000000000000..b40a0778d81da --- /dev/null +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureResponse.java @@ -0,0 +1,42 @@ +/* + * 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.xpack.core.action; + +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.protocol.xpack.XPackInfoResponse.FeatureSetsInfo.FeatureSet; + +import java.io.IOException; + +public class XPackInfoFeatureResponse extends ActionResponse { + + private FeatureSet info; + + public XPackInfoFeatureResponse() { + // empty, for readFrom + } + + public XPackInfoFeatureResponse(FeatureSet info) { + this.info = info; + } + + public FeatureSet getInfo() { + return info; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + info.writeTo(out); + } + + @Override + public void readFrom(StreamInput in) throws IOException { + super.readFrom(in); + info = new FeatureSet(in); + } +} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureTransportAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureTransportAction.java new file mode 100644 index 0000000000000..f352240783534 --- /dev/null +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureTransportAction.java @@ -0,0 +1,32 @@ +/* + * 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.xpack.core.action; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.HandledTransportAction; +import org.elasticsearch.protocol.xpack.XPackInfoRequest; +import org.elasticsearch.protocol.xpack.XPackInfoResponse.FeatureSetsInfo.FeatureSet; +import org.elasticsearch.tasks.Task; +import org.elasticsearch.transport.TransportService; + +public abstract class XPackInfoFeatureTransportAction extends HandledTransportAction { + + public XPackInfoFeatureTransportAction(String name, TransportService transportService, ActionFilters actionFilters) { + super(name, transportService, actionFilters, XPackInfoRequest::new); + } + + protected abstract String name(); + + protected abstract boolean available(); + + protected abstract boolean enabled(); + + @Override + protected void doExecute(Task task, XPackInfoRequest request, ActionListener listener) { + listener.onResponse(new XPackInfoFeatureResponse(new FeatureSet(name(), available(), enabled()))); + } +} diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/action/TransportXPackInfoActionTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/action/TransportXPackInfoActionTests.java index 33500271de936..09fc9c94c2353 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/action/TransportXPackInfoActionTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/action/TransportXPackInfoActionTests.java @@ -7,6 +7,7 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.license.License; import org.elasticsearch.license.LicenseService; @@ -57,7 +58,7 @@ public void testDoExecute() throws Exception { TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null, TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet()); TransportXPackInfoAction action = new TransportXPackInfoAction(transportService, mock(ActionFilters.class), - licenseService, featureSets); + licenseService, mock(NodeClient.class), null); License license = mock(License.class); long expiryDate = randomLong(); diff --git a/x-pack/plugin/data-frame/qa/single-node-tests/src/test/java/org/elasticsearch/xpack/dataframe/integration/DataFrameUsageIT.java b/x-pack/plugin/data-frame/qa/single-node-tests/src/test/java/org/elasticsearch/xpack/dataframe/integration/DataFrameUsageIT.java index 2058e0b9b2c2f..b39ee6b1e6943 100644 --- a/x-pack/plugin/data-frame/qa/single-node-tests/src/test/java/org/elasticsearch/xpack/dataframe/integration/DataFrameUsageIT.java +++ b/x-pack/plugin/data-frame/qa/single-node-tests/src/test/java/org/elasticsearch/xpack/dataframe/integration/DataFrameUsageIT.java @@ -20,7 +20,7 @@ import java.util.Map; import static org.elasticsearch.xpack.core.dataframe.DataFrameField.INDEX_DOC_TYPE; -import static org.elasticsearch.xpack.dataframe.DataFrameFeatureSet.PROVIDED_STATS; +import static org.elasticsearch.xpack.dataframe.DataFrameInfoTransportAction.PROVIDED_STATS; public class DataFrameUsageIT extends DataFrameRestTestCase { diff --git a/x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrame.java b/x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrame.java index 32d61c0285346..3828f15b34995 100644 --- a/x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrame.java +++ b/x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrame.java @@ -16,7 +16,6 @@ import org.elasticsearch.cluster.metadata.IndexTemplateMetaData; import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.service.ClusterService; -import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.IndexScopedSettings; @@ -73,7 +72,6 @@ import java.io.IOException; import java.time.Clock; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -83,7 +81,6 @@ import java.util.function.UnaryOperator; import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; public class DataFrame extends Plugin implements ActionPlugin, PersistentTaskPlugin { @@ -104,13 +101,6 @@ public DataFrame(Settings settings) { this.enabled = XPackSettings.DATA_FRAME_ENABLED.get(settings); } - @Override - public Collection createGuiceModules() { - List modules = new ArrayList<>(); - modules.add(b -> XPackPlugin.bindFeatureSet(b, DataFrameFeatureSet.class)); - return modules; - } - protected XPackLicenseState getLicenseState() { return XPackPlugin.getSharedLicenseState(); } @Override @@ -135,9 +125,10 @@ public List getRestHandlers(final Settings settings, final RestCont @Override public List> getActions() { - var usageAction = new ActionHandler<>(XPackUsageFeatureAction.DATA_FRAME, DataFrameFeatureSet.UsageTransportAction.class); - if (!enabled) { - return singletonList(usageAction); + var usageAction = new ActionHandler<>(XPackUsageFeatureAction.DATA_FRAME, DataFrameUsageTransportAction.class); + var infoAction = new ActionHandler<>(XPackUsageFeatureAction.DATA_FRAME, DataFrameUsageTransportAction.class); + if (enabled == false) { + return Arrays.asList(usageAction, infoAction); } return Arrays.asList( @@ -149,7 +140,8 @@ public List getRestHandlers(final Settings settings, final RestCont new ActionHandler<>(GetDataFrameTransformsAction.INSTANCE, TransportGetDataFrameTransformsAction.class), new ActionHandler<>(GetDataFrameTransformsStatsAction.INSTANCE, TransportGetDataFrameTransformsStatsAction.class), new ActionHandler<>(PreviewDataFrameTransformAction.INSTANCE, TransportPreviewDataFrameTransformAction.class), - usageAction); + usageAction, + infoAction); } @Override diff --git a/x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrameFeatureSet.java b/x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrameFeatureSet.java deleted file mode 100644 index 9d64906be83a6..0000000000000 --- a/x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrameFeatureSet.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * 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.xpack.dataframe; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.elasticsearch.ResourceNotFoundException; -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.action.search.SearchRequest; -import org.elasticsearch.action.search.SearchRequestBuilder; -import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.support.ActionFilters; -import org.elasticsearch.client.Client; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; -import org.elasticsearch.cluster.service.ClusterService; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.index.query.QueryBuilders; -import org.elasticsearch.license.XPackLicenseState; -import org.elasticsearch.persistent.PersistentTasksCustomMetaData; -import org.elasticsearch.protocol.xpack.XPackUsageRequest; -import org.elasticsearch.search.aggregations.Aggregation; -import org.elasticsearch.search.aggregations.AggregationBuilders; -import org.elasticsearch.search.aggregations.metrics.NumericMetricsAggregation; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.TransportService; -import org.elasticsearch.xpack.core.ClientHelper; -import org.elasticsearch.xpack.core.XPackFeatureSet; -import org.elasticsearch.xpack.core.XPackField; -import org.elasticsearch.xpack.core.XPackSettings; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; -import org.elasticsearch.xpack.core.dataframe.DataFrameFeatureSetUsage; -import org.elasticsearch.xpack.core.dataframe.DataFrameField; -import org.elasticsearch.xpack.core.dataframe.transforms.DataFrameIndexerTransformStats; -import org.elasticsearch.xpack.core.dataframe.transforms.DataFrameTransform; -import org.elasticsearch.xpack.core.dataframe.transforms.DataFrameTransformConfig; -import org.elasticsearch.xpack.core.dataframe.transforms.DataFrameTransformState; -import org.elasticsearch.xpack.core.dataframe.transforms.DataFrameTransformStateAndStats; -import org.elasticsearch.xpack.core.dataframe.transforms.DataFrameTransformTaskState; -import org.elasticsearch.xpack.dataframe.persistence.DataFrameInternalIndex; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - - -public class DataFrameFeatureSet implements XPackFeatureSet { - - private final boolean enabled; - private final XPackLicenseState licenseState; - - private static final Logger logger = LogManager.getLogger(DataFrameFeatureSet.class); - - public static final String[] PROVIDED_STATS = new String[] { - DataFrameIndexerTransformStats.NUM_PAGES.getPreferredName(), - DataFrameIndexerTransformStats.NUM_INPUT_DOCUMENTS.getPreferredName(), - DataFrameIndexerTransformStats.NUM_OUTPUT_DOCUMENTS.getPreferredName(), - DataFrameIndexerTransformStats.NUM_INVOCATIONS.getPreferredName(), - DataFrameIndexerTransformStats.INDEX_TIME_IN_MS.getPreferredName(), - DataFrameIndexerTransformStats.SEARCH_TIME_IN_MS.getPreferredName(), - DataFrameIndexerTransformStats.INDEX_TOTAL.getPreferredName(), - DataFrameIndexerTransformStats.SEARCH_TOTAL.getPreferredName(), - DataFrameIndexerTransformStats.INDEX_FAILURES.getPreferredName(), - DataFrameIndexerTransformStats.SEARCH_FAILURES.getPreferredName(), - }; - - @Inject - public DataFrameFeatureSet(Settings settings, XPackLicenseState licenseState) { - this.enabled = XPackSettings.DATA_FRAME_ENABLED.get(settings); - this.licenseState = licenseState; - } - - @Override - public String name() { - return XPackField.DATA_FRAME; - } - - @Override - public boolean available() { - return licenseState != null && licenseState.isDataFrameAllowed(); - } - - @Override - public boolean enabled() { - return enabled; - } - - public static class UsageTransportAction extends XPackUsageFeatureTransportAction { - - private final boolean enabled; - private final XPackLicenseState licenseState; - private final Client client; - - @Inject - public UsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, - ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, - Settings settings, XPackLicenseState licenseState, Client client) { - super(XPackUsageFeatureAction.DATA_FRAME.name(), transportService, clusterService, - threadPool, actionFilters, indexNameExpressionResolver); - this.enabled = XPackSettings.DATA_FRAME_ENABLED.get(settings); - this.licenseState = licenseState; - this.client = client; - } - - @Override - protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { - boolean available = licenseState.isDataFrameAllowed(); - if (enabled == false) { - var usage = new DataFrameFeatureSetUsage(available, enabled, Collections.emptyMap(), - DataFrameIndexerTransformStats.withDefaultTransformId()); - listener.onResponse(new XPackUsageFeatureResponse(usage)); - return; - } - - PersistentTasksCustomMetaData taskMetadata = PersistentTasksCustomMetaData.getPersistentTasksCustomMetaData(state); - Collection> dataFrameTasks = taskMetadata == null ? - Collections.emptyList() : - taskMetadata.findTasks(DataFrameTransform.NAME, (t) -> true); - final int taskCount = dataFrameTasks.size(); - final Map transformsCountByState = new HashMap<>(); - for(PersistentTasksCustomMetaData.PersistentTask dataFrameTask : dataFrameTasks) { - DataFrameTransformState transformState = (DataFrameTransformState)dataFrameTask.getState(); - transformsCountByState.merge(transformState.getTaskState().value(), 1L, Long::sum); - } - - ActionListener totalStatsListener = ActionListener.wrap( - statSummations -> { - var usage = new DataFrameFeatureSetUsage(available, enabled, transformsCountByState, statSummations); - listener.onResponse(new XPackUsageFeatureResponse(usage)); - }, - listener::onFailure - ); - - ActionListener totalTransformCountListener = ActionListener.wrap( - transformCountSuccess -> { - if (transformCountSuccess.getShardFailures().length > 0) { - logger.error("total transform count search returned shard failures: {}", - Arrays.toString(transformCountSuccess.getShardFailures())); - } - long totalTransforms = transformCountSuccess.getHits().getTotalHits().value; - if (totalTransforms == 0) { - var usage = new DataFrameFeatureSetUsage(available, enabled, transformsCountByState, - DataFrameIndexerTransformStats.withDefaultTransformId()); - listener.onResponse(new XPackUsageFeatureResponse(usage)); - return; - } - transformsCountByState.merge(DataFrameTransformTaskState.STOPPED.value(), totalTransforms - taskCount, Long::sum); - getStatisticSummations(client, totalStatsListener); - }, - transformCountFailure -> { - if (transformCountFailure instanceof ResourceNotFoundException) { - getStatisticSummations(client, totalStatsListener); - } else { - listener.onFailure(transformCountFailure); - } - } - ); - - SearchRequest totalTransformCount = client.prepareSearch(DataFrameInternalIndex.INDEX_NAME) - .setTrackTotalHits(true) - .setQuery(QueryBuilders.constantScoreQuery(QueryBuilders.boolQuery() - .filter(QueryBuilders.termQuery(DataFrameField.INDEX_DOC_TYPE.getPreferredName(), DataFrameTransformConfig.NAME)))) - .request(); - - ClientHelper.executeAsyncWithOrigin(client.threadPool().getThreadContext(), - ClientHelper.DATA_FRAME_ORIGIN, - totalTransformCount, - totalTransformCountListener, - client::search); - } - } - - static DataFrameIndexerTransformStats parseSearchAggs(SearchResponse searchResponse) { - List statisticsList = new ArrayList<>(PROVIDED_STATS.length); - - for(String statName : PROVIDED_STATS) { - Aggregation agg = searchResponse.getAggregations().get(statName); - - if (agg instanceof NumericMetricsAggregation.SingleValue) { - statisticsList.add((long)((NumericMetricsAggregation.SingleValue)agg).value()); - } else { - statisticsList.add(0L); - } - } - return DataFrameIndexerTransformStats.withDefaultTransformId(statisticsList.get(0), // numPages - statisticsList.get(1), // numInputDocuments - statisticsList.get(2), // numOutputDocuments - statisticsList.get(3), // numInvocations - statisticsList.get(4), // indexTime - statisticsList.get(5), // searchTime - statisticsList.get(6), // indexTotal - statisticsList.get(7), // searchTotal - statisticsList.get(8), // indexFailures - statisticsList.get(9)); // searchFailures - } - - static void getStatisticSummations(Client client, ActionListener statsListener) { - QueryBuilder queryBuilder = QueryBuilders.constantScoreQuery(QueryBuilders.boolQuery() - .filter(QueryBuilders.termQuery(DataFrameField.INDEX_DOC_TYPE.getPreferredName(), - DataFrameTransformStateAndStats.NAME))); - - SearchRequestBuilder requestBuilder = client.prepareSearch(DataFrameInternalIndex.INDEX_NAME) - .setSize(0) - .setQuery(queryBuilder); - - final String path = DataFrameField.STATS_FIELD.getPreferredName() + "."; - for(String statName : PROVIDED_STATS) { - requestBuilder.addAggregation(AggregationBuilders.sum(statName).field(path + statName)); - } - - ActionListener getStatisticSummationsListener = ActionListener.wrap( - searchResponse -> { - if (searchResponse.getShardFailures().length > 0) { - logger.error("statistics summations search returned shard failures: {}", - Arrays.toString(searchResponse.getShardFailures())); - } - - statsListener.onResponse(parseSearchAggs(searchResponse)); - }, - failure -> { - if (failure instanceof ResourceNotFoundException) { - statsListener.onResponse(DataFrameIndexerTransformStats.withDefaultTransformId()); - } else { - statsListener.onFailure(failure); - } - } - ); - ClientHelper.executeAsyncWithOrigin(client.threadPool().getThreadContext(), - ClientHelper.DATA_FRAME_ORIGIN, - requestBuilder.request(), - getStatisticSummationsListener, - client::search); - } -} diff --git a/x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrameInfoTransportAction.java b/x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrameInfoTransportAction.java new file mode 100644 index 0000000000000..4988d0e71df97 --- /dev/null +++ b/x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrameInfoTransportAction.java @@ -0,0 +1,145 @@ +/* + * 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.xpack.dataframe; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.elasticsearch.ResourceNotFoundException; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.search.SearchRequestBuilder; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.client.Client; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.search.aggregations.Aggregation; +import org.elasticsearch.search.aggregations.AggregationBuilders; +import org.elasticsearch.search.aggregations.metrics.NumericMetricsAggregation; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.ClientHelper; +import org.elasticsearch.xpack.core.XPackField; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureTransportAction; +import org.elasticsearch.xpack.core.dataframe.DataFrameField; +import org.elasticsearch.xpack.core.dataframe.transforms.DataFrameIndexerTransformStats; +import org.elasticsearch.xpack.core.dataframe.transforms.DataFrameTransformStateAndStats; +import org.elasticsearch.xpack.dataframe.persistence.DataFrameInternalIndex; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + + +public class DataFrameInfoTransportAction extends XPackInfoFeatureTransportAction { + + private final boolean enabled; + private final XPackLicenseState licenseState; + + private static final Logger logger = LogManager.getLogger(DataFrameInfoTransportAction.class); + + public static final String[] PROVIDED_STATS = new String[] { + DataFrameIndexerTransformStats.NUM_PAGES.getPreferredName(), + DataFrameIndexerTransformStats.NUM_INPUT_DOCUMENTS.getPreferredName(), + DataFrameIndexerTransformStats.NUM_OUTPUT_DOCUMENTS.getPreferredName(), + DataFrameIndexerTransformStats.NUM_INVOCATIONS.getPreferredName(), + DataFrameIndexerTransformStats.INDEX_TIME_IN_MS.getPreferredName(), + DataFrameIndexerTransformStats.SEARCH_TIME_IN_MS.getPreferredName(), + DataFrameIndexerTransformStats.INDEX_TOTAL.getPreferredName(), + DataFrameIndexerTransformStats.SEARCH_TOTAL.getPreferredName(), + DataFrameIndexerTransformStats.INDEX_FAILURES.getPreferredName(), + DataFrameIndexerTransformStats.SEARCH_FAILURES.getPreferredName(), + }; + + @Inject + public DataFrameInfoTransportAction(TransportService transportService, ActionFilters actionFilters, + Settings settings, XPackLicenseState licenseState) { + super(XPackInfoFeatureAction.DATA_FRAME.name(), transportService, actionFilters); + this.enabled = XPackSettings.DATA_FRAME_ENABLED.get(settings); + this.licenseState = licenseState; + } + + @Override + public String name() { + return XPackField.DATA_FRAME; + } + + @Override + public boolean available() { + return licenseState.isDataFrameAllowed(); + } + + @Override + public boolean enabled() { + return enabled; + } + + static DataFrameIndexerTransformStats parseSearchAggs(SearchResponse searchResponse) { + List statisticsList = new ArrayList<>(PROVIDED_STATS.length); + + for(String statName : PROVIDED_STATS) { + Aggregation agg = searchResponse.getAggregations().get(statName); + + if (agg instanceof NumericMetricsAggregation.SingleValue) { + statisticsList.add((long)((NumericMetricsAggregation.SingleValue)agg).value()); + } else { + statisticsList.add(0L); + } + } + return DataFrameIndexerTransformStats.withDefaultTransformId(statisticsList.get(0), // numPages + statisticsList.get(1), // numInputDocuments + statisticsList.get(2), // numOutputDocuments + statisticsList.get(3), // numInvocations + statisticsList.get(4), // indexTime + statisticsList.get(5), // searchTime + statisticsList.get(6), // indexTotal + statisticsList.get(7), // searchTotal + statisticsList.get(8), // indexFailures + statisticsList.get(9)); // searchFailures + } + + static void getStatisticSummations(Client client, ActionListener statsListener) { + QueryBuilder queryBuilder = QueryBuilders.constantScoreQuery(QueryBuilders.boolQuery() + .filter(QueryBuilders.termQuery(DataFrameField.INDEX_DOC_TYPE.getPreferredName(), + DataFrameTransformStateAndStats.NAME))); + + SearchRequestBuilder requestBuilder = client.prepareSearch(DataFrameInternalIndex.INDEX_NAME) + .setSize(0) + .setQuery(queryBuilder); + + final String path = DataFrameField.STATS_FIELD.getPreferredName() + "."; + for(String statName : PROVIDED_STATS) { + requestBuilder.addAggregation(AggregationBuilders.sum(statName).field(path + statName)); + } + + ActionListener getStatisticSummationsListener = ActionListener.wrap( + searchResponse -> { + if (searchResponse.getShardFailures().length > 0) { + logger.error("statistics summations search returned shard failures: {}", + Arrays.toString(searchResponse.getShardFailures())); + } + + statsListener.onResponse(parseSearchAggs(searchResponse)); + }, + failure -> { + if (failure instanceof ResourceNotFoundException) { + statsListener.onResponse(DataFrameIndexerTransformStats.withDefaultTransformId()); + } else { + statsListener.onFailure(failure); + } + } + ); + ClientHelper.executeAsyncWithOrigin(client.threadPool().getThreadContext(), + ClientHelper.DATA_FRAME_ORIGIN, + requestBuilder.request(), + getStatisticSummationsListener, + client::search); + } +} diff --git a/x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrameUsageTransportAction.java b/x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrameUsageTransportAction.java new file mode 100644 index 0000000000000..36e1050b2ef03 --- /dev/null +++ b/x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrameUsageTransportAction.java @@ -0,0 +1,128 @@ +/* + * 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.xpack.dataframe; + +import org.elasticsearch.ResourceNotFoundException; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.client.Client; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.persistent.PersistentTasksCustomMetaData; +import org.elasticsearch.protocol.xpack.XPackUsageRequest; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.ClientHelper; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; +import org.elasticsearch.xpack.core.dataframe.DataFrameFeatureSetUsage; +import org.elasticsearch.xpack.core.dataframe.DataFrameField; +import org.elasticsearch.xpack.core.dataframe.transforms.DataFrameIndexerTransformStats; +import org.elasticsearch.xpack.core.dataframe.transforms.DataFrameTransform; +import org.elasticsearch.xpack.core.dataframe.transforms.DataFrameTransformConfig; +import org.elasticsearch.xpack.core.dataframe.transforms.DataFrameTransformState; +import org.elasticsearch.xpack.core.dataframe.transforms.DataFrameTransformTaskState; +import org.elasticsearch.xpack.dataframe.persistence.DataFrameInternalIndex; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class DataFrameUsageTransportAction extends XPackUsageFeatureTransportAction { + + private final boolean enabled; + private final XPackLicenseState licenseState; + private final Client client; + + @Inject + public DataFrameUsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, + ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, + Settings settings, XPackLicenseState licenseState, Client client) { + super(XPackUsageFeatureAction.DATA_FRAME.name(), transportService, clusterService, + threadPool, actionFilters, indexNameExpressionResolver); + this.enabled = XPackSettings.DATA_FRAME_ENABLED.get(settings); + this.licenseState = licenseState; + this.client = client; + } + + @Override + protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { + boolean available = licenseState.isDataFrameAllowed(); + if (enabled == false) { + var usage = new DataFrameFeatureSetUsage(available, enabled, Collections.emptyMap(), + DataFrameIndexerTransformStats.withDefaultTransformId()); + listener.onResponse(new XPackUsageFeatureResponse(usage)); + return; + } + + PersistentTasksCustomMetaData taskMetadata = PersistentTasksCustomMetaData.getPersistentTasksCustomMetaData(state); + Collection> dataFrameTasks = taskMetadata == null ? + Collections.emptyList() : + taskMetadata.findTasks(DataFrameTransform.NAME, (t) -> true); + final int taskCount = dataFrameTasks.size(); + final Map transformsCountByState = new HashMap<>(); + for(PersistentTasksCustomMetaData.PersistentTask dataFrameTask : dataFrameTasks) { + DataFrameTransformState transformState = (DataFrameTransformState)dataFrameTask.getState(); + transformsCountByState.merge(transformState.getTaskState().value(), 1L, Long::sum); + } + + ActionListener totalStatsListener = ActionListener.wrap( + statSummations -> { + var usage = new DataFrameFeatureSetUsage(available, enabled, transformsCountByState, statSummations); + listener.onResponse(new XPackUsageFeatureResponse(usage)); + }, + listener::onFailure + ); + + ActionListener totalTransformCountListener = ActionListener.wrap( + transformCountSuccess -> { + if (transformCountSuccess.getShardFailures().length > 0) { + logger.error("total transform count search returned shard failures: {}", + Arrays.toString(transformCountSuccess.getShardFailures())); + } + long totalTransforms = transformCountSuccess.getHits().getTotalHits().value; + if (totalTransforms == 0) { + var usage = new DataFrameFeatureSetUsage(available, enabled, transformsCountByState, + DataFrameIndexerTransformStats.withDefaultTransformId()); + listener.onResponse(new XPackUsageFeatureResponse(usage)); + return; + } + transformsCountByState.merge(DataFrameTransformTaskState.STOPPED.value(), totalTransforms - taskCount, Long::sum); + DataFrameInfoTransportAction.getStatisticSummations(client, totalStatsListener); + }, + transformCountFailure -> { + if (transformCountFailure instanceof ResourceNotFoundException) { + DataFrameInfoTransportAction.getStatisticSummations(client, totalStatsListener); + } else { + listener.onFailure(transformCountFailure); + } + } + ); + + SearchRequest totalTransformCount = client.prepareSearch(DataFrameInternalIndex.INDEX_NAME) + .setTrackTotalHits(true) + .setQuery(QueryBuilders.constantScoreQuery(QueryBuilders.boolQuery() + .filter(QueryBuilders.termQuery(DataFrameField.INDEX_DOC_TYPE.getPreferredName(), DataFrameTransformConfig.NAME)))) + .request(); + + ClientHelper.executeAsyncWithOrigin(client.threadPool().getThreadContext(), + ClientHelper.DATA_FRAME_ORIGIN, + totalTransformCount, + totalTransformCountListener, + client::search); + } +} diff --git a/x-pack/plugin/data-frame/src/test/java/org/elasticsearch/xpack/dataframe/DataFrameFeatureSetTests.java b/x-pack/plugin/data-frame/src/test/java/org/elasticsearch/xpack/dataframe/DataFrameInfoTransportActionTests.java similarity index 82% rename from x-pack/plugin/data-frame/src/test/java/org/elasticsearch/xpack/dataframe/DataFrameFeatureSetTests.java rename to x-pack/plugin/data-frame/src/test/java/org/elasticsearch/xpack/dataframe/DataFrameInfoTransportActionTests.java index c10d2793a067c..856c608b5dea3 100644 --- a/x-pack/plugin/data-frame/src/test/java/org/elasticsearch/xpack/dataframe/DataFrameFeatureSetTests.java +++ b/x-pack/plugin/data-frame/src/test/java/org/elasticsearch/xpack/dataframe/DataFrameInfoTransportActionTests.java @@ -35,13 +35,13 @@ import java.util.Map; import java.util.concurrent.ExecutionException; -import static org.elasticsearch.xpack.dataframe.DataFrameFeatureSet.PROVIDED_STATS; +import static org.elasticsearch.xpack.dataframe.DataFrameInfoTransportAction.PROVIDED_STATS; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.core.Is.is; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class DataFrameFeatureSetTests extends ESTestCase { +public class DataFrameInfoTransportActionTests extends ESTestCase { private XPackLicenseState licenseState; @Before @@ -50,7 +50,8 @@ public void init() { } public void testAvailable() { - DataFrameFeatureSet featureSet = new DataFrameFeatureSet(Settings.EMPTY, licenseState); + DataFrameInfoTransportAction featureSet = new DataFrameInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, licenseState); boolean available = randomBoolean(); when(licenseState.isDataFrameAllowed()).thenReturn(available); assertThat(featureSet.available(), is(available)); @@ -60,12 +61,14 @@ public void testEnabledSetting() { boolean enabled = randomBoolean(); Settings.Builder settings = Settings.builder(); settings.put("xpack.data_frame.enabled", enabled); - DataFrameFeatureSet featureSet = new DataFrameFeatureSet(settings.build(), licenseState); + DataFrameInfoTransportAction featureSet = new DataFrameInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), settings.build(), licenseState); assertThat(featureSet.enabled(), is(enabled)); } public void testEnabledDefault() { - DataFrameFeatureSet featureSet = new DataFrameFeatureSet(Settings.EMPTY, licenseState); + DataFrameInfoTransportAction featureSet = new DataFrameInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, licenseState); assertTrue(featureSet.enabled()); } @@ -74,7 +77,8 @@ public void testParseSearchAggs() { SearchResponse withEmptyAggs = mock(SearchResponse.class); when(withEmptyAggs.getAggregations()).thenReturn(emptyAggs); - assertThat(DataFrameFeatureSet.parseSearchAggs(withEmptyAggs), equalTo(DataFrameIndexerTransformStats.withDefaultTransformId())); + assertThat(DataFrameInfoTransportAction.parseSearchAggs(withEmptyAggs), + equalTo(DataFrameIndexerTransformStats.withDefaultTransformId())); DataFrameIndexerTransformStats expectedStats = new DataFrameIndexerTransformStats("_all", 1, // numPages @@ -97,7 +101,7 @@ public void testParseSearchAggs() { SearchResponse withAggs = mock(SearchResponse.class); when(withAggs.getAggregations()).thenReturn(aggregations); - assertThat(DataFrameFeatureSet.parseSearchAggs(withAggs), equalTo(expectedStats)); + assertThat(DataFrameInfoTransportAction.parseSearchAggs(withAggs), equalTo(expectedStats)); } private static Aggregation buildAgg(String name, double value) { @@ -111,7 +115,7 @@ public void testUsageDisabled() throws IOException, InterruptedException, Execut when(licenseState.isDataFrameAllowed()).thenReturn(true); Settings.Builder settings = Settings.builder(); settings.put("xpack.data_frame.enabled", false); - var usageAction = new DataFrameFeatureSet.UsageTransportAction(mock(TransportService.class), null, null, + var usageAction = new DataFrameUsageTransportAction(mock(TransportService.class), null, null, mock(ActionFilters.class), null, settings.build(), licenseState, mock(Client.class)); PlainActionFuture future = new PlainActionFuture<>(); usageAction.masterOperation(null, mock(ClusterState.class), future); diff --git a/x-pack/plugin/graph/src/main/java/org/elasticsearch/xpack/graph/Graph.java b/x-pack/plugin/graph/src/main/java/org/elasticsearch/xpack/graph/Graph.java index 0ecf1e0b0b232..7281a7bfde67b 100644 --- a/x-pack/plugin/graph/src/main/java/org/elasticsearch/xpack/graph/Graph.java +++ b/x-pack/plugin/graph/src/main/java/org/elasticsearch/xpack/graph/Graph.java @@ -9,7 +9,6 @@ import org.elasticsearch.action.ActionResponse; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.node.DiscoveryNodes; -import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.IndexScopedSettings; import org.elasticsearch.common.settings.Settings; @@ -18,16 +17,14 @@ import org.elasticsearch.plugins.Plugin; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestHandler; -import org.elasticsearch.xpack.core.XPackPlugin; import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; import org.elasticsearch.xpack.core.graph.action.GraphExploreAction; import org.elasticsearch.xpack.graph.action.TransportGraphExploreAction; import org.elasticsearch.xpack.graph.rest.action.RestGraphAction; import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.function.Supplier; @@ -36,29 +33,23 @@ public class Graph extends Plugin implements ActionPlugin { - public static final String NAME = "graph"; protected final boolean enabled; - public Graph(Settings settings) { this.enabled = XPackSettings.GRAPH_ENABLED.get(settings); } - public Collection createGuiceModules() { - return Collections.singletonList(b -> { - XPackPlugin.bindFeatureSet(b, GraphFeatureSet.class); - }); - } - @Override public List> getActions() { - var usageAction = new ActionHandler<>(XPackUsageFeatureAction.GRAPH, GraphFeatureSet.UsageTransportAction.class); + var usageAction = new ActionHandler<>(XPackUsageFeatureAction.GRAPH, GraphUsageTransportAction.class); + var infoAction = new ActionHandler<>(XPackInfoFeatureAction.GRAPH, GraphInfoTransportAction.class); if (false == enabled) { - return singletonList(usageAction); + return Arrays.asList(usageAction, infoAction); } return Arrays.asList( new ActionHandler<>(GraphExploreAction.INSTANCE, TransportGraphExploreAction.class), - usageAction); + usageAction, + infoAction); } @Override diff --git a/x-pack/plugin/graph/src/main/java/org/elasticsearch/xpack/graph/GraphFeatureSet.java b/x-pack/plugin/graph/src/main/java/org/elasticsearch/xpack/graph/GraphFeatureSet.java deleted file mode 100644 index 05ce1b32527eb..0000000000000 --- a/x-pack/plugin/graph/src/main/java/org/elasticsearch/xpack/graph/GraphFeatureSet.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.xpack.graph; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.action.support.ActionFilters; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; -import org.elasticsearch.cluster.service.ClusterService; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.license.XPackLicenseState; -import org.elasticsearch.protocol.xpack.XPackUsageRequest; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.TransportService; -import org.elasticsearch.xpack.core.XPackFeatureSet; -import org.elasticsearch.xpack.core.XPackField; -import org.elasticsearch.xpack.core.XPackSettings; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; -import org.elasticsearch.xpack.core.graph.GraphFeatureSetUsage; - -public class GraphFeatureSet implements XPackFeatureSet { - - private final boolean enabled; - private final XPackLicenseState licenseState; - - @Inject - public GraphFeatureSet(Settings settings, XPackLicenseState licenseState) { - this.enabled = XPackSettings.GRAPH_ENABLED.get(settings); - this.licenseState = licenseState; - } - - @Override - public String name() { - return XPackField.GRAPH; - } - - @Override - public boolean available() { - return licenseState != null && licenseState.isGraphAllowed(); - } - - @Override - public boolean enabled() { - return enabled; - } - - public static class UsageTransportAction extends XPackUsageFeatureTransportAction { - - private final Settings settings; - private final XPackLicenseState licenseState; - - @Inject - public UsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, - ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, - Settings settings, XPackLicenseState licenseState) { - super(XPackUsageFeatureAction.GRAPH.name(), transportService, clusterService, - threadPool, actionFilters, indexNameExpressionResolver); - this.settings = settings; - this.licenseState = licenseState; - } - - @Override - protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { - GraphFeatureSetUsage usage = - new GraphFeatureSetUsage(licenseState.isGraphAllowed(), XPackSettings.GRAPH_ENABLED.get(settings)); - listener.onResponse(new XPackUsageFeatureResponse(usage)); - } - } -} diff --git a/x-pack/plugin/graph/src/main/java/org/elasticsearch/xpack/graph/GraphInfoTransportAction.java b/x-pack/plugin/graph/src/main/java/org/elasticsearch/xpack/graph/GraphInfoTransportAction.java new file mode 100644 index 0000000000000..d8c181e5196d5 --- /dev/null +++ b/x-pack/plugin/graph/src/main/java/org/elasticsearch/xpack/graph/GraphInfoTransportAction.java @@ -0,0 +1,46 @@ +/* + * 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.xpack.graph; + +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackField; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureTransportAction; + +public class GraphInfoTransportAction extends XPackInfoFeatureTransportAction { + + private final boolean enabled; + private final XPackLicenseState licenseState; + + @Inject + public GraphInfoTransportAction(TransportService transportService, ActionFilters actionFilters, + Settings settings, XPackLicenseState licenseState) { + super(XPackInfoFeatureAction.GRAPH.name(), transportService, actionFilters); + this.enabled = XPackSettings.GRAPH_ENABLED.get(settings); + this.licenseState = licenseState; + } + + @Override + public String name() { + return XPackField.GRAPH; + } + + @Override + public boolean available() { + return licenseState != null && licenseState.isGraphAllowed(); + } + + @Override + public boolean enabled() { + return enabled; + } + +} diff --git a/x-pack/plugin/graph/src/main/java/org/elasticsearch/xpack/graph/GraphUsageTransportAction.java b/x-pack/plugin/graph/src/main/java/org/elasticsearch/xpack/graph/GraphUsageTransportAction.java new file mode 100644 index 0000000000000..f915d91524d46 --- /dev/null +++ b/x-pack/plugin/graph/src/main/java/org/elasticsearch/xpack/graph/GraphUsageTransportAction.java @@ -0,0 +1,46 @@ +/* + * 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.xpack.graph; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.protocol.xpack.XPackUsageRequest; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; +import org.elasticsearch.xpack.core.graph.GraphFeatureSetUsage; + +public class GraphUsageTransportAction extends XPackUsageFeatureTransportAction { + + private final Settings settings; + private final XPackLicenseState licenseState; + + @Inject + public GraphUsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, + ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, + Settings settings, XPackLicenseState licenseState) { + super(XPackUsageFeatureAction.GRAPH.name(), transportService, clusterService, + threadPool, actionFilters, indexNameExpressionResolver); + this.settings = settings; + this.licenseState = licenseState; + } + + @Override + protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { + GraphFeatureSetUsage usage = + new GraphFeatureSetUsage(licenseState.isGraphAllowed(), XPackSettings.GRAPH_ENABLED.get(settings)); + listener.onResponse(new XPackUsageFeatureResponse(usage)); + } +} diff --git a/x-pack/plugin/graph/src/test/java/org/elasticsearch/xpack/graph/GraphFeatureSetTests.java b/x-pack/plugin/graph/src/test/java/org/elasticsearch/xpack/graph/GraphInfoTransportActionTests.java similarity index 82% rename from x-pack/plugin/graph/src/test/java/org/elasticsearch/xpack/graph/GraphFeatureSetTests.java rename to x-pack/plugin/graph/src/test/java/org/elasticsearch/xpack/graph/GraphInfoTransportActionTests.java index 289196ff38ace..dcea451e92d36 100644 --- a/x-pack/plugin/graph/src/test/java/org/elasticsearch/xpack/graph/GraphFeatureSetTests.java +++ b/x-pack/plugin/graph/src/test/java/org/elasticsearch/xpack/graph/GraphInfoTransportActionTests.java @@ -21,7 +21,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class GraphFeatureSetTests extends ESTestCase { +public class GraphInfoTransportActionTests extends ESTestCase { private XPackLicenseState licenseState; @@ -31,12 +31,13 @@ public void init() throws Exception { } public void testAvailable() throws Exception { - GraphFeatureSet featureSet = new GraphFeatureSet(Settings.EMPTY, licenseState); + GraphInfoTransportAction featureSet = new GraphInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, licenseState); boolean available = randomBoolean(); when(licenseState.isGraphAllowed()).thenReturn(available); assertThat(featureSet.available(), is(available)); - var usageAction = new GraphFeatureSet.UsageTransportAction(mock(TransportService.class), null, null, + var usageAction = new GraphUsageTransportAction(mock(TransportService.class), null, null, mock(ActionFilters.class), null, Settings.EMPTY, licenseState); PlainActionFuture future = new PlainActionFuture<>(); usageAction.masterOperation(null, null, future); @@ -59,10 +60,11 @@ public void testEnabled() throws Exception { } else { settings.put("xpack.graph.enabled", enabled); } - GraphFeatureSet featureSet = new GraphFeatureSet(settings.build(), licenseState); + GraphInfoTransportAction featureSet = new GraphInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), settings.build(), licenseState); assertThat(featureSet.enabled(), is(enabled)); - GraphFeatureSet.UsageTransportAction usageAction = new GraphFeatureSet.UsageTransportAction(mock(TransportService.class), + GraphUsageTransportAction usageAction = new GraphUsageTransportAction(mock(TransportService.class), null, null, mock(ActionFilters.class), null, settings.build(), licenseState); PlainActionFuture future = new PlainActionFuture<>(); usageAction.masterOperation(null, null, future); diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycle.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycle.java index ed9f5fcb40920..2a03a1c834fac 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycle.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycle.java @@ -14,7 +14,6 @@ import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.ParseField; -import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.NamedWriteableRegistry.Entry; import org.elasticsearch.common.settings.ClusterSettings; @@ -32,8 +31,8 @@ import org.elasticsearch.script.ScriptService; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.watcher.ResourceWatcherService; -import org.elasticsearch.xpack.core.XPackPlugin; import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; import org.elasticsearch.xpack.core.indexlifecycle.AllocateAction; import org.elasticsearch.xpack.core.indexlifecycle.DeleteAction; @@ -43,9 +42,9 @@ import org.elasticsearch.xpack.core.indexlifecycle.LifecycleAction; import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings; import org.elasticsearch.xpack.core.indexlifecycle.LifecycleType; -import org.elasticsearch.xpack.core.indexlifecycle.SetPriorityAction; import org.elasticsearch.xpack.core.indexlifecycle.ReadOnlyAction; import org.elasticsearch.xpack.core.indexlifecycle.RolloverAction; +import org.elasticsearch.xpack.core.indexlifecycle.SetPriorityAction; import org.elasticsearch.xpack.core.indexlifecycle.ShrinkAction; import org.elasticsearch.xpack.core.indexlifecycle.TimeseriesLifecycleType; import org.elasticsearch.xpack.core.indexlifecycle.UnfollowAction; @@ -81,7 +80,6 @@ import org.elasticsearch.xpack.indexlifecycle.action.TransportStopILMAction; import java.time.Clock; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -89,7 +87,6 @@ import java.util.function.Supplier; import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; public class IndexLifecycle extends Plugin implements ActionPlugin { private final SetOnce indexLifecycleInitialisationService = new SetOnce<>(); @@ -106,12 +103,6 @@ protected Clock getClock() { return Clock.systemUTC(); } - public Collection createGuiceModules() { - List modules = new ArrayList<>(); - modules.add(b -> XPackPlugin.bindFeatureSet(b, IndexLifecycleFeatureSet.class)); - return modules; - } - @Override public List> getSettings() { return Arrays.asList( @@ -185,9 +176,11 @@ public List getRestHandlers(Settings settings, RestController restC @Override public List> getActions() { var usageAction = - new ActionHandler<>(XPackUsageFeatureAction.INDEX_LIFECYCLE, IndexLifecycleFeatureSet.UsageTransportAction.class); + new ActionHandler<>(XPackUsageFeatureAction.INDEX_LIFECYCLE, IndexLifecycleUsageTransportAction.class); + var infoAction = + new ActionHandler<>(XPackInfoFeatureAction.INDEX_LIFECYCLE, IndexLifecycleInfoTransportAction.class); if (enabled == false) { - return singletonList(usageAction); + return Arrays.asList(usageAction, infoAction); } return Arrays.asList( new ActionHandler<>(PutLifecycleAction.INSTANCE, TransportPutLifecycleAction.class), @@ -200,7 +193,8 @@ public List getRestHandlers(Settings settings, RestController restC new ActionHandler<>(StartILMAction.INSTANCE, TransportStartILMAction.class), new ActionHandler<>(StopILMAction.INSTANCE, TransportStopILMAction.class), new ActionHandler<>(GetStatusAction.INSTANCE, TransportGetStatusAction.class), - usageAction); + usageAction, + infoAction); } @Override diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleFeatureSet.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleFeatureSet.java deleted file mode 100644 index 8bceb8ad303e7..0000000000000 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleFeatureSet.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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.xpack.indexlifecycle; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.action.support.ActionFilters; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; -import org.elasticsearch.cluster.metadata.MetaData; -import org.elasticsearch.cluster.service.ClusterService; -import org.elasticsearch.common.collect.Tuple; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.license.XPackLicenseState; -import org.elasticsearch.protocol.xpack.XPackUsageRequest; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.TransportService; -import org.elasticsearch.xpack.core.XPackFeatureSet; -import org.elasticsearch.xpack.core.XPackField; -import org.elasticsearch.xpack.core.XPackSettings; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; -import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleFeatureSetUsage; -import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleFeatureSetUsage.PhaseStats; -import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleFeatureSetUsage.PolicyStats; -import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata; -import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -public class IndexLifecycleFeatureSet implements XPackFeatureSet { - - private final boolean enabled; - private final XPackLicenseState licenseState; - - @Inject - public IndexLifecycleFeatureSet(Settings settings, XPackLicenseState licenseState) { - this.enabled = XPackSettings.INDEX_LIFECYCLE_ENABLED.get(settings); - this.licenseState = licenseState; - } - - @Override - public String name() { - return XPackField.INDEX_LIFECYCLE; - } - - @Override - public boolean available() { - return licenseState != null && licenseState.isIndexLifecycleAllowed(); - } - - @Override - public boolean enabled() { - return enabled; - } - - public static class UsageTransportAction extends XPackUsageFeatureTransportAction { - private final boolean enabled; - private final XPackLicenseState licenseState; - - @Inject - public UsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, - ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, - Settings settings, XPackLicenseState licenseState) { - super(XPackUsageFeatureAction.INDEX_LIFECYCLE.name(), transportService, clusterService, threadPool, actionFilters, - indexNameExpressionResolver); - this.enabled = XPackSettings.INDEX_LIFECYCLE_ENABLED.get(settings); - this.licenseState = licenseState; - } - - @Override - protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { - boolean available = licenseState.isIndexLifecycleAllowed(); - MetaData metaData = state.metaData(); - IndexLifecycleMetadata lifecycleMetadata = metaData.custom(IndexLifecycleMetadata.TYPE); - final IndexLifecycleFeatureSetUsage usage; - if (enabled && lifecycleMetadata != null) { - Map policyUsage = new HashMap<>(); - metaData.indices().forEach(entry -> { - String policyName = LifecycleSettings.LIFECYCLE_NAME_SETTING.get(entry.value.getSettings()); - Integer indicesManaged = policyUsage.get(policyName); - if (indicesManaged == null) { - indicesManaged = 1; - } else { - indicesManaged = indicesManaged + 1; - } - policyUsage.put(policyName, indicesManaged); - }); - List policyStats = lifecycleMetadata.getPolicies().values().stream().map(policy -> { - Map phaseStats = policy.getPhases().values().stream().map(phase -> { - String[] actionNames = phase.getActions().keySet().toArray(new String[phase.getActions().size()]); - return new Tuple(phase.getName(), new PhaseStats(phase.getMinimumAge(), actionNames)); - }).collect(Collectors.toMap(Tuple::v1, Tuple::v2)); - return new PolicyStats(phaseStats, policyUsage.getOrDefault(policy.getName(), 0)); - }).collect(Collectors.toList()); - usage = new IndexLifecycleFeatureSetUsage(available, enabled, policyStats); - } else { - usage = new IndexLifecycleFeatureSetUsage(available, enabled); - } - listener.onResponse(new XPackUsageFeatureResponse(usage)); - } - } -} diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleInfoTransportAction.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleInfoTransportAction.java new file mode 100644 index 0000000000000..65fa28458e759 --- /dev/null +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleInfoTransportAction.java @@ -0,0 +1,46 @@ +/* + * 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.xpack.indexlifecycle; + +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackField; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureTransportAction; + +public class IndexLifecycleInfoTransportAction extends XPackInfoFeatureTransportAction { + + private final boolean enabled; + private final XPackLicenseState licenseState; + + @Inject + public IndexLifecycleInfoTransportAction(TransportService transportService, ActionFilters actionFilters, + Settings settings, XPackLicenseState licenseState) { + super(XPackInfoFeatureAction.INDEX_LIFECYCLE.name(), transportService, actionFilters); + this.enabled = XPackSettings.INDEX_LIFECYCLE_ENABLED.get(settings); + this.licenseState = licenseState; + } + + @Override + public String name() { + return XPackField.INDEX_LIFECYCLE; + } + + @Override + public boolean available() { + return licenseState.isIndexLifecycleAllowed(); + } + + @Override + public boolean enabled() { + return enabled; + } + +} diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleUsageTransportAction.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleUsageTransportAction.java new file mode 100644 index 0000000000000..0e8a9ae6f1d29 --- /dev/null +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleUsageTransportAction.java @@ -0,0 +1,79 @@ +/* + * 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.xpack.indexlifecycle; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.cluster.metadata.MetaData; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.collect.Tuple; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.protocol.xpack.XPackUsageRequest; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; +import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleFeatureSetUsage; +import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata; +import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class IndexLifecycleUsageTransportAction extends XPackUsageFeatureTransportAction { + private final boolean enabled; + private final XPackLicenseState licenseState; + + @Inject + public IndexLifecycleUsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, + ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, + Settings settings, XPackLicenseState licenseState) { + super(XPackUsageFeatureAction.INDEX_LIFECYCLE.name(), transportService, clusterService, threadPool, actionFilters, + indexNameExpressionResolver); + this.enabled = XPackSettings.INDEX_LIFECYCLE_ENABLED.get(settings); + this.licenseState = licenseState; + } + + @Override + protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { + boolean available = licenseState.isIndexLifecycleAllowed(); + MetaData metaData = state.metaData(); + IndexLifecycleMetadata lifecycleMetadata = metaData.custom(IndexLifecycleMetadata.TYPE); + final IndexLifecycleFeatureSetUsage usage; + if (enabled && lifecycleMetadata != null) { + Map policyUsage = new HashMap<>(); + metaData.indices().forEach(entry -> { + String policyName = LifecycleSettings.LIFECYCLE_NAME_SETTING.get(entry.value.getSettings()); + Integer indicesManaged = policyUsage.get(policyName); + if (indicesManaged == null) { + indicesManaged = 1; + } else { + indicesManaged = indicesManaged + 1; + } + policyUsage.put(policyName, indicesManaged); + }); + List policyStats = lifecycleMetadata.getPolicies().values().stream().map(policy -> { + Map phaseStats = policy.getPhases().values().stream().map(phase -> { + String[] actionNames = phase.getActions().keySet().toArray(new String[phase.getActions().size()]); + return new Tuple<>(phase.getName(), new IndexLifecycleFeatureSetUsage.PhaseStats(phase.getMinimumAge(), actionNames)); + }).collect(Collectors.toMap(Tuple::v1, Tuple::v2)); + return new IndexLifecycleFeatureSetUsage.PolicyStats(phaseStats, policyUsage.getOrDefault(policy.getName(), 0)); + }).collect(Collectors.toList()); + usage = new IndexLifecycleFeatureSetUsage(available, enabled, policyStats); + } else { + usage = new IndexLifecycleFeatureSetUsage(available, enabled); + } + listener.onResponse(new XPackUsageFeatureResponse(usage)); + } +} diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleFeatureSetTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleInfoTransportActionTests.java similarity index 85% rename from x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleFeatureSetTests.java rename to x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleInfoTransportActionTests.java index 0bccd7bbe4ab6..0e305fd6fffe1 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleFeatureSetTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleInfoTransportActionTests.java @@ -42,7 +42,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class IndexLifecycleFeatureSetTests extends ESTestCase { +public class IndexLifecycleInfoTransportActionTests extends ESTestCase { private XPackLicenseState licenseState; private ClusterService clusterService; @@ -54,7 +54,8 @@ public void init() throws Exception { } public void testAvailable() { - IndexLifecycleFeatureSet featureSet = new IndexLifecycleFeatureSet(Settings.EMPTY, licenseState); + IndexLifecycleInfoTransportAction featureSet = new IndexLifecycleInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, licenseState); when(licenseState.isIndexLifecycleAllowed()).thenReturn(false); assertThat(featureSet.available(), equalTo(false)); @@ -62,22 +63,26 @@ public void testAvailable() { when(licenseState.isIndexLifecycleAllowed()).thenReturn(true); assertThat(featureSet.available(), equalTo(true)); - featureSet = new IndexLifecycleFeatureSet(Settings.EMPTY, null); + featureSet = new IndexLifecycleInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, null); assertThat(featureSet.available(), equalTo(false)); } public void testEnabled() { Settings.Builder settings = Settings.builder().put("xpack.ilm.enabled", false); - IndexLifecycleFeatureSet featureSet = new IndexLifecycleFeatureSet(settings.build(), licenseState); + IndexLifecycleInfoTransportAction featureSet = new IndexLifecycleInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), settings.build(), licenseState); assertThat(featureSet.enabled(), equalTo(false)); settings = Settings.builder().put("xpack.ilm.enabled", true); - featureSet = new IndexLifecycleFeatureSet(settings.build(), licenseState); + featureSet = new IndexLifecycleInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), settings.build(), licenseState); assertThat(featureSet.enabled(), equalTo(true)); } public void testName() { - IndexLifecycleFeatureSet featureSet = new IndexLifecycleFeatureSet(Settings.EMPTY, licenseState); + IndexLifecycleInfoTransportAction featureSet = new IndexLifecycleInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, licenseState); assertThat(featureSet.name(), equalTo("ilm")); } @@ -108,7 +113,7 @@ public void testUsageStats() throws Exception { ClusterState clusterState = buildClusterState(policies, indexPolicies); Mockito.when(clusterService.state()).thenReturn(clusterState); - var usageAction = new IndexLifecycleFeatureSet.UsageTransportAction(mock(TransportService.class), null, null, + var usageAction = new IndexLifecycleUsageTransportAction(mock(TransportService.class), null, null, mock(ActionFilters.class), null, Settings.EMPTY, licenseState); PlainActionFuture future = new PlainActionFuture<>(); usageAction.masterOperation(null, clusterState, future); diff --git a/x-pack/plugin/logstash/src/main/java/org/elasticsearch/xpack/logstash/Logstash.java b/x-pack/plugin/logstash/src/main/java/org/elasticsearch/xpack/logstash/Logstash.java index 3ec1367bf9ab9..7ea6e6d2e4daa 100644 --- a/x-pack/plugin/logstash/src/main/java/org/elasticsearch/xpack/logstash/Logstash.java +++ b/x-pack/plugin/logstash/src/main/java/org/elasticsearch/xpack/logstash/Logstash.java @@ -10,19 +10,16 @@ import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionResponse; import org.elasticsearch.cluster.metadata.IndexTemplateMetaData; -import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.plugins.Plugin; -import org.elasticsearch.xpack.core.XPackPlugin; import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; import org.elasticsearch.xpack.core.template.TemplateUtils; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.function.UnaryOperator; @@ -45,22 +42,11 @@ public Logstash(Settings settings) { this.enabled = XPackSettings.LOGSTASH_ENABLED.get(settings); } - boolean isEnabled() { - return enabled; - } - - public Collection createGuiceModules() { - List modules = new ArrayList<>(); - modules.add(b -> { - XPackPlugin.bindFeatureSet(b, LogstashFeatureSet.class); - }); - return modules; - } - @Override public List> getActions() { - return Collections.singletonList( - new ActionHandler<>(XPackUsageFeatureAction.LOGSTASH, LogstashFeatureSet.UsageTransportAction.class)); + return Arrays.asList( + new ActionHandler<>(XPackUsageFeatureAction.LOGSTASH, LogstashUsageTransportAction.class), + new ActionHandler<>(XPackInfoFeatureAction.LOGSTASH, LogstashInfoTransportAction.class)); } public UnaryOperator> getIndexTemplateMetaDataUpgrader() { diff --git a/x-pack/plugin/logstash/src/main/java/org/elasticsearch/xpack/logstash/LogstashFeatureSet.java b/x-pack/plugin/logstash/src/main/java/org/elasticsearch/xpack/logstash/LogstashFeatureSet.java deleted file mode 100644 index 0d667afcde370..0000000000000 --- a/x-pack/plugin/logstash/src/main/java/org/elasticsearch/xpack/logstash/LogstashFeatureSet.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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.xpack.logstash; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.action.support.ActionFilters; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; -import org.elasticsearch.cluster.service.ClusterService; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.license.XPackLicenseState; -import org.elasticsearch.protocol.xpack.XPackUsageRequest; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.TransportService; -import org.elasticsearch.xpack.core.XPackFeatureSet; -import org.elasticsearch.xpack.core.XPackField; -import org.elasticsearch.xpack.core.XPackSettings; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; -import org.elasticsearch.xpack.core.logstash.LogstashFeatureSetUsage; - -public class LogstashFeatureSet implements XPackFeatureSet { - - private final boolean enabled; - private final XPackLicenseState licenseState; - - @Inject - public LogstashFeatureSet(Settings settings, XPackLicenseState licenseState) { - this.enabled = XPackSettings.LOGSTASH_ENABLED.get(settings); - this.licenseState = licenseState; - } - - @Override - public String name() { - return XPackField.LOGSTASH; - } - - @Override - public boolean available() { - return licenseState != null && licenseState.isLogstashAllowed(); - } - - @Override - public boolean enabled() { - return enabled; - } - - public static class UsageTransportAction extends XPackUsageFeatureTransportAction { - - private final Settings settings; - private final XPackLicenseState licenseState; - - @Inject - public UsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, - ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, - Settings settings, XPackLicenseState licenseState) { - super(XPackUsageFeatureAction.LOGSTASH.name(), transportService, clusterService, - threadPool, actionFilters, indexNameExpressionResolver); - this.settings = settings; - this.licenseState = licenseState; - } - - @Override - protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { - boolean available = licenseState.isLogstashAllowed(); - LogstashFeatureSetUsage usage = - new LogstashFeatureSetUsage(available, XPackSettings.LOGSTASH_ENABLED.get(settings)); - listener.onResponse(new XPackUsageFeatureResponse(usage)); - } - } -} diff --git a/x-pack/plugin/logstash/src/main/java/org/elasticsearch/xpack/logstash/LogstashInfoTransportAction.java b/x-pack/plugin/logstash/src/main/java/org/elasticsearch/xpack/logstash/LogstashInfoTransportAction.java new file mode 100644 index 0000000000000..49a48daf5ea9c --- /dev/null +++ b/x-pack/plugin/logstash/src/main/java/org/elasticsearch/xpack/logstash/LogstashInfoTransportAction.java @@ -0,0 +1,46 @@ +/* + * 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.xpack.logstash; + +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackField; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureTransportAction; + +public class LogstashInfoTransportAction extends XPackInfoFeatureTransportAction { + + private final boolean enabled; + private final XPackLicenseState licenseState; + + @Inject + public LogstashInfoTransportAction(TransportService transportService, ActionFilters actionFilters, + Settings settings, XPackLicenseState licenseState) { + super(XPackInfoFeatureAction.LOGSTASH.name(), transportService, actionFilters); + this.enabled = XPackSettings.LOGSTASH_ENABLED.get(settings); + this.licenseState = licenseState; + } + + @Override + public String name() { + return XPackField.LOGSTASH; + } + + @Override + public boolean available() { + return licenseState.isLogstashAllowed(); + } + + @Override + public boolean enabled() { + return enabled; + } + +} diff --git a/x-pack/plugin/logstash/src/main/java/org/elasticsearch/xpack/logstash/LogstashUsageTransportAction.java b/x-pack/plugin/logstash/src/main/java/org/elasticsearch/xpack/logstash/LogstashUsageTransportAction.java new file mode 100644 index 0000000000000..70284bcf2dc2d --- /dev/null +++ b/x-pack/plugin/logstash/src/main/java/org/elasticsearch/xpack/logstash/LogstashUsageTransportAction.java @@ -0,0 +1,47 @@ +/* + * 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.xpack.logstash; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.protocol.xpack.XPackUsageRequest; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; +import org.elasticsearch.xpack.core.logstash.LogstashFeatureSetUsage; + +public class LogstashUsageTransportAction extends XPackUsageFeatureTransportAction { + + private final Settings settings; + private final XPackLicenseState licenseState; + + @Inject + public LogstashUsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, + ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, + Settings settings, XPackLicenseState licenseState) { + super(XPackUsageFeatureAction.LOGSTASH.name(), transportService, clusterService, + threadPool, actionFilters, indexNameExpressionResolver); + this.settings = settings; + this.licenseState = licenseState; + } + + @Override + protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { + boolean available = licenseState.isLogstashAllowed(); + LogstashFeatureSetUsage usage = + new LogstashFeatureSetUsage(available, XPackSettings.LOGSTASH_ENABLED.get(settings)); + listener.onResponse(new XPackUsageFeatureResponse(usage)); + } +} diff --git a/x-pack/plugin/logstash/src/test/java/org/elasticsearch/xpack/logstash/LogstashFeatureSetTests.java b/x-pack/plugin/logstash/src/test/java/org/elasticsearch/xpack/logstash/LogstashInfoTransportActionTests.java similarity index 78% rename from x-pack/plugin/logstash/src/test/java/org/elasticsearch/xpack/logstash/LogstashFeatureSetTests.java rename to x-pack/plugin/logstash/src/test/java/org/elasticsearch/xpack/logstash/LogstashInfoTransportActionTests.java index 860cdbe3aa655..ac6a4850e744b 100644 --- a/x-pack/plugin/logstash/src/test/java/org/elasticsearch/xpack/logstash/LogstashFeatureSetTests.java +++ b/x-pack/plugin/logstash/src/test/java/org/elasticsearch/xpack/logstash/LogstashInfoTransportActionTests.java @@ -20,7 +20,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class LogstashFeatureSetTests extends ESTestCase { +public class LogstashInfoTransportActionTests extends ESTestCase { public void testEnabledSetting() throws Exception { boolean enabled = randomBoolean(); @@ -28,10 +28,11 @@ public void testEnabledSetting() throws Exception { .put("path.home", createTempDir()) .put("xpack.logstash.enabled", enabled) .build(); - LogstashFeatureSet featureSet = new LogstashFeatureSet(settings, null); + LogstashInfoTransportAction featureSet = new LogstashInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), settings, null); assertThat(featureSet.enabled(), is(enabled)); - LogstashFeatureSet.UsageTransportAction usageAction = newUsageAction(settings, false); + LogstashUsageTransportAction usageAction = newUsageAction(settings, false); PlainActionFuture future = new PlainActionFuture<>(); usageAction.masterOperation(null, null, future); XPackFeatureSet.Usage usage = future.get().getUsage(); @@ -44,13 +45,15 @@ public void testEnabledSetting() throws Exception { public void testEnabledDefault() throws Exception { Settings settings = Settings.builder().put("path.home", createTempDir()).build(); - LogstashFeatureSet featureSet = new LogstashFeatureSet(settings, null); + LogstashInfoTransportAction featureSet = new LogstashInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), settings, null); assertThat(featureSet.enabled(), is(true)); } public void testAvailable() throws Exception { final XPackLicenseState licenseState = mock(XPackLicenseState.class); - LogstashFeatureSet featureSet = new LogstashFeatureSet(Settings.EMPTY, licenseState); + LogstashInfoTransportAction featureSet = new LogstashInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, licenseState); boolean available = randomBoolean(); when(licenseState.isLogstashAllowed()).thenReturn(available); assertThat(featureSet.available(), is(available)); @@ -67,10 +70,10 @@ public void testAvailable() throws Exception { assertThat(serializedUsage.available(), is(available)); } - private LogstashFeatureSet.UsageTransportAction newUsageAction(Settings settings, boolean available) { + private LogstashUsageTransportAction newUsageAction(Settings settings, boolean available) { XPackLicenseState licenseState = mock(XPackLicenseState.class); when(licenseState.isLogstashAllowed()).thenReturn(available); - return new LogstashFeatureSet.UsageTransportAction(mock(TransportService.class), null, + return new LogstashUsageTransportAction(mock(TransportService.class), null, null, mock(ActionFilters.class), null, settings, licenseState); } } diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MachineLearning.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MachineLearning.java index a675f4a2e1a12..989d4e9c934aa 100644 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MachineLearning.java +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MachineLearning.java @@ -22,7 +22,6 @@ import org.elasticsearch.cluster.routing.UnassignedInfo; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.Strings; -import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.IndexScopedSettings; @@ -58,6 +57,7 @@ import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.xpack.core.XPackPlugin; import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; import org.elasticsearch.xpack.core.ml.MachineLearningField; import org.elasticsearch.xpack.core.ml.MlMetaIndex; @@ -243,7 +243,6 @@ import java.math.BigInteger; import java.nio.file.Path; import java.time.Clock; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -253,7 +252,6 @@ import java.util.function.UnaryOperator; import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME; public class MachineLearning extends Plugin implements ActionPlugin, AnalysisPlugin, PersistentTaskPlugin { @@ -435,7 +433,7 @@ public Collection createComponents(Client client, ClusterService cluster AutodetectProcessFactory autodetectProcessFactory; NormalizerProcessFactory normalizerProcessFactory; - if (MachineLearningField.AUTODETECT_PROCESS.get(settings) && MachineLearningFeatureSet.isRunningOnMlPlatform(true)) { + if (MachineLearningField.AUTODETECT_PROCESS.get(settings) && MachineLearningInfoTransportAction.isRunningOnMlPlatform(true)) { try { NativeController nativeController = NativeControllerHolder.getNativeController(clusterService.getNodeName(), environment); if (nativeController == null) { @@ -450,7 +448,7 @@ public Collection createComponents(Client client, ClusterService cluster clusterService); normalizerProcessFactory = new NativeNormalizerProcessFactory(environment, nativeController); } catch (IOException e) { - // This also should not happen in production, as the MachineLearningFeatureSet should have + // This also should not happen in production, as the MachineLearningInfoTransportAction should have // hit the same error first and brought down the node with a friendlier error message throw new ElasticsearchException("Failed to create native process factories for Machine Learning", e); } @@ -517,14 +515,6 @@ public List> getPersistentTasksExecutor(ClusterServic ); } - public Collection createGuiceModules() { - List modules = new ArrayList<>(); - modules.add(b -> { - XPackPlugin.bindFeatureSet(b, MachineLearningFeatureSet.class); - }); - return modules; - } - @Override public List getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings, IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter, @@ -586,9 +576,11 @@ public List getRestHandlers(Settings settings, RestController restC @Override public List> getActions() { var usageAction = - new ActionHandler<>(XPackUsageFeatureAction.MACHINE_LEARNING, MachineLearningFeatureSet.UsageTransportAction.class); + new ActionHandler<>(XPackUsageFeatureAction.MACHINE_LEARNING, MachineLearningUsageTransportAction.class); + var infoAction = + new ActionHandler<>(XPackInfoFeatureAction.MACHINE_LEARNING, MachineLearningInfoTransportAction.class); if (false == enabled) { - return singletonList(usageAction); + return Arrays.asList(usageAction, infoAction); } return Arrays.asList( new ActionHandler<>(GetJobsAction.INSTANCE, TransportGetJobsAction.class), @@ -641,7 +633,8 @@ public List getRestHandlers(Settings settings, RestController restC new ActionHandler<>(PersistJobAction.INSTANCE, TransportPersistJobAction.class), new ActionHandler<>(FindFileStructureAction.INSTANCE, TransportFindFileStructureAction.class), new ActionHandler<>(SetUpgradeModeAction.INSTANCE, TransportSetUpgradeModeAction.class), - usageAction); + usageAction, + infoAction); } @Override diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MachineLearningFeatureSet.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MachineLearningFeatureSet.java deleted file mode 100644 index 4368b53121216..0000000000000 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MachineLearningFeatureSet.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * 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.xpack.ml; - -import org.apache.lucene.util.Constants; -import org.apache.lucene.util.Counter; -import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.action.support.ActionFilters; -import org.elasticsearch.client.Client; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; -import org.elasticsearch.cluster.metadata.MetaData; -import org.elasticsearch.cluster.node.DiscoveryNode; -import org.elasticsearch.cluster.service.ClusterService; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.env.Environment; -import org.elasticsearch.license.XPackLicenseState; -import org.elasticsearch.plugins.Platforms; -import org.elasticsearch.protocol.xpack.XPackUsageRequest; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.TransportService; -import org.elasticsearch.xpack.core.XPackFeatureSet; -import org.elasticsearch.xpack.core.XPackField; -import org.elasticsearch.xpack.core.XPackSettings; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; -import org.elasticsearch.xpack.core.ml.MachineLearningFeatureSetUsage; -import org.elasticsearch.xpack.core.ml.action.GetDatafeedsStatsAction; -import org.elasticsearch.xpack.core.ml.action.GetJobsStatsAction; -import org.elasticsearch.xpack.core.ml.datafeed.DatafeedState; -import org.elasticsearch.xpack.core.ml.job.config.Job; -import org.elasticsearch.xpack.core.ml.job.config.JobState; -import org.elasticsearch.xpack.core.ml.job.process.autodetect.state.ModelSizeStats; -import org.elasticsearch.xpack.core.ml.stats.ForecastStats; -import org.elasticsearch.xpack.core.ml.stats.StatsAccumulator; -import org.elasticsearch.xpack.ml.job.JobManagerHolder; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.stream.Collectors; - -public class MachineLearningFeatureSet implements XPackFeatureSet { - - /** - * List of platforms for which the native processes are available - */ - private static final List mlPlatforms = - Arrays.asList("darwin-x86_64", "linux-x86_64", "windows-x86_64"); - - private final boolean enabled; - private final XPackLicenseState licenseState; - - @Inject - public MachineLearningFeatureSet(Settings settings, XPackLicenseState licenseState) { - this.enabled = XPackSettings.MACHINE_LEARNING_ENABLED.get(settings); - this.licenseState = licenseState; - } - - // TODO: remove these methods - static boolean isRunningOnMlPlatform(boolean fatalIfNot) { - return isRunningOnMlPlatform(Constants.OS_NAME, Constants.OS_ARCH, fatalIfNot); - } - - static boolean isRunningOnMlPlatform(String osName, String osArch, boolean fatalIfNot) { - String platformName = Platforms.platformName(osName, osArch); - if (mlPlatforms.contains(platformName)) { - return true; - } - if (fatalIfNot) { - throw new ElasticsearchException("X-Pack is not supported and Machine Learning is not available for [" + platformName - + "]; you can use the other X-Pack features (unsupported) by setting xpack.ml.enabled: false in elasticsearch.yml"); - } - return false; - } - - @Override - public String name() { - return XPackField.MACHINE_LEARNING; - } - - @Override - public boolean available() { - return licenseState != null && licenseState.isMachineLearningAllowed(); - } - - @Override - public boolean enabled() { - return enabled; - } - - public static class UsageTransportAction extends XPackUsageFeatureTransportAction { - - private final Client client; - private final XPackLicenseState licenseState; - private final JobManagerHolder jobManagerHolder; - private final boolean enabled; - - @Inject - public UsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, - ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, - Environment environment, Client client, - XPackLicenseState licenseState, JobManagerHolder jobManagerHolder) { - super(XPackUsageFeatureAction.MACHINE_LEARNING.name(), transportService, clusterService, - threadPool, actionFilters, indexNameExpressionResolver); - this.client = client; - this.licenseState = licenseState; - this.jobManagerHolder = jobManagerHolder; - this.enabled = XPackSettings.MACHINE_LEARNING_ENABLED.get(environment.settings()); - } - - @Override - protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { - if (enabled == false) { - MachineLearningFeatureSetUsage usage = new MachineLearningFeatureSetUsage(licenseState.isMachineLearningAllowed(), enabled, - Collections.emptyMap(), Collections.emptyMap(), 0); - listener.onResponse(new XPackUsageFeatureResponse(usage)); - return; - } - - Map jobsUsage = new LinkedHashMap<>(); - Map datafeedsUsage = new LinkedHashMap<>(); - int nodeCount = mlNodeCount(state); - - // Step 2. Extract usage from datafeeds stats and return usage response - ActionListener datafeedStatsListener = - ActionListener.wrap(response -> { - addDatafeedsUsage(response, datafeedsUsage); - MachineLearningFeatureSetUsage usage = new MachineLearningFeatureSetUsage(licenseState.isMachineLearningAllowed(), - enabled, jobsUsage, datafeedsUsage, nodeCount); - listener.onResponse(new XPackUsageFeatureResponse(usage)); - }, - listener::onFailure); - - // Step 1. Extract usage from jobs stats and then request stats for all datafeeds - GetJobsStatsAction.Request jobStatsRequest = new GetJobsStatsAction.Request(MetaData.ALL); - ActionListener jobStatsListener = ActionListener.wrap( - response -> { - jobManagerHolder.getJobManager().expandJobs(MetaData.ALL, true, ActionListener.wrap(jobs -> { - addJobsUsage(response, jobs.results(), jobsUsage); - GetDatafeedsStatsAction.Request datafeedStatsRequest = new GetDatafeedsStatsAction.Request( - GetDatafeedsStatsAction.ALL); - client.execute(GetDatafeedsStatsAction.INSTANCE, datafeedStatsRequest, datafeedStatsListener); - }, listener::onFailure)); - }, listener::onFailure); - - // Step 0. Kick off the chain of callbacks by requesting jobs stats - client.execute(GetJobsStatsAction.INSTANCE, jobStatsRequest, jobStatsListener); - } - - private void addJobsUsage(GetJobsStatsAction.Response response, List jobs, Map jobsUsage) { - StatsAccumulator allJobsDetectorsStats = new StatsAccumulator(); - StatsAccumulator allJobsModelSizeStats = new StatsAccumulator(); - ForecastStats allJobsForecastStats = new ForecastStats(); - - Map jobCountByState = new HashMap<>(); - Map detectorStatsByState = new HashMap<>(); - Map modelSizeStatsByState = new HashMap<>(); - Map forecastStatsByState = new HashMap<>(); - Map> createdByByState = new HashMap<>(); - - List jobsStats = response.getResponse().results(); - Map jobMap = jobs.stream().collect(Collectors.toMap(Job::getId, item -> item)); - Map allJobsCreatedBy = jobs.stream().map(this::jobCreatedBy) - .collect(Collectors.groupingBy(item -> item, Collectors.counting()));; - for (GetJobsStatsAction.Response.JobStats jobStats : jobsStats) { - ModelSizeStats modelSizeStats = jobStats.getModelSizeStats(); - Job job = jobMap.get(jobStats.getJobId()); - int detectorsCount = job.getAnalysisConfig().getDetectors().size(); - double modelSize = modelSizeStats == null ? 0.0 - : jobStats.getModelSizeStats().getModelBytes(); - - allJobsForecastStats.merge(jobStats.getForecastStats()); - allJobsDetectorsStats.add(detectorsCount); - allJobsModelSizeStats.add(modelSize); - - JobState jobState = jobStats.getState(); - jobCountByState.computeIfAbsent(jobState, js -> Counter.newCounter()).addAndGet(1); - detectorStatsByState.computeIfAbsent(jobState, - js -> new StatsAccumulator()).add(detectorsCount); - modelSizeStatsByState.computeIfAbsent(jobState, - js -> new StatsAccumulator()).add(modelSize); - forecastStatsByState.merge(jobState, jobStats.getForecastStats(), (f1, f2) -> f1.merge(f2)); - createdByByState.computeIfAbsent(jobState, js -> new HashMap<>()) - .compute(jobCreatedBy(job), (k, v) -> (v == null) ? 1L : (v + 1)); - } - - jobsUsage.put(MachineLearningFeatureSetUsage.ALL, createJobUsageEntry(jobs.size(), allJobsDetectorsStats, - allJobsModelSizeStats, allJobsForecastStats, allJobsCreatedBy)); - for (JobState jobState : jobCountByState.keySet()) { - jobsUsage.put(jobState.name().toLowerCase(Locale.ROOT), createJobUsageEntry( - jobCountByState.get(jobState).get(), - detectorStatsByState.get(jobState), - modelSizeStatsByState.get(jobState), - forecastStatsByState.get(jobState), - createdByByState.get(jobState))); - } - } - - private String jobCreatedBy(Job job) { - Map customSettings = job.getCustomSettings(); - if (customSettings == null || customSettings.containsKey(MachineLearningFeatureSetUsage.CREATED_BY) == false) { - return "unknown"; - } - // Replace non-alpha-numeric characters with underscores because - // the values from custom settings become keys in the usage data - return customSettings.get(MachineLearningFeatureSetUsage.CREATED_BY).toString().replaceAll("\\W", "_"); - } - - private Map createJobUsageEntry(long count, StatsAccumulator detectorStats, - StatsAccumulator modelSizeStats, - ForecastStats forecastStats, Map createdBy) { - Map usage = new HashMap<>(); - usage.put(MachineLearningFeatureSetUsage.COUNT, count); - usage.put(MachineLearningFeatureSetUsage.DETECTORS, detectorStats.asMap()); - usage.put(MachineLearningFeatureSetUsage.MODEL_SIZE, modelSizeStats.asMap()); - usage.put(MachineLearningFeatureSetUsage.FORECASTS, forecastStats.asMap()); - usage.put(MachineLearningFeatureSetUsage.CREATED_BY, createdBy); - return usage; - } - - private void addDatafeedsUsage(GetDatafeedsStatsAction.Response response, Map datafeedsUsage) { - Map datafeedCountByState = new HashMap<>(); - - List datafeedsStats = response.getResponse().results(); - for (GetDatafeedsStatsAction.Response.DatafeedStats datafeedStats : datafeedsStats) { - datafeedCountByState.computeIfAbsent(datafeedStats.getDatafeedState(), - ds -> Counter.newCounter()).addAndGet(1); - } - - datafeedsUsage.put(MachineLearningFeatureSetUsage.ALL, createDatafeedUsageEntry(response.getResponse().count())); - for (DatafeedState datafeedState : datafeedCountByState.keySet()) { - datafeedsUsage.put(datafeedState.name().toLowerCase(Locale.ROOT), - createDatafeedUsageEntry(datafeedCountByState.get(datafeedState).get())); - } - } - - private Map createDatafeedUsageEntry(long count) { - Map usage = new HashMap<>(); - usage.put(MachineLearningFeatureSetUsage.COUNT, count); - return usage; - } - - private static int mlNodeCount(final ClusterState clusterState) { - int mlNodeCount = 0; - for (DiscoveryNode node : clusterState.getNodes()) { - if (MachineLearning.isMlNode(node)) { - ++mlNodeCount; - } - } - return mlNodeCount; - } - } -} diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MachineLearningInfoTransportAction.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MachineLearningInfoTransportAction.java new file mode 100644 index 0000000000000..fa8d8a1b853c6 --- /dev/null +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MachineLearningInfoTransportAction.java @@ -0,0 +1,75 @@ +/* + * 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.xpack.ml; + +import org.apache.lucene.util.Constants; +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.plugins.Platforms; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackField; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureTransportAction; + +import java.util.Arrays; +import java.util.List; + +public class MachineLearningInfoTransportAction extends XPackInfoFeatureTransportAction { + + /** + * List of platforms for which the native processes are available + */ + private static final List mlPlatforms = + Arrays.asList("darwin-x86_64", "linux-x86_64", "windows-x86_64"); + + private final boolean enabled; + private final XPackLicenseState licenseState; + + @Inject + public MachineLearningInfoTransportAction(TransportService transportService, ActionFilters actionFilters, + Settings settings, XPackLicenseState licenseState) { + super(XPackInfoFeatureAction.MACHINE_LEARNING.name(), transportService, actionFilters); + this.enabled = XPackSettings.MACHINE_LEARNING_ENABLED.get(settings); + this.licenseState = licenseState; + } + + // TODO: remove these methods + static boolean isRunningOnMlPlatform(boolean fatalIfNot) { + return isRunningOnMlPlatform(Constants.OS_NAME, Constants.OS_ARCH, fatalIfNot); + } + + static boolean isRunningOnMlPlatform(String osName, String osArch, boolean fatalIfNot) { + String platformName = Platforms.platformName(osName, osArch); + if (mlPlatforms.contains(platformName)) { + return true; + } + if (fatalIfNot) { + throw new ElasticsearchException("X-Pack is not supported and Machine Learning is not available for [" + platformName + + "]; you can use the other X-Pack features (unsupported) by setting xpack.ml.enabled: false in elasticsearch.yml"); + } + return false; + } + + @Override + public String name() { + return XPackField.MACHINE_LEARNING; + } + + @Override + public boolean available() { + return licenseState.isMachineLearningAllowed(); + } + + @Override + public boolean enabled() { + return enabled; + } + +} diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MachineLearningUsageTransportAction.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MachineLearningUsageTransportAction.java new file mode 100644 index 0000000000000..6b18e89413762 --- /dev/null +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MachineLearningUsageTransportAction.java @@ -0,0 +1,207 @@ +/* + * 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.xpack.ml; + +import org.apache.lucene.util.Counter; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.client.Client; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.cluster.metadata.MetaData; +import org.elasticsearch.cluster.node.DiscoveryNode; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.env.Environment; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.protocol.xpack.XPackUsageRequest; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; +import org.elasticsearch.xpack.core.ml.MachineLearningFeatureSetUsage; +import org.elasticsearch.xpack.core.ml.action.GetDatafeedsStatsAction; +import org.elasticsearch.xpack.core.ml.action.GetJobsStatsAction; +import org.elasticsearch.xpack.core.ml.datafeed.DatafeedState; +import org.elasticsearch.xpack.core.ml.job.config.Job; +import org.elasticsearch.xpack.core.ml.job.config.JobState; +import org.elasticsearch.xpack.core.ml.job.process.autodetect.state.ModelSizeStats; +import org.elasticsearch.xpack.core.ml.stats.ForecastStats; +import org.elasticsearch.xpack.core.ml.stats.StatsAccumulator; +import org.elasticsearch.xpack.ml.job.JobManagerHolder; + +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.stream.Collectors; + +public class MachineLearningUsageTransportAction extends XPackUsageFeatureTransportAction { + + private final Client client; + private final XPackLicenseState licenseState; + private final JobManagerHolder jobManagerHolder; + private final boolean enabled; + + @Inject + public MachineLearningUsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, + ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, + Environment environment, Client client, + XPackLicenseState licenseState, JobManagerHolder jobManagerHolder) { + super(XPackUsageFeatureAction.MACHINE_LEARNING.name(), transportService, clusterService, + threadPool, actionFilters, indexNameExpressionResolver); + this.client = client; + this.licenseState = licenseState; + this.jobManagerHolder = jobManagerHolder; + this.enabled = XPackSettings.MACHINE_LEARNING_ENABLED.get(environment.settings()); + } + + @Override + protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { + if (enabled == false) { + MachineLearningFeatureSetUsage usage = new MachineLearningFeatureSetUsage(licenseState.isMachineLearningAllowed(), enabled, + Collections.emptyMap(), Collections.emptyMap(), 0); + listener.onResponse(new XPackUsageFeatureResponse(usage)); + return; + } + + Map jobsUsage = new LinkedHashMap<>(); + Map datafeedsUsage = new LinkedHashMap<>(); + int nodeCount = mlNodeCount(state); + + // Step 2. Extract usage from datafeeds stats and return usage response + ActionListener datafeedStatsListener = + ActionListener.wrap(response -> { + addDatafeedsUsage(response, datafeedsUsage); + MachineLearningFeatureSetUsage usage = new MachineLearningFeatureSetUsage(licenseState.isMachineLearningAllowed(), + enabled, jobsUsage, datafeedsUsage, nodeCount); + listener.onResponse(new XPackUsageFeatureResponse(usage)); + }, + listener::onFailure); + + // Step 1. Extract usage from jobs stats and then request stats for all datafeeds + GetJobsStatsAction.Request jobStatsRequest = new GetJobsStatsAction.Request(MetaData.ALL); + ActionListener jobStatsListener = ActionListener.wrap( + response -> { + jobManagerHolder.getJobManager().expandJobs(MetaData.ALL, true, ActionListener.wrap(jobs -> { + addJobsUsage(response, jobs.results(), jobsUsage); + GetDatafeedsStatsAction.Request datafeedStatsRequest = new GetDatafeedsStatsAction.Request( + GetDatafeedsStatsAction.ALL); + client.execute(GetDatafeedsStatsAction.INSTANCE, datafeedStatsRequest, datafeedStatsListener); + }, listener::onFailure)); + }, listener::onFailure); + + // Step 0. Kick off the chain of callbacks by requesting jobs stats + client.execute(GetJobsStatsAction.INSTANCE, jobStatsRequest, jobStatsListener); + } + + private void addJobsUsage(GetJobsStatsAction.Response response, List jobs, Map jobsUsage) { + StatsAccumulator allJobsDetectorsStats = new StatsAccumulator(); + StatsAccumulator allJobsModelSizeStats = new StatsAccumulator(); + ForecastStats allJobsForecastStats = new ForecastStats(); + + Map jobCountByState = new HashMap<>(); + Map detectorStatsByState = new HashMap<>(); + Map modelSizeStatsByState = new HashMap<>(); + Map forecastStatsByState = new HashMap<>(); + Map> createdByByState = new HashMap<>(); + + List jobsStats = response.getResponse().results(); + Map jobMap = jobs.stream().collect(Collectors.toMap(Job::getId, item -> item)); + Map allJobsCreatedBy = jobs.stream().map(this::jobCreatedBy) + .collect(Collectors.groupingBy(item -> item, Collectors.counting()));; + for (GetJobsStatsAction.Response.JobStats jobStats : jobsStats) { + ModelSizeStats modelSizeStats = jobStats.getModelSizeStats(); + Job job = jobMap.get(jobStats.getJobId()); + int detectorsCount = job.getAnalysisConfig().getDetectors().size(); + double modelSize = modelSizeStats == null ? 0.0 + : jobStats.getModelSizeStats().getModelBytes(); + + allJobsForecastStats.merge(jobStats.getForecastStats()); + allJobsDetectorsStats.add(detectorsCount); + allJobsModelSizeStats.add(modelSize); + + JobState jobState = jobStats.getState(); + jobCountByState.computeIfAbsent(jobState, js -> Counter.newCounter()).addAndGet(1); + detectorStatsByState.computeIfAbsent(jobState, + js -> new StatsAccumulator()).add(detectorsCount); + modelSizeStatsByState.computeIfAbsent(jobState, + js -> new StatsAccumulator()).add(modelSize); + forecastStatsByState.merge(jobState, jobStats.getForecastStats(), (f1, f2) -> f1.merge(f2)); + createdByByState.computeIfAbsent(jobState, js -> new HashMap<>()) + .compute(jobCreatedBy(job), (k, v) -> (v == null) ? 1L : (v + 1)); + } + + jobsUsage.put(MachineLearningFeatureSetUsage.ALL, createJobUsageEntry(jobs.size(), allJobsDetectorsStats, + allJobsModelSizeStats, allJobsForecastStats, allJobsCreatedBy)); + for (JobState jobState : jobCountByState.keySet()) { + jobsUsage.put(jobState.name().toLowerCase(Locale.ROOT), createJobUsageEntry( + jobCountByState.get(jobState).get(), + detectorStatsByState.get(jobState), + modelSizeStatsByState.get(jobState), + forecastStatsByState.get(jobState), + createdByByState.get(jobState))); + } + } + + private String jobCreatedBy(Job job) { + Map customSettings = job.getCustomSettings(); + if (customSettings == null || customSettings.containsKey(MachineLearningFeatureSetUsage.CREATED_BY) == false) { + return "unknown"; + } + // Replace non-alpha-numeric characters with underscores because + // the values from custom settings become keys in the usage data + return customSettings.get(MachineLearningFeatureSetUsage.CREATED_BY).toString().replaceAll("\\W", "_"); + } + + private Map createJobUsageEntry(long count, StatsAccumulator detectorStats, + StatsAccumulator modelSizeStats, + ForecastStats forecastStats, Map createdBy) { + Map usage = new HashMap<>(); + usage.put(MachineLearningFeatureSetUsage.COUNT, count); + usage.put(MachineLearningFeatureSetUsage.DETECTORS, detectorStats.asMap()); + usage.put(MachineLearningFeatureSetUsage.MODEL_SIZE, modelSizeStats.asMap()); + usage.put(MachineLearningFeatureSetUsage.FORECASTS, forecastStats.asMap()); + usage.put(MachineLearningFeatureSetUsage.CREATED_BY, createdBy); + return usage; + } + + private void addDatafeedsUsage(GetDatafeedsStatsAction.Response response, Map datafeedsUsage) { + Map datafeedCountByState = new HashMap<>(); + + List datafeedsStats = response.getResponse().results(); + for (GetDatafeedsStatsAction.Response.DatafeedStats datafeedStats : datafeedsStats) { + datafeedCountByState.computeIfAbsent(datafeedStats.getDatafeedState(), + ds -> Counter.newCounter()).addAndGet(1); + } + + datafeedsUsage.put(MachineLearningFeatureSetUsage.ALL, createDatafeedUsageEntry(response.getResponse().count())); + for (DatafeedState datafeedState : datafeedCountByState.keySet()) { + datafeedsUsage.put(datafeedState.name().toLowerCase(Locale.ROOT), + createDatafeedUsageEntry(datafeedCountByState.get(datafeedState).get())); + } + } + + private Map createDatafeedUsageEntry(long count) { + Map usage = new HashMap<>(); + usage.put(MachineLearningFeatureSetUsage.COUNT, count); + return usage; + } + + private static int mlNodeCount(final ClusterState clusterState) { + int mlNodeCount = 0; + for (DiscoveryNode node : clusterState.getNodes()) { + if (MachineLearning.isMlNode(node)) { + ++mlNodeCount; + } + } + return mlNodeCount; + } +} diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MlLifeCycleService.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MlLifeCycleService.java index 7309afa6b3ab4..0aa248e308384 100644 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MlLifeCycleService.java +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MlLifeCycleService.java @@ -41,7 +41,7 @@ public void beforeStop() { public synchronized void stop() { try { - if (MachineLearningFeatureSet.isRunningOnMlPlatform(false)) { + if (MachineLearningInfoTransportAction.isRunningOnMlPlatform(false)) { // This prevents datafeeds from sending data to autodetect processes WITHOUT stopping the // datafeeds, so they get reallocated. We have to do this first, otherwise the datafeeds // could fail if they send data to a dead autodetect process. diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/process/NativeControllerHolder.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/process/NativeControllerHolder.java index 5365a11f6b560..e5e009994a880 100644 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/process/NativeControllerHolder.java +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/process/NativeControllerHolder.java @@ -12,7 +12,7 @@ import java.io.IOException; /** - * Manages a singleton NativeController so that both the MachineLearningFeatureSet and MachineLearning classes can + * Manages a singleton NativeController so that both the MachineLearningInfoTransportAction and MachineLearning classes can * get access to the same one. */ public class NativeControllerHolder { diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/MachineLearningFeatureSetTests.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/MachineLearningInfoTransportActionTests.java similarity index 93% rename from x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/MachineLearningFeatureSetTests.java rename to x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/MachineLearningInfoTransportActionTests.java index 427b8dc851108..ab4b9aad52820 100644 --- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/MachineLearningFeatureSetTests.java +++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/MachineLearningInfoTransportActionTests.java @@ -72,7 +72,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class MachineLearningFeatureSetTests extends ESTestCase { +public class MachineLearningInfoTransportActionTests extends ESTestCase { private Settings commonSettings; private ClusterService clusterService; @@ -98,29 +98,30 @@ public void init() { givenDatafeeds(Collections.emptyList()); } - private MachineLearningFeatureSet.UsageTransportAction newUsageAction(Settings settings) { - return new MachineLearningFeatureSet.UsageTransportAction(mock(TransportService.class), clusterService, + private MachineLearningUsageTransportAction newUsageAction(Settings settings) { + return new MachineLearningUsageTransportAction(mock(TransportService.class), clusterService, null, mock(ActionFilters.class), mock(IndexNameExpressionResolver.class), TestEnvironment.newEnvironment(settings), client, licenseState, jobManagerHolder); } public void testIsRunningOnMlPlatform() { - assertTrue(MachineLearningFeatureSet.isRunningOnMlPlatform("Linux", "amd64", true)); - assertTrue(MachineLearningFeatureSet.isRunningOnMlPlatform("Windows 10", "amd64", true)); - assertTrue(MachineLearningFeatureSet.isRunningOnMlPlatform("Mac OS X", "x86_64", true)); - assertFalse(MachineLearningFeatureSet.isRunningOnMlPlatform("Linux", "i386", false)); - assertFalse(MachineLearningFeatureSet.isRunningOnMlPlatform("Windows 10", "i386", false)); - assertFalse(MachineLearningFeatureSet.isRunningOnMlPlatform("SunOS", "amd64", false)); + assertTrue(MachineLearningInfoTransportAction.isRunningOnMlPlatform("Linux", "amd64", true)); + assertTrue(MachineLearningInfoTransportAction.isRunningOnMlPlatform("Windows 10", "amd64", true)); + assertTrue(MachineLearningInfoTransportAction.isRunningOnMlPlatform("Mac OS X", "x86_64", true)); + assertFalse(MachineLearningInfoTransportAction.isRunningOnMlPlatform("Linux", "i386", false)); + assertFalse(MachineLearningInfoTransportAction.isRunningOnMlPlatform("Windows 10", "i386", false)); + assertFalse(MachineLearningInfoTransportAction.isRunningOnMlPlatform("SunOS", "amd64", false)); expectThrows(ElasticsearchException.class, - () -> MachineLearningFeatureSet.isRunningOnMlPlatform("Linux", "i386", true)); + () -> MachineLearningInfoTransportAction.isRunningOnMlPlatform("Linux", "i386", true)); expectThrows(ElasticsearchException.class, - () -> MachineLearningFeatureSet.isRunningOnMlPlatform("Windows 10", "i386", true)); + () -> MachineLearningInfoTransportAction.isRunningOnMlPlatform("Windows 10", "i386", true)); expectThrows(ElasticsearchException.class, - () -> MachineLearningFeatureSet.isRunningOnMlPlatform("SunOS", "amd64", true)); + () -> MachineLearningInfoTransportAction.isRunningOnMlPlatform("SunOS", "amd64", true)); } public void testAvailable() throws Exception { - MachineLearningFeatureSet featureSet = new MachineLearningFeatureSet(commonSettings, licenseState); + MachineLearningInfoTransportAction featureSet = new MachineLearningInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), commonSettings, licenseState); boolean available = randomBoolean(); when(licenseState.isMachineLearningAllowed()).thenReturn(available); assertThat(featureSet.available(), is(available)); @@ -145,7 +146,8 @@ public void testEnabled() throws Exception { settings.put("xpack.ml.enabled", enabled); } boolean expected = enabled || useDefault; - MachineLearningFeatureSet featureSet = new MachineLearningFeatureSet(settings.build(), licenseState); + MachineLearningInfoTransportAction featureSet = new MachineLearningInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), settings.build(), licenseState); assertThat(featureSet.enabled(), is(expected)); var usageAction = newUsageAction(settings.build()); PlainActionFuture future = new PlainActionFuture<>(); diff --git a/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/Monitoring.java b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/Monitoring.java index a6e0caf929971..5fac72d5edad9 100644 --- a/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/Monitoring.java +++ b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/Monitoring.java @@ -33,6 +33,7 @@ import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.xpack.core.XPackPlugin; import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; import org.elasticsearch.xpack.core.monitoring.MonitoringField; import org.elasticsearch.xpack.core.monitoring.action.MonitoringBulkAction; @@ -98,7 +99,6 @@ boolean isEnabled() { public Collection createGuiceModules() { List modules = new ArrayList<>(); modules.add(b -> { - XPackPlugin.bindFeatureSet(b, MonitoringFeatureSet.class); if (enabled == false) { b.bind(MonitoringService.class).toProvider(Providers.of(null)); b.bind(Exporters.class).toProvider(Providers.of(null)); @@ -142,13 +142,15 @@ public Collection createComponents(Client client, ClusterService cluster @Override public List> getActions() { - var usageAction = new ActionHandler<>(XPackUsageFeatureAction.MONITORING, MonitoringFeatureSet.UsageTransportAction.class); + var usageAction = new ActionHandler<>(XPackUsageFeatureAction.MONITORING, MonitoringUsageTransportAction.class); + var infoAction = new ActionHandler<>(XPackInfoFeatureAction.MONITORING, MonitoringInfoTransportAction.class); if (false == enabled) { - return singletonList(usageAction); + return Arrays.asList(usageAction, infoAction); } return Arrays.asList( new ActionHandler<>(MonitoringBulkAction.INSTANCE, TransportMonitoringBulkAction.class), - usageAction); + usageAction, + infoAction); } @Override diff --git a/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/MonitoringInfoTransportAction.java b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/MonitoringInfoTransportAction.java new file mode 100644 index 0000000000000..6769138e4caa0 --- /dev/null +++ b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/MonitoringInfoTransportAction.java @@ -0,0 +1,45 @@ +/* + * 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.xpack.monitoring; + +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackField; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureTransportAction; + +public class MonitoringInfoTransportAction extends XPackInfoFeatureTransportAction { + + private final boolean enabled; + private final XPackLicenseState licenseState; + + @Inject + public MonitoringInfoTransportAction(TransportService transportService, ActionFilters actionFilters, + Settings settings, XPackLicenseState licenseState) { + super(XPackInfoFeatureAction.MONITORING.name(), transportService, actionFilters); + this.enabled = XPackSettings.MONITORING_ENABLED.get(settings); + this.licenseState = licenseState; + } + + @Override + public String name() { + return XPackField.MONITORING; + } + + @Override + public boolean available() { + return licenseState.isMonitoringAllowed(); + } + + @Override + public boolean enabled() { + return enabled; + } +} diff --git a/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/MonitoringFeatureSet.java b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/MonitoringUsageTransportAction.java similarity index 50% rename from x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/MonitoringFeatureSet.java rename to x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/MonitoringUsageTransportAction.java index 4a0d53b424394..6666a8f0c4158 100644 --- a/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/MonitoringFeatureSet.java +++ b/x-pack/plugin/monitoring/src/main/java/org/elasticsearch/xpack/monitoring/MonitoringUsageTransportAction.java @@ -17,8 +17,6 @@ import org.elasticsearch.protocol.xpack.XPackUsageRequest; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; -import org.elasticsearch.xpack.core.XPackFeatureSet; -import org.elasticsearch.xpack.core.XPackField; import org.elasticsearch.xpack.core.XPackSettings; import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; @@ -30,58 +28,31 @@ import java.util.HashMap; import java.util.Map; -public class MonitoringFeatureSet implements XPackFeatureSet { - +public class MonitoringUsageTransportAction extends XPackUsageFeatureTransportAction { private final boolean enabled; + private final MonitoringService monitoring; private final XPackLicenseState licenseState; + private final Exporters exporters; @Inject - public MonitoringFeatureSet(Settings settings, XPackLicenseState licenseState) { + public MonitoringUsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, + ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, + Settings settings, XPackLicenseState licenseState, @Nullable MonitoringService monitoring, + @Nullable Exporters exporters) { + super(XPackUsageFeatureAction.MONITORING.name(), transportService, clusterService, threadPool, + actionFilters, indexNameExpressionResolver); this.enabled = XPackSettings.MONITORING_ENABLED.get(settings); this.licenseState = licenseState; + this.monitoring = monitoring; + this.exporters = exporters; } @Override - public String name() { - return XPackField.MONITORING; - } - - @Override - public boolean available() { - return licenseState != null && licenseState.isMonitoringAllowed(); - } - - @Override - public boolean enabled() { - return enabled; - } - - public static class UsageTransportAction extends XPackUsageFeatureTransportAction { - private final boolean enabled; - private final MonitoringService monitoring; - private final XPackLicenseState licenseState; - private final Exporters exporters; - - @Inject - public UsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, - ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, - Settings settings, XPackLicenseState licenseState, @Nullable MonitoringService monitoring, - @Nullable Exporters exporters) { - super(XPackUsageFeatureAction.MONITORING.name(), transportService, clusterService, threadPool, - actionFilters, indexNameExpressionResolver); - this.enabled = XPackSettings.MONITORING_ENABLED.get(settings); - this.licenseState = licenseState; - this.monitoring = monitoring; - this.exporters = exporters; - } - - @Override - protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { - final boolean collectionEnabled = monitoring != null && monitoring.isMonitoringActive(); - var usage = - new MonitoringFeatureSetUsage(licenseState.isMonitoringAllowed(), enabled, collectionEnabled, exportersUsage(exporters)); - listener.onResponse(new XPackUsageFeatureResponse(usage)); - } + protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { + final boolean collectionEnabled = monitoring != null && monitoring.isMonitoringActive(); + var usage = + new MonitoringFeatureSetUsage(licenseState.isMonitoringAllowed(), enabled, collectionEnabled, exportersUsage(exporters)); + listener.onResponse(new XPackUsageFeatureResponse(usage)); } static Map exportersUsage(Exporters exporters) { @@ -98,5 +69,4 @@ static Map exportersUsage(Exporters exporters) { } return usage; } - } diff --git a/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/MonitoringFeatureSetTests.java b/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/MonitoringInfoTransportActionTests.java similarity index 89% rename from x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/MonitoringFeatureSetTests.java rename to x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/MonitoringInfoTransportActionTests.java index b83cd37cdf348..6dc53b3d67a73 100644 --- a/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/MonitoringFeatureSetTests.java +++ b/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/MonitoringInfoTransportActionTests.java @@ -38,14 +38,15 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class MonitoringFeatureSetTests extends ESTestCase { +public class MonitoringInfoTransportActionTests extends ESTestCase { private final MonitoringService monitoring = mock(MonitoringService.class); private final XPackLicenseState licenseState = mock(XPackLicenseState.class); private final Exporters exporters = mock(Exporters.class); public void testAvailable() { - MonitoringFeatureSet featureSet = new MonitoringFeatureSet(Settings.EMPTY, licenseState); + MonitoringInfoTransportAction featureSet = new MonitoringInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, licenseState); boolean available = randomBoolean(); when(licenseState.isMonitoringAllowed()).thenReturn(available); assertThat(featureSet.available(), is(available)); @@ -55,12 +56,14 @@ public void testEnabledSetting() { boolean enabled = randomBoolean(); Settings.Builder settings = Settings.builder(); settings.put("xpack.monitoring.enabled", enabled); - MonitoringFeatureSet featureSet = new MonitoringFeatureSet(settings.build(), licenseState); + MonitoringInfoTransportAction featureSet = new MonitoringInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), settings.build(), licenseState); assertThat(featureSet.enabled(), is(enabled)); } public void testEnabledDefault() { - MonitoringFeatureSet featureSet = new MonitoringFeatureSet(Settings.EMPTY, licenseState); + MonitoringInfoTransportAction featureSet = new MonitoringInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, licenseState); assertThat(featureSet.enabled(), is(true)); } @@ -99,7 +102,7 @@ public void testUsage() throws Exception { when(exporters.getEnabledExporters()).thenReturn(exporterList); when(monitoring.isMonitoringActive()).thenReturn(collectionEnabled); - var usageAction = new MonitoringFeatureSet.UsageTransportAction(mock(TransportService.class), null, null, + var usageAction = new MonitoringUsageTransportAction(mock(TransportService.class), null, null, mock(ActionFilters.class), null, Settings.EMPTY,licenseState, monitoring, exporters); PlainActionFuture future = new PlainActionFuture<>(); usageAction.masterOperation(null, null, future); diff --git a/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/Rollup.java b/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/Rollup.java index 46fc4e95bf81f..20c8fb4502891 100644 --- a/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/Rollup.java +++ b/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/Rollup.java @@ -13,7 +13,6 @@ import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.service.ClusterService; -import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.IndexScopedSettings; @@ -23,7 +22,6 @@ import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.env.Environment; import org.elasticsearch.env.NodeEnvironment; -import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.persistent.PersistentTasksExecutor; import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.plugins.PersistentTaskPlugin; @@ -35,8 +33,8 @@ import org.elasticsearch.threadpool.FixedExecutorBuilder; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.watcher.ResourceWatcherService; -import org.elasticsearch.xpack.core.XPackPlugin; import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; import org.elasticsearch.xpack.core.rollup.RollupField; import org.elasticsearch.xpack.core.rollup.action.DeleteRollupJobAction; @@ -68,7 +66,6 @@ import org.elasticsearch.xpack.rollup.rest.RestStopRollupJobAction; import java.time.Clock; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -79,7 +76,6 @@ import java.util.regex.Pattern; import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; public class Rollup extends Plugin implements ActionPlugin, PersistentTaskPlugin { @@ -124,15 +120,6 @@ public Collection createComponents(Client client, ClusterService cluster return emptyList(); } - @Override - public Collection createGuiceModules() { - List modules = new ArrayList<>(); - modules.add(b -> XPackPlugin.bindFeatureSet(b, RollupFeatureSet.class)); - return modules; - } - - protected XPackLicenseState getLicenseState() { return XPackPlugin.getSharedLicenseState(); } - @Override public List getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings, IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter, @@ -157,9 +144,10 @@ public List getRestHandlers(Settings settings, RestController restC @Override public List> getActions() { - var usageAction = new ActionHandler<>(XPackUsageFeatureAction.ROLLUP, RollupFeatureSet.UsageTransportAction.class); - if (!enabled) { - return singletonList(usageAction); + var usageAction = new ActionHandler<>(XPackUsageFeatureAction.ROLLUP, RollupUsageTransportAction.class); + var infoAction = new ActionHandler<>(XPackInfoFeatureAction.ROLLUP, RollupInfoTransportAction.class); + if (enabled == false) { + return Arrays.asList(usageAction, infoAction); } return Arrays.asList( new ActionHandler<>(RollupSearchAction.INSTANCE, TransportRollupSearchAction.class), @@ -170,7 +158,8 @@ public List getRestHandlers(Settings settings, RestController restC new ActionHandler<>(GetRollupJobsAction.INSTANCE, TransportGetRollupJobAction.class), new ActionHandler<>(GetRollupCapsAction.INSTANCE, TransportGetRollupCapsAction.class), new ActionHandler<>(GetRollupIndexCapsAction.INSTANCE, TransportGetRollupIndexCapsAction.class), - usageAction); + usageAction, + infoAction); } @Override diff --git a/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/RollupFeatureSet.java b/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/RollupFeatureSet.java deleted file mode 100644 index 5727563a84f3a..0000000000000 --- a/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/RollupFeatureSet.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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.xpack.rollup; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.action.support.ActionFilters; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; -import org.elasticsearch.cluster.service.ClusterService; -import org.elasticsearch.common.Nullable; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.license.XPackLicenseState; -import org.elasticsearch.protocol.xpack.XPackUsageRequest; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.TransportService; -import org.elasticsearch.xpack.core.XPackFeatureSet; -import org.elasticsearch.xpack.core.XPackField; -import org.elasticsearch.xpack.core.XPackSettings; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; -import org.elasticsearch.xpack.core.rollup.RollupFeatureSetUsage; - -public class RollupFeatureSet implements XPackFeatureSet { - - private final boolean enabled; - private final XPackLicenseState licenseState; - - @Inject - public RollupFeatureSet(Settings settings, @Nullable XPackLicenseState licenseState) { - this.enabled = XPackSettings.ROLLUP_ENABLED.get(settings); - this.licenseState = licenseState; - } - - @Override - public String name() { - return XPackField.ROLLUP; - } - - @Override - public boolean available() { - return licenseState != null && licenseState.isRollupAllowed(); - } - - @Override - public boolean enabled() { - return enabled; - } - - public static class UsageTransportAction extends XPackUsageFeatureTransportAction { - - private final Settings settings; - private final XPackLicenseState licenseState; - - @Inject - public UsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, - ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, - Settings settings, XPackLicenseState licenseState) { - super(XPackUsageFeatureAction.ROLLUP.name(), transportService, clusterService, - threadPool, actionFilters, indexNameExpressionResolver); - this.settings = settings; - this.licenseState = licenseState; - } - - @Override - protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { - boolean available = licenseState.isRollupAllowed(); - // TODO expose the currently running rollup tasks on this node? Unclear the best way to do that - RollupFeatureSetUsage usage = - new RollupFeatureSetUsage(available, XPackSettings.ROLLUP_ENABLED.get(settings)); - listener.onResponse(new XPackUsageFeatureResponse(usage)); - } - } -} diff --git a/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/RollupInfoTransportAction.java b/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/RollupInfoTransportAction.java new file mode 100644 index 0000000000000..93330872554cc --- /dev/null +++ b/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/RollupInfoTransportAction.java @@ -0,0 +1,46 @@ +/* + * 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.xpack.rollup; + +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackField; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureTransportAction; + +public class RollupInfoTransportAction extends XPackInfoFeatureTransportAction { + + private final boolean enabled; + private final XPackLicenseState licenseState; + + @Inject + public RollupInfoTransportAction(TransportService transportService, ActionFilters actionFilters, + Settings settings, XPackLicenseState licenseState) { + super(XPackInfoFeatureAction.ROLLUP.name(), transportService, actionFilters); + this.enabled = XPackSettings.ROLLUP_ENABLED.get(settings); + this.licenseState = licenseState; + } + + @Override + public String name() { + return XPackField.ROLLUP; + } + + @Override + public boolean available() { + return licenseState.isRollupAllowed(); + } + + @Override + public boolean enabled() { + return enabled; + } + +} diff --git a/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/RollupUsageTransportAction.java b/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/RollupUsageTransportAction.java new file mode 100644 index 0000000000000..74982b9bf2c3f --- /dev/null +++ b/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/RollupUsageTransportAction.java @@ -0,0 +1,48 @@ +/* + * 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.xpack.rollup; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.protocol.xpack.XPackUsageRequest; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; +import org.elasticsearch.xpack.core.rollup.RollupFeatureSetUsage; + +public class RollupUsageTransportAction extends XPackUsageFeatureTransportAction { + + private final Settings settings; + private final XPackLicenseState licenseState; + + @Inject + public RollupUsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, + ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, + Settings settings, XPackLicenseState licenseState) { + super(XPackUsageFeatureAction.ROLLUP.name(), transportService, clusterService, + threadPool, actionFilters, indexNameExpressionResolver); + this.settings = settings; + this.licenseState = licenseState; + } + + @Override + protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { + boolean available = licenseState.isRollupAllowed(); + // TODO expose the currently running rollup tasks on this node? Unclear the best way to do that + RollupFeatureSetUsage usage = + new RollupFeatureSetUsage(available, XPackSettings.ROLLUP_ENABLED.get(settings)); + listener.onResponse(new XPackUsageFeatureResponse(usage)); + } +} diff --git a/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/RollupFeatureSetTests.java b/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/RollupInfoTransportActionTests.java similarity index 78% rename from x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/RollupFeatureSetTests.java rename to x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/RollupInfoTransportActionTests.java index 154a89e155315..a47e582adc1c9 100644 --- a/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/RollupFeatureSetTests.java +++ b/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/RollupInfoTransportActionTests.java @@ -24,7 +24,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class RollupFeatureSetTests extends ESTestCase { +public class RollupInfoTransportActionTests extends ESTestCase { private XPackLicenseState licenseState; @Before @@ -33,7 +33,8 @@ public void init() { } public void testAvailable() { - RollupFeatureSet featureSet = new RollupFeatureSet(Settings.EMPTY, licenseState); + RollupInfoTransportAction featureSet = new RollupInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, licenseState); boolean available = randomBoolean(); when(licenseState.isRollupAllowed()).thenReturn(available); assertThat(featureSet.available(), is(available)); @@ -43,17 +44,19 @@ public void testEnabledSetting() { boolean enabled = randomBoolean(); Settings.Builder settings = Settings.builder(); settings.put("xpack.rollup.enabled", enabled); - RollupFeatureSet featureSet = new RollupFeatureSet(settings.build(), licenseState); + RollupInfoTransportAction featureSet = new RollupInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), settings.build(), licenseState); assertThat(featureSet.enabled(), is(enabled)); } public void testEnabledDefault() { - RollupFeatureSet featureSet = new RollupFeatureSet(Settings.EMPTY, licenseState); + RollupInfoTransportAction featureSet = new RollupInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, licenseState); assertThat(featureSet.enabled(), is(true)); } public void testUsage() throws ExecutionException, InterruptedException, IOException { - var usageAction = new RollupFeatureSet.UsageTransportAction(mock(TransportService.class), null, null, + var usageAction = new RollupUsageTransportAction(mock(TransportService.class), null, null, mock(ActionFilters.class), null, Settings.EMPTY, licenseState); PlainActionFuture future = new PlainActionFuture<>(); usageAction.masterOperation(null, null, future); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java index e5b49eea42122..3af8a7e36d1e8 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -72,6 +72,7 @@ import org.elasticsearch.xpack.core.XPackField; import org.elasticsearch.xpack.core.XPackPlugin; import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; import org.elasticsearch.xpack.core.security.SecurityContext; import org.elasticsearch.xpack.core.security.SecurityExtension; @@ -329,13 +330,12 @@ public Collection createGuiceModules() { if (enabled == false) { modules.add(b -> b.bind(IPFilter.class).toProvider(Providers.of(null))); } - modules.add(b -> XPackPlugin.bindFeatureSet(b, SecurityFeatureSet.class)); if (enabled == false) { modules.add(b -> { - b.bind(Realms.class).toProvider(Providers.of(null)); // for SecurityFeatureSet - b.bind(CompositeRolesStore.class).toProvider(Providers.of(null)); // for SecurityFeatureSet - b.bind(NativeRoleMappingStore.class).toProvider(Providers.of(null)); // for SecurityFeatureSet + b.bind(Realms.class).toProvider(Providers.of(null)); // for SecurityInfoTransportAction + b.bind(CompositeRolesStore.class).toProvider(Providers.of(null)); // for SecurityInfoTransportAction + b.bind(NativeRoleMappingStore.class).toProvider(Providers.of(null)); // for SecurityInfoTransportAction b.bind(AuditTrailService.class) .toInstance(new AuditTrailService(Collections.emptyList(), getLicenseState())); }); @@ -473,7 +473,7 @@ auditTrailService, failureHandler, threadPool, anonymousUser, getAuthorizationEn components.add(nativeRolesStore); // used by roles actions components.add(reservedRolesStore); // used by roles actions - components.add(allRolesStore); // for SecurityFeatureSet and clear roles cache + components.add(allRolesStore); // for SecurityInfoTransportAction and clear roles cache components.add(authzService); ipFilter.set(new IPFilter(settings, auditTrailService, clusterService.getClusterSettings(), getLicenseState())); @@ -707,9 +707,10 @@ public void onIndexModule(IndexModule module) { @Override public List> getActions() { - var usageAction = new ActionHandler<>(XPackUsageFeatureAction.SECURITY, SecurityFeatureSet.UsageTransportAction.class); + var usageAction = new ActionHandler<>(XPackUsageFeatureAction.SECURITY, SecurityUsageTransportAction.class); + var infoAction = new ActionHandler<>(XPackInfoFeatureAction.SECURITY, SecurityInfoTransportAction.class); if (enabled == false) { - return singletonList(usageAction); + return Arrays.asList(usageAction, infoAction); } return Arrays.asList( new ActionHandler<>(ClearRealmCacheAction.INSTANCE, TransportClearRealmCacheAction.class), @@ -746,7 +747,8 @@ public void onIndexModule(IndexModule module) { new ActionHandler<>(CreateApiKeyAction.INSTANCE, TransportCreateApiKeyAction.class), new ActionHandler<>(InvalidateApiKeyAction.INSTANCE, TransportInvalidateApiKeyAction.class), new ActionHandler<>(GetApiKeyAction.INSTANCE, TransportGetApiKeyAction.class), - usageAction); + usageAction, + infoAction); } @Override diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityFeatureSet.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityFeatureSet.java deleted file mode 100644 index 0d60c7938b270..0000000000000 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityFeatureSet.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * 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.xpack.security; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.action.support.ActionFilters; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; -import org.elasticsearch.cluster.service.ClusterService; -import org.elasticsearch.common.Nullable; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.util.concurrent.CountDown; -import org.elasticsearch.license.XPackLicenseState; -import org.elasticsearch.protocol.xpack.XPackUsageRequest; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.TransportService; -import org.elasticsearch.xpack.core.XPackFeatureSet; -import org.elasticsearch.xpack.core.XPackField; -import org.elasticsearch.xpack.core.XPackSettings; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; -import org.elasticsearch.xpack.core.security.SecurityFeatureSetUsage; -import org.elasticsearch.xpack.core.security.user.AnonymousUser; -import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail; -import org.elasticsearch.xpack.security.authc.Realms; -import org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingStore; -import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore; -import org.elasticsearch.xpack.security.transport.filter.IPFilter; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; - -import static java.util.Collections.singletonMap; -import static org.elasticsearch.xpack.core.XPackSettings.API_KEY_SERVICE_ENABLED_SETTING; -import static org.elasticsearch.xpack.core.XPackSettings.HTTP_SSL_ENABLED; -import static org.elasticsearch.xpack.core.XPackSettings.TOKEN_SERVICE_ENABLED_SETTING; -import static org.elasticsearch.xpack.core.XPackSettings.TRANSPORT_SSL_ENABLED; - -/** - * Indicates whether the features of Security are currently in use - */ -public class SecurityFeatureSet implements XPackFeatureSet { - - private final Settings settings; - private final XPackLicenseState licenseState; - - @Inject - public SecurityFeatureSet(Settings settings, @Nullable XPackLicenseState licenseState) { - this.licenseState = licenseState; - this.settings = settings; - } - - @Override - public String name() { - return XPackField.SECURITY; - } - - @Override - public boolean available() { - return licenseState != null && licenseState.isSecurityAvailable(); - } - - @Override - public boolean enabled() { - if (licenseState != null) { - return XPackSettings.SECURITY_ENABLED.get(settings) && licenseState.isSecurityDisabledByLicenseDefaults() == false; - } - return false; - } - - private static boolean available(XPackLicenseState licenseState) { - return licenseState != null && licenseState.isSecurityAvailable(); - } - - private static boolean enabled(Settings settings, XPackLicenseState licenseState) { - if (licenseState != null) { - return XPackSettings.SECURITY_ENABLED.get(settings) && - licenseState.isSecurityDisabledByLicenseDefaults() == false; - } - return false; - } - - public static class UsageTransportAction extends XPackUsageFeatureTransportAction { - - private final Settings settings; - private final XPackLicenseState licenseState; - private final Realms realms; - private final CompositeRolesStore rolesStore; - private final NativeRoleMappingStore roleMappingStore; - private final IPFilter ipFilter; - - @Inject - public UsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, - ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, - Settings settings, XPackLicenseState licenseState, @Nullable Realms realms, - @Nullable CompositeRolesStore rolesStore, @Nullable NativeRoleMappingStore roleMappingStore, - @Nullable IPFilter ipFilter) { - super(XPackUsageFeatureAction.SECURITY.name(), transportService, clusterService, threadPool, - actionFilters, indexNameExpressionResolver); - this.settings = settings; - this.licenseState = licenseState; - this.realms = realms; - this.rolesStore = rolesStore; - this.roleMappingStore = roleMappingStore; - this.ipFilter = ipFilter; - } - - @Override - protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { - Map sslUsage = sslUsage(settings); - Map tokenServiceUsage = tokenServiceUsage(settings); - Map apiKeyServiceUsage = apiKeyServiceUsage(settings); - Map auditUsage = auditUsage(settings); - Map ipFilterUsage = ipFilterUsage(ipFilter); - Map anonymousUsage = singletonMap("enabled", AnonymousUser.isAnonymousEnabled(settings)); - - final AtomicReference> rolesUsageRef = new AtomicReference<>(); - final AtomicReference> roleMappingUsageRef = new AtomicReference<>(); - final AtomicReference> realmsUsageRef = new AtomicReference<>(); - final CountDown countDown = new CountDown(3); - final Runnable doCountDown = () -> { - if (countDown.countDown()) { - var usage = new SecurityFeatureSetUsage(available(licenseState), enabled(settings, licenseState), - realmsUsageRef.get(), rolesUsageRef.get(), roleMappingUsageRef.get(), sslUsage, auditUsage, - ipFilterUsage, anonymousUsage, tokenServiceUsage, apiKeyServiceUsage); - listener.onResponse(new XPackUsageFeatureResponse(usage)); - } - }; - - final ActionListener> rolesStoreUsageListener = - ActionListener.wrap(rolesStoreUsage -> { - rolesUsageRef.set(rolesStoreUsage); - doCountDown.run(); - }, listener::onFailure); - - final ActionListener> roleMappingStoreUsageListener = - ActionListener.wrap(nativeRoleMappingStoreUsage -> { - Map usage = singletonMap("native", nativeRoleMappingStoreUsage); - roleMappingUsageRef.set(usage); - doCountDown.run(); - }, listener::onFailure); - - final ActionListener> realmsUsageListener = - ActionListener.wrap(realmsUsage -> { - realmsUsageRef.set(realmsUsage); - doCountDown.run(); - }, listener::onFailure); - - if (rolesStore == null) { - rolesStoreUsageListener.onResponse(Collections.emptyMap()); - } else { - rolesStore.usageStats(rolesStoreUsageListener); - } - if (roleMappingStore == null) { - roleMappingStoreUsageListener.onResponse(Collections.emptyMap()); - } else { - roleMappingStore.usageStats(roleMappingStoreUsageListener); - } - if (realms == null) { - realmsUsageListener.onResponse(Collections.emptyMap()); - } else { - realms.usageStats(realmsUsageListener); - } - - } - } - - static Map sslUsage(Settings settings) { - // If security has been explicitly disabled in the settings, then SSL is also explicitly disabled, and we don't want to report - // these http/transport settings as they would be misleading (they could report `true` even though they were ignored) - // But, if security has not been explicitly configured, but has defaulted to off due to the current license type, - // then these SSL settings are still respected (that is SSL might be enabled, while the rest of security is disabled). - if (XPackSettings.SECURITY_ENABLED.get(settings)) { - Map map = new HashMap<>(2); - map.put("http", singletonMap("enabled", HTTP_SSL_ENABLED.get(settings))); - map.put("transport", singletonMap("enabled", TRANSPORT_SSL_ENABLED.get(settings))); - return map; - } else { - return Collections.emptyMap(); - } - } - - static Map tokenServiceUsage(Settings settings) { - return singletonMap("enabled", TOKEN_SERVICE_ENABLED_SETTING.get(settings)); - } - - static Map apiKeyServiceUsage(Settings settings) { - return singletonMap("enabled", API_KEY_SERVICE_ENABLED_SETTING.get(settings)); - } - - static Map auditUsage(Settings settings) { - Map map = new HashMap<>(2); - map.put("enabled", XPackSettings.AUDIT_ENABLED.get(settings)); - if (XPackSettings.AUDIT_ENABLED.get(settings)) { - // the only available output type is "logfile", but the optputs= is to keep compatibility with previous reporting format - map.put("outputs", Arrays.asList(LoggingAuditTrail.NAME)); - } - return map; - } - - static Map ipFilterUsage(@Nullable IPFilter ipFilter) { - if (ipFilter == null) { - return IPFilter.DISABLED_USAGE_STATS; - } - return ipFilter.usageStats(); - } - -} diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityInfoTransportAction.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityInfoTransportAction.java new file mode 100644 index 0000000000000..b554309def497 --- /dev/null +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityInfoTransportAction.java @@ -0,0 +1,48 @@ +/* + * 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.xpack.security; + +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackField; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureTransportAction; + +/** + * Indicates whether the features of Security are currently in use + */ +public class SecurityInfoTransportAction extends XPackInfoFeatureTransportAction { + + private final boolean enabled; + private final XPackLicenseState licenseState; + + @Inject + public SecurityInfoTransportAction(TransportService transportService, ActionFilters actionFilters, + Settings settings, XPackLicenseState licenseState) { + super(XPackInfoFeatureAction.SECURITY.name(), transportService, actionFilters); + this.enabled = XPackSettings.SECURITY_ENABLED.get(settings); + this.licenseState = licenseState; + } + + @Override + public String name() { + return XPackField.SECURITY; + } + + @Override + public boolean available() { + return licenseState.isSecurityAvailable(); + } + + @Override + public boolean enabled() { + return enabled && licenseState.isSecurityDisabledByLicenseDefaults() == false; + } +} diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityUsageTransportAction.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityUsageTransportAction.java new file mode 100644 index 0000000000000..3281373580747 --- /dev/null +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityUsageTransportAction.java @@ -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.xpack.security; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.CountDown; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.protocol.xpack.XPackUsageRequest; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; +import org.elasticsearch.xpack.core.security.SecurityFeatureSetUsage; +import org.elasticsearch.xpack.core.security.user.AnonymousUser; +import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail; +import org.elasticsearch.xpack.security.authc.Realms; +import org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingStore; +import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore; +import org.elasticsearch.xpack.security.transport.filter.IPFilter; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +import static java.util.Collections.singletonMap; +import static org.elasticsearch.xpack.core.XPackSettings.API_KEY_SERVICE_ENABLED_SETTING; +import static org.elasticsearch.xpack.core.XPackSettings.HTTP_SSL_ENABLED; +import static org.elasticsearch.xpack.core.XPackSettings.TOKEN_SERVICE_ENABLED_SETTING; +import static org.elasticsearch.xpack.core.XPackSettings.TRANSPORT_SSL_ENABLED; + +public class SecurityUsageTransportAction extends XPackUsageFeatureTransportAction { + + private final boolean enabledInSettings; + private final Settings settings; + private final XPackLicenseState licenseState; + private final Realms realms; + private final CompositeRolesStore rolesStore; + private final NativeRoleMappingStore roleMappingStore; + private final IPFilter ipFilter; + + @Inject + public SecurityUsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, + ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, + Settings settings, XPackLicenseState licenseState, @Nullable Realms realms, + @Nullable CompositeRolesStore rolesStore, @Nullable NativeRoleMappingStore roleMappingStore, + @Nullable IPFilter ipFilter) { + super(XPackUsageFeatureAction.SECURITY.name(), transportService, clusterService, threadPool, + actionFilters, indexNameExpressionResolver); + this.enabledInSettings = XPackSettings.SECURITY_ENABLED.get(settings); + this.settings = settings; + this.licenseState = licenseState; + this.realms = realms; + this.rolesStore = rolesStore; + this.roleMappingStore = roleMappingStore; + this.ipFilter = ipFilter; + } + + @Override + protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { + Map sslUsage = sslUsage(settings); + Map tokenServiceUsage = tokenServiceUsage(settings); + Map apiKeyServiceUsage = apiKeyServiceUsage(settings); + Map auditUsage = auditUsage(settings); + Map ipFilterUsage = ipFilterUsage(ipFilter); + Map anonymousUsage = singletonMap("enabled", AnonymousUser.isAnonymousEnabled(settings)); + + final AtomicReference> rolesUsageRef = new AtomicReference<>(); + final AtomicReference> roleMappingUsageRef = new AtomicReference<>(); + final AtomicReference> realmsUsageRef = new AtomicReference<>(); + final CountDown countDown = new CountDown(3); + final Runnable doCountDown = () -> { + if (countDown.countDown()) { + boolean enabled = enabledInSettings && licenseState.isSecurityDisabledByLicenseDefaults() == false; + var usage = new SecurityFeatureSetUsage(licenseState.isSecurityAvailable(), enabled, + realmsUsageRef.get(), rolesUsageRef.get(), roleMappingUsageRef.get(), sslUsage, auditUsage, + ipFilterUsage, anonymousUsage, tokenServiceUsage, apiKeyServiceUsage); + listener.onResponse(new XPackUsageFeatureResponse(usage)); + } + }; + + final ActionListener> rolesStoreUsageListener = + ActionListener.wrap(rolesStoreUsage -> { + rolesUsageRef.set(rolesStoreUsage); + doCountDown.run(); + }, listener::onFailure); + + final ActionListener> roleMappingStoreUsageListener = + ActionListener.wrap(nativeRoleMappingStoreUsage -> { + Map usage = singletonMap("native", nativeRoleMappingStoreUsage); + roleMappingUsageRef.set(usage); + doCountDown.run(); + }, listener::onFailure); + + final ActionListener> realmsUsageListener = + ActionListener.wrap(realmsUsage -> { + realmsUsageRef.set(realmsUsage); + doCountDown.run(); + }, listener::onFailure); + + if (rolesStore == null) { + rolesStoreUsageListener.onResponse(Collections.emptyMap()); + } else { + rolesStore.usageStats(rolesStoreUsageListener); + } + if (roleMappingStore == null) { + roleMappingStoreUsageListener.onResponse(Collections.emptyMap()); + } else { + roleMappingStore.usageStats(roleMappingStoreUsageListener); + } + if (realms == null) { + realmsUsageListener.onResponse(Collections.emptyMap()); + } else { + realms.usageStats(realmsUsageListener); + } + + } + + static Map sslUsage(Settings settings) { + // If security has been explicitly disabled in the settings, then SSL is also explicitly disabled, and we don't want to report + // these http/transport settings as they would be misleading (they could report `true` even though they were ignored) + // But, if security has not been explicitly configured, but has defaulted to off due to the current license type, + // then these SSL settings are still respected (that is SSL might be enabled, while the rest of security is disabled). + if (XPackSettings.SECURITY_ENABLED.get(settings)) { + Map map = new HashMap<>(2); + map.put("http", singletonMap("enabled", HTTP_SSL_ENABLED.get(settings))); + map.put("transport", singletonMap("enabled", TRANSPORT_SSL_ENABLED.get(settings))); + return map; + } else { + return Collections.emptyMap(); + } + } + + static Map tokenServiceUsage(Settings settings) { + return singletonMap("enabled", TOKEN_SERVICE_ENABLED_SETTING.get(settings)); + } + + static Map apiKeyServiceUsage(Settings settings) { + return singletonMap("enabled", API_KEY_SERVICE_ENABLED_SETTING.get(settings)); + } + + static Map auditUsage(Settings settings) { + Map map = new HashMap<>(2); + map.put("enabled", XPackSettings.AUDIT_ENABLED.get(settings)); + if (XPackSettings.AUDIT_ENABLED.get(settings)) { + // the only available output type is "logfile", but the optputs= is to keep compatibility with previous reporting format + map.put("outputs", Arrays.asList(LoggingAuditTrail.NAME)); + } + return map; + } + + static Map ipFilterUsage(@Nullable IPFilter ipFilter) { + if (ipFilter == null) { + return IPFilter.DISABLED_USAGE_STATS; + } + return ipFilter.usageStats(); + } +} diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityFeatureSetTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityInfoTransportActionTests.java similarity index 95% rename from x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityFeatureSetTests.java rename to x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityInfoTransportActionTests.java index 3889b4d4d2192..21517144d0457 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityFeatureSetTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityInfoTransportActionTests.java @@ -47,7 +47,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class SecurityFeatureSetTests extends ESTestCase { +public class SecurityInfoTransportActionTests extends ESTestCase { private Settings settings; private XPackLicenseState licenseState; @@ -67,7 +67,8 @@ public void init() throws Exception { } public void testAvailable() { - SecurityFeatureSet featureSet = new SecurityFeatureSet(settings, licenseState); + SecurityInfoTransportAction featureSet = new SecurityInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), settings, licenseState); when(licenseState.isSecurityAvailable()).thenReturn(true); assertThat(featureSet.available(), is(true)); @@ -76,11 +77,13 @@ public void testAvailable() { } public void testEnabled() { - SecurityFeatureSet featureSet = new SecurityFeatureSet(settings, licenseState); + SecurityInfoTransportAction featureSet = new SecurityInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), settings, licenseState); assertThat(featureSet.enabled(), is(true)); when(licenseState.isSecurityDisabledByLicenseDefaults()).thenReturn(true); - featureSet = new SecurityFeatureSet(settings, licenseState); + featureSet = new SecurityInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), settings, licenseState); assertThat(featureSet.enabled(), is(false)); } @@ -321,8 +324,8 @@ private void configureRoleMappingStoreUsage(boolean roleMappingStoreEnabled) { }).when(roleMappingStore).usageStats(any(ActionListener.class)); } - private SecurityFeatureSet.UsageTransportAction newUsageAction(Settings settings) { - return new SecurityFeatureSet.UsageTransportAction(mock(TransportService.class),null, + private SecurityUsageTransportAction newUsageAction(Settings settings) { + return new SecurityUsageTransportAction(mock(TransportService.class),null, null, mock(ActionFilters.class),null, settings, licenseState, realms, rolesStore, roleMappingStore, ipFilter); } diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/SqlFeatureSet.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/SqlFeatureSet.java deleted file mode 100644 index eb99e27ace9e0..0000000000000 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/SqlFeatureSet.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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.xpack.sql; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.action.support.ActionFilters; -import org.elasticsearch.client.Client; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; -import org.elasticsearch.cluster.service.ClusterService; -import org.elasticsearch.common.Nullable; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.license.XPackLicenseState; -import org.elasticsearch.protocol.xpack.XPackUsageRequest; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.TransportService; -import org.elasticsearch.xpack.core.XPackFeatureSet; -import org.elasticsearch.xpack.core.XPackField; -import org.elasticsearch.xpack.core.XPackSettings; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; -import org.elasticsearch.xpack.core.sql.SqlFeatureSetUsage; -import org.elasticsearch.xpack.core.watcher.common.stats.Counters; -import org.elasticsearch.xpack.sql.plugin.SqlStatsAction; -import org.elasticsearch.xpack.sql.plugin.SqlStatsRequest; -import org.elasticsearch.xpack.sql.plugin.SqlStatsResponse; - -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -public class SqlFeatureSet implements XPackFeatureSet { - - private final boolean enabled; - private final XPackLicenseState licenseState; - private final Client client; - - @Inject - public SqlFeatureSet(Settings settings, @Nullable XPackLicenseState licenseState, Client client) { - this.enabled = XPackSettings.SQL_ENABLED.get(settings); - this.licenseState = licenseState; - this.client = client; - } - - @Override - public String name() { - return XPackField.SQL; - } - - @Override - public boolean available() { - return licenseState != null && licenseState.isSqlAllowed(); - } - - @Override - public boolean enabled() { - return enabled; - } - - public static class UsageTransportAction extends XPackUsageFeatureTransportAction { - private final boolean enabled; - private final XPackLicenseState licenseState; - private final Client client; - - @Inject - public UsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, - ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, - Settings settings, XPackLicenseState licenseState, Client client) { - super(XPackUsageFeatureAction.SQL.name(), transportService, clusterService, threadPool, actionFilters, - indexNameExpressionResolver); - this.enabled = XPackSettings.SQL_ENABLED.get(settings); - this.licenseState = licenseState; - this.client = client; - } - - @Override - protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { - boolean available = licenseState.isSqlAllowed(); - if (enabled) { - SqlStatsRequest sqlRequest = new SqlStatsRequest(); - sqlRequest.includeStats(true); - client.execute(SqlStatsAction.INSTANCE, sqlRequest, ActionListener.wrap(r -> { - List countersPerNode = r.getNodes() - .stream() - .map(SqlStatsResponse.NodeStatsResponse::getStats) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - Counters mergedCounters = Counters.merge(countersPerNode); - SqlFeatureSetUsage usage = new SqlFeatureSetUsage(available, enabled, mergedCounters.toNestedMap()); - listener.onResponse(new XPackUsageFeatureResponse(usage)); - }, listener::onFailure)); - } else { - SqlFeatureSetUsage usage = new SqlFeatureSetUsage(available, enabled, Collections.emptyMap()); - listener.onResponse(new XPackUsageFeatureResponse(usage)); - } - } - } -} diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/SqlInfoTransportAction.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/SqlInfoTransportAction.java new file mode 100644 index 0000000000000..45a076f251273 --- /dev/null +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/SqlInfoTransportAction.java @@ -0,0 +1,46 @@ +/* + * 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.xpack.sql; + +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackField; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureTransportAction; + +public class SqlInfoTransportAction extends XPackInfoFeatureTransportAction { + + private final boolean enabled; + private final XPackLicenseState licenseState; + + @Inject + public SqlInfoTransportAction(TransportService transportService, ActionFilters actionFilters, + Settings settings, XPackLicenseState licenseState) { + super(XPackInfoFeatureAction.SQL.name(), transportService, actionFilters); + this.enabled = XPackSettings.SQL_ENABLED.get(settings); + this.licenseState = licenseState; + } + + @Override + public String name() { + return XPackField.SQL; + } + + @Override + public boolean available() { + return licenseState.isSqlAllowed(); + } + + @Override + public boolean enabled() { + return enabled; + } + +} diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/SqlUsageTransportAction.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/SqlUsageTransportAction.java new file mode 100644 index 0000000000000..561d1ab2cdb8b --- /dev/null +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/SqlUsageTransportAction.java @@ -0,0 +1,72 @@ +/* + * 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.xpack.sql; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.client.Client; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.protocol.xpack.XPackUsageRequest; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; +import org.elasticsearch.xpack.core.sql.SqlFeatureSetUsage; +import org.elasticsearch.xpack.core.watcher.common.stats.Counters; +import org.elasticsearch.xpack.sql.plugin.SqlStatsAction; +import org.elasticsearch.xpack.sql.plugin.SqlStatsRequest; +import org.elasticsearch.xpack.sql.plugin.SqlStatsResponse; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public class SqlUsageTransportAction extends XPackUsageFeatureTransportAction { + private final boolean enabled; + private final XPackLicenseState licenseState; + private final Client client; + + @Inject + public SqlUsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, + ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, + Settings settings, XPackLicenseState licenseState, Client client) { + super(XPackUsageFeatureAction.SQL.name(), transportService, clusterService, threadPool, actionFilters, + indexNameExpressionResolver); + this.enabled = XPackSettings.SQL_ENABLED.get(settings); + this.licenseState = licenseState; + this.client = client; + } + + @Override + protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { + boolean available = licenseState.isSqlAllowed(); + if (enabled) { + SqlStatsRequest sqlRequest = new SqlStatsRequest(); + sqlRequest.includeStats(true); + client.execute(SqlStatsAction.INSTANCE, sqlRequest, ActionListener.wrap(r -> { + List countersPerNode = r.getNodes() + .stream() + .map(SqlStatsResponse.NodeStatsResponse::getStats) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + Counters mergedCounters = Counters.merge(countersPerNode); + SqlFeatureSetUsage usage = new SqlFeatureSetUsage(available, enabled, mergedCounters.toNestedMap()); + listener.onResponse(new XPackUsageFeatureResponse(usage)); + }, listener::onFailure)); + } else { + SqlFeatureSetUsage usage = new SqlFeatureSetUsage(available, enabled, Collections.emptyMap()); + listener.onResponse(new XPackUsageFeatureResponse(usage)); + } + } +} diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plugin/SqlPlugin.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plugin/SqlPlugin.java index 47f53784afe10..28c482adfccf2 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plugin/SqlPlugin.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plugin/SqlPlugin.java @@ -11,7 +11,6 @@ import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.service.ClusterService; -import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.IndexScopedSettings; @@ -32,22 +31,22 @@ import org.elasticsearch.xpack.core.XPackField; import org.elasticsearch.xpack.core.XPackPlugin; import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; -import org.elasticsearch.xpack.sql.SqlFeatureSet; +import org.elasticsearch.xpack.sql.SqlInfoTransportAction; +import org.elasticsearch.xpack.sql.SqlUsageTransportAction; import org.elasticsearch.xpack.sql.action.SqlClearCursorAction; import org.elasticsearch.xpack.sql.action.SqlQueryAction; import org.elasticsearch.xpack.sql.action.SqlTranslateAction; import org.elasticsearch.xpack.sql.analysis.index.IndexResolver; import org.elasticsearch.xpack.sql.execution.PlanExecutor; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.function.Supplier; import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; public class SqlPlugin extends Plugin implements ActionPlugin { @@ -105,13 +104,6 @@ Collection createComponents(Client client, String clusterName, NamedWrit return Arrays.asList(sqlLicenseChecker, indexResolver, new PlanExecutor(client, indexResolver, namedWriteableRegistry)); } - @Override - public Collection createGuiceModules() { - List modules = new ArrayList<>(); - modules.add(b -> XPackPlugin.bindFeatureSet(b, SqlFeatureSet.class)); - return modules; - } - @Override public List getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings, IndexScopedSettings indexScopedSettings, @@ -130,15 +122,17 @@ public List getRestHandlers(Settings settings, RestController restC @Override public List> getActions() { - var usageAction = new ActionHandler<>(XPackUsageFeatureAction.SQL, SqlFeatureSet.UsageTransportAction.class); + var usageAction = new ActionHandler<>(XPackUsageFeatureAction.SQL, SqlUsageTransportAction.class); + var infoAction = new ActionHandler<>(XPackInfoFeatureAction.SQL, SqlInfoTransportAction.class); if (false == enabled) { - return singletonList(usageAction); + return Arrays.asList(usageAction, infoAction); } return Arrays.asList(new ActionHandler<>(SqlQueryAction.INSTANCE, TransportSqlQueryAction.class), new ActionHandler<>(SqlTranslateAction.INSTANCE, TransportSqlTranslateAction.class), new ActionHandler<>(SqlClearCursorAction.INSTANCE, TransportSqlClearCursorAction.class), new ActionHandler<>(SqlStatsAction.INSTANCE, TransportSqlStatsAction.class), - usageAction); + usageAction, + infoAction); } } diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/SqlFeatureSetTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/SqlInfoTransportActionTests.java similarity index 90% rename from x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/SqlFeatureSetTests.java rename to x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/SqlInfoTransportActionTests.java index d5d78453ef059..916ffcf6e3969 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/SqlFeatureSetTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/SqlInfoTransportActionTests.java @@ -38,7 +38,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class SqlFeatureSetTests extends ESTestCase { +public class SqlInfoTransportActionTests extends ESTestCase { private XPackLicenseState licenseState; private Client client; @@ -54,7 +54,8 @@ public void init() throws Exception { } public void testAvailable() { - SqlFeatureSet featureSet = new SqlFeatureSet(Settings.EMPTY, licenseState, client); + SqlInfoTransportAction featureSet = new SqlInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, licenseState); boolean available = randomBoolean(); when(licenseState.isSqlAllowed()).thenReturn(available); assertThat(featureSet.available(), is(available)); @@ -70,7 +71,8 @@ public void testEnabled() { } else { settings.put("xpack.sql.enabled", enabled); } - SqlFeatureSet featureSet = new SqlFeatureSet(settings.build(), licenseState, client); + SqlInfoTransportAction featureSet = new SqlInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), settings.build(), licenseState); assertThat(featureSet.enabled(), is(enabled)); } @@ -101,7 +103,7 @@ public void testUsageStats() throws Exception { return null; }).when(client).execute(eq(SqlStatsAction.INSTANCE), any(), any()); - var usageAction = new SqlFeatureSet.UsageTransportAction(mock(TransportService.class), null, null, + var usageAction = new SqlUsageTransportAction(mock(TransportService.class), null, null, mock(ActionFilters.class), null, Settings.EMPTY, licenseState, client); PlainActionFuture future = new PlainActionFuture<>(); usageAction.masterOperation(null, null, future); diff --git a/x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/Vectors.java b/x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/Vectors.java index d6a55e831ff1d..6e714984077ca 100644 --- a/x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/Vectors.java +++ b/x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/Vectors.java @@ -8,19 +8,18 @@ import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionResponse; -import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.mapper.Mapper; import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.plugins.MapperPlugin; import org.elasticsearch.plugins.Plugin; -import org.elasticsearch.xpack.core.XPackPlugin; import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; import org.elasticsearch.xpack.vectors.mapper.DenseVectorFieldMapper; import org.elasticsearch.xpack.vectors.mapper.SparseVectorFieldMapper; -import java.util.Collection; +import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -30,23 +29,17 @@ public class Vectors extends Plugin implements MapperPlugin, ActionPlugin { - public static final String NAME = "vectors"; protected final boolean enabled; public Vectors(Settings settings) { this.enabled = XPackSettings.VECTORS_ENABLED.get(settings); } - public Collection createGuiceModules() { - return Collections.singletonList(b -> { - XPackPlugin.bindFeatureSet(b, VectorsFeatureSet.class); - }); - } - @Override public List> getActions() { - return Collections.singletonList( - new ActionPlugin.ActionHandler<>(XPackUsageFeatureAction.VECTORS, VectorsFeatureSet.UsageTransportAction.class)); + return Arrays.asList( + new ActionPlugin.ActionHandler<>(XPackUsageFeatureAction.VECTORS, VectorsUsageTransportAction.class), + new ActionPlugin.ActionHandler<>(XPackInfoFeatureAction.VECTORS, VectorsInfoTransportAction.class)); } @Override diff --git a/x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/VectorsFeatureSet.java b/x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/VectorsFeatureSet.java deleted file mode 100644 index a94bd6529e87e..0000000000000 --- a/x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/VectorsFeatureSet.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.xpack.vectors; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.action.support.ActionFilters; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; -import org.elasticsearch.cluster.service.ClusterService; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.license.XPackLicenseState; -import org.elasticsearch.protocol.xpack.XPackUsageRequest; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.TransportService; -import org.elasticsearch.xpack.core.XPackFeatureSet; -import org.elasticsearch.xpack.core.XPackField; -import org.elasticsearch.xpack.core.XPackSettings; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; -import org.elasticsearch.xpack.core.vectors.VectorsFeatureSetUsage; - -public class VectorsFeatureSet implements XPackFeatureSet { - - private final boolean enabled; - private final XPackLicenseState licenseState; - - @Inject - public VectorsFeatureSet(Settings settings, XPackLicenseState licenseState) { - this.enabled = XPackSettings.VECTORS_ENABLED.get(settings); - this.licenseState = licenseState; - } - - @Override - public String name() { - return XPackField.VECTORS; - } - - @Override - public boolean available() { - return licenseState != null && licenseState.isVectorsAllowed(); - } - - @Override - public boolean enabled() { - return enabled; - } - - public static class UsageTransportAction extends XPackUsageFeatureTransportAction { - - private final Settings settings; - private final XPackLicenseState licenseState; - - @Inject - public UsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, - ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, - Settings settings, XPackLicenseState licenseState) { - super(XPackUsageFeatureAction.VECTORS.name(), transportService, clusterService, - threadPool, actionFilters, indexNameExpressionResolver); - this.settings = settings; - this.licenseState = licenseState; - } - - @Override - protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { - VectorsFeatureSetUsage usage = - new VectorsFeatureSetUsage(licenseState.isVectorsAllowed(), XPackSettings.VECTORS_ENABLED.get(settings)); - listener.onResponse(new XPackUsageFeatureResponse(usage)); - } - } -} diff --git a/x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/VectorsInfoTransportAction.java b/x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/VectorsInfoTransportAction.java new file mode 100644 index 0000000000000..7974b6ec246f3 --- /dev/null +++ b/x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/VectorsInfoTransportAction.java @@ -0,0 +1,46 @@ +/* + * 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.xpack.vectors; + +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackField; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureTransportAction; + +public class VectorsInfoTransportAction extends XPackInfoFeatureTransportAction { + + private final boolean enabled; + private final XPackLicenseState licenseState; + + @Inject + public VectorsInfoTransportAction(TransportService transportService, ActionFilters actionFilters, + Settings settings, XPackLicenseState licenseState) { + super(XPackInfoFeatureAction.VECTORS.name(), transportService, actionFilters); + this.enabled = XPackSettings.VECTORS_ENABLED.get(settings); + this.licenseState = licenseState; + } + + @Override + public String name() { + return XPackField.VECTORS; + } + + @Override + public boolean available() { + return licenseState.isVectorsAllowed(); + } + + @Override + public boolean enabled() { + return enabled; + } + +} diff --git a/x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/VectorsUsageTransportAction.java b/x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/VectorsUsageTransportAction.java new file mode 100644 index 0000000000000..973dfa29d247e --- /dev/null +++ b/x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/VectorsUsageTransportAction.java @@ -0,0 +1,46 @@ +/* + * 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.xpack.vectors; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.protocol.xpack.XPackUsageRequest; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; +import org.elasticsearch.xpack.core.vectors.VectorsFeatureSetUsage; + +public class VectorsUsageTransportAction extends XPackUsageFeatureTransportAction { + + private final Settings settings; + private final XPackLicenseState licenseState; + + @Inject + public VectorsUsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, + ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, + Settings settings, XPackLicenseState licenseState) { + super(XPackUsageFeatureAction.VECTORS.name(), transportService, clusterService, + threadPool, actionFilters, indexNameExpressionResolver); + this.settings = settings; + this.licenseState = licenseState; + } + + @Override + protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { + VectorsFeatureSetUsage usage = + new VectorsFeatureSetUsage(licenseState.isVectorsAllowed(), XPackSettings.VECTORS_ENABLED.get(settings)); + listener.onResponse(new XPackUsageFeatureResponse(usage)); + } +} diff --git a/x-pack/plugin/vectors/src/test/java/org/elasticsearch/xpack/vectors/VectorsFeatureSetTests.java b/x-pack/plugin/vectors/src/test/java/org/elasticsearch/xpack/vectors/VectorsInfoTransportActionTests.java similarity index 82% rename from x-pack/plugin/vectors/src/test/java/org/elasticsearch/xpack/vectors/VectorsFeatureSetTests.java rename to x-pack/plugin/vectors/src/test/java/org/elasticsearch/xpack/vectors/VectorsInfoTransportActionTests.java index 318c0195a68aa..fd4b3c253cd1e 100644 --- a/x-pack/plugin/vectors/src/test/java/org/elasticsearch/xpack/vectors/VectorsFeatureSetTests.java +++ b/x-pack/plugin/vectors/src/test/java/org/elasticsearch/xpack/vectors/VectorsInfoTransportActionTests.java @@ -21,7 +21,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class VectorsFeatureSetTests extends ESTestCase { +public class VectorsInfoTransportActionTests extends ESTestCase { private XPackLicenseState licenseState; @@ -31,12 +31,13 @@ public void init() { } public void testAvailable() throws Exception { - VectorsFeatureSet featureSet = new VectorsFeatureSet(Settings.EMPTY, licenseState); + VectorsInfoTransportAction featureSet = new VectorsInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, licenseState); boolean available = randomBoolean(); when(licenseState.isVectorsAllowed()).thenReturn(available); assertThat(featureSet.available(), is(available)); - var usageAction = new VectorsFeatureSet.UsageTransportAction(mock(TransportService.class), null, null, + var usageAction = new VectorsUsageTransportAction(mock(TransportService.class), null, null, mock(ActionFilters.class), null, Settings.EMPTY, licenseState); PlainActionFuture future = new PlainActionFuture<>(); usageAction.masterOperation(null, null, future); @@ -59,10 +60,11 @@ public void testEnabled() throws Exception { } else { settings.put("xpack.vectors.enabled", enabled); } - VectorsFeatureSet featureSet = new VectorsFeatureSet(settings.build(), licenseState); + VectorsInfoTransportAction featureSet = new VectorsInfoTransportAction( +mock(TransportService.class), mock(ActionFilters.class), settings.build(), licenseState); assertThat(featureSet.enabled(), is(enabled)); - VectorsFeatureSet.UsageTransportAction usageAction = new VectorsFeatureSet.UsageTransportAction(mock(TransportService.class), + VectorsUsageTransportAction usageAction = new VectorsUsageTransportAction(mock(TransportService.class), null, null, mock(ActionFilters.class), null, settings.build(), licenseState); PlainActionFuture future = new PlainActionFuture<>(); usageAction.masterOperation(null, null, future); diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/Watcher.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/Watcher.java index 959fad3f7d08d..64799a4c57d65 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/Watcher.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/Watcher.java @@ -58,6 +58,7 @@ import org.elasticsearch.xpack.core.ClientHelper; import org.elasticsearch.xpack.core.XPackPlugin; import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; import org.elasticsearch.xpack.core.ssl.SSLService; import org.elasticsearch.xpack.core.watcher.WatcherField; @@ -195,7 +196,6 @@ import java.util.stream.Collectors; import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; import static org.elasticsearch.common.settings.Setting.Property.NodeScope; import static org.elasticsearch.xpack.core.ClientHelper.WATCHER_ORIGIN; @@ -432,7 +432,6 @@ public Collection createGuiceModules() { List modules = new ArrayList<>(); modules.add(b -> b.bind(Clock.class).toInstance(getClock())); //currently assuming the only place clock is bound modules.add(b -> { - XPackPlugin.bindFeatureSet(b, WatcherFeatureSet.class); if (enabled == false) { b.bind(WatcherService.class).toProvider(Providers.of(null)); } @@ -534,9 +533,10 @@ static int getWatcherThreadPoolSize(Settings settings) { @Override public List> getActions() { - var usageAction = new ActionHandler<>(XPackUsageFeatureAction.WATCHER, WatcherFeatureSet.UsageTransportAction.class); + var usageAction = new ActionHandler<>(XPackUsageFeatureAction.WATCHER, WatcherUsageTransportAction.class); + var infoAction = new ActionHandler<>(XPackInfoFeatureAction.WATCHER, WatcherInfoTransportAction.class); if (false == enabled) { - return singletonList(usageAction); + return Arrays.asList(usageAction, infoAction); } return Arrays.asList(new ActionHandler<>(PutWatchAction.INSTANCE, TransportPutWatchAction.class), new ActionHandler<>(DeleteWatchAction.INSTANCE, TransportDeleteWatchAction.class), @@ -546,7 +546,8 @@ static int getWatcherThreadPoolSize(Settings settings) { new ActionHandler<>(ActivateWatchAction.INSTANCE, TransportActivateWatchAction.class), new ActionHandler<>(WatcherServiceAction.INSTANCE, TransportWatcherServiceAction.class), new ActionHandler<>(ExecuteWatchAction.INSTANCE, TransportExecuteWatchAction.class), - usageAction); + usageAction, + infoAction); } @Override diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherFeatureSet.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherFeatureSet.java deleted file mode 100644 index e52d0537f8881..0000000000000 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherFeatureSet.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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.xpack.watcher; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.action.support.ActionFilters; -import org.elasticsearch.client.Client; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; -import org.elasticsearch.cluster.service.ClusterService; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.util.concurrent.ThreadContext; -import org.elasticsearch.license.XPackLicenseState; -import org.elasticsearch.protocol.xpack.XPackUsageRequest; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.TransportService; -import org.elasticsearch.xpack.core.XPackFeatureSet; -import org.elasticsearch.xpack.core.XPackField; -import org.elasticsearch.xpack.core.XPackSettings; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; -import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; -import org.elasticsearch.xpack.core.watcher.WatcherFeatureSetUsage; -import org.elasticsearch.xpack.core.watcher.common.stats.Counters; -import org.elasticsearch.xpack.core.watcher.transport.actions.stats.WatcherStatsAction; -import org.elasticsearch.xpack.core.watcher.transport.actions.stats.WatcherStatsRequest; -import org.elasticsearch.xpack.core.watcher.transport.actions.stats.WatcherStatsResponse; - -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -import static org.elasticsearch.xpack.core.ClientHelper.WATCHER_ORIGIN; - -public class WatcherFeatureSet implements XPackFeatureSet { - - private final boolean enabled; - private final XPackLicenseState licenseState; - - @Inject - public WatcherFeatureSet(Settings settings, XPackLicenseState licenseState) { - this.enabled = XPackSettings.WATCHER_ENABLED.get(settings); - this.licenseState = licenseState; - } - - @Override - public String name() { - return XPackField.WATCHER; - } - - @Override - public boolean available() { - return licenseState != null && licenseState.isWatcherAllowed(); - } - - @Override - public boolean enabled() { - return enabled; - } - - public static class UsageTransportAction extends XPackUsageFeatureTransportAction { - private final boolean enabled; - private final XPackLicenseState licenseState; - private final Client client; - - @Inject - public UsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, - ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, - Settings settings, XPackLicenseState licenseState, Client client) { - super(XPackUsageFeatureAction.WATCHER.name(), transportService, clusterService, threadPool, actionFilters, - indexNameExpressionResolver); - this.enabled = XPackSettings.WATCHER_ENABLED.get(settings); - this.licenseState = licenseState; - this.client = client; - } - - @Override - protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { - if (enabled) { - try (ThreadContext.StoredContext ignore = - client.threadPool().getThreadContext().stashWithOrigin(WATCHER_ORIGIN)) { - WatcherStatsRequest statsRequest = new WatcherStatsRequest(); - statsRequest.includeStats(true); - client.execute(WatcherStatsAction.INSTANCE, statsRequest, ActionListener.wrap(r -> { - List countersPerNode = r.getNodes() - .stream() - .map(WatcherStatsResponse.Node::getStats) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - Counters mergedCounters = Counters.merge(countersPerNode); - WatcherFeatureSetUsage usage = - new WatcherFeatureSetUsage(licenseState.isWatcherAllowed(), true, mergedCounters.toNestedMap()); - listener.onResponse(new XPackUsageFeatureResponse(usage)); - }, listener::onFailure)); - } - } else { - WatcherFeatureSetUsage usage = - new WatcherFeatureSetUsage(licenseState.isWatcherAllowed(), false, Collections.emptyMap()); - listener.onResponse(new XPackUsageFeatureResponse(usage)); - } - } - } -} diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherInfoTransportAction.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherInfoTransportAction.java new file mode 100644 index 0000000000000..63f071e7d1e50 --- /dev/null +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherInfoTransportAction.java @@ -0,0 +1,46 @@ +/* + * 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.xpack.watcher; + +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackField; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureTransportAction; + +public class WatcherInfoTransportAction extends XPackInfoFeatureTransportAction { + + private final boolean enabled; + private final XPackLicenseState licenseState; + + @Inject + public WatcherInfoTransportAction(TransportService transportService, ActionFilters actionFilters, + Settings settings, XPackLicenseState licenseState) { + super(XPackInfoFeatureAction.WATCHER.name(), transportService, actionFilters); + this.enabled = XPackSettings.WATCHER_ENABLED.get(settings); + this.licenseState = licenseState; + } + + @Override + public String name() { + return XPackField.WATCHER; + } + + @Override + public boolean available() { + return licenseState.isWatcherAllowed(); + } + + @Override + public boolean enabled() { + return enabled; + } + +} diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherUsageTransportAction.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherUsageTransportAction.java new file mode 100644 index 0000000000000..667692bd98c7d --- /dev/null +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherUsageTransportAction.java @@ -0,0 +1,79 @@ +/* + * 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.xpack.watcher; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.client.Client; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.protocol.xpack.XPackUsageRequest; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse; +import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction; +import org.elasticsearch.xpack.core.watcher.WatcherFeatureSetUsage; +import org.elasticsearch.xpack.core.watcher.common.stats.Counters; +import org.elasticsearch.xpack.core.watcher.transport.actions.stats.WatcherStatsAction; +import org.elasticsearch.xpack.core.watcher.transport.actions.stats.WatcherStatsRequest; +import org.elasticsearch.xpack.core.watcher.transport.actions.stats.WatcherStatsResponse; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.elasticsearch.xpack.core.ClientHelper.WATCHER_ORIGIN; + +public class WatcherUsageTransportAction extends XPackUsageFeatureTransportAction { + private final boolean enabled; + private final XPackLicenseState licenseState; + private final Client client; + + @Inject + public WatcherUsageTransportAction(TransportService transportService, ClusterService clusterService, ThreadPool threadPool, + ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, + Settings settings, XPackLicenseState licenseState, Client client) { + super(XPackUsageFeatureAction.WATCHER.name(), transportService, clusterService, threadPool, actionFilters, + indexNameExpressionResolver); + this.enabled = XPackSettings.WATCHER_ENABLED.get(settings); + this.licenseState = licenseState; + this.client = client; + } + + @Override + protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { + if (enabled) { + try (ThreadContext.StoredContext ignore = + client.threadPool().getThreadContext().stashWithOrigin(WATCHER_ORIGIN)) { + WatcherStatsRequest statsRequest = new WatcherStatsRequest(); + statsRequest.includeStats(true); + client.execute(WatcherStatsAction.INSTANCE, statsRequest, ActionListener.wrap(r -> { + List countersPerNode = r.getNodes() + .stream() + .map(WatcherStatsResponse.Node::getStats) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + Counters mergedCounters = Counters.merge(countersPerNode); + WatcherFeatureSetUsage usage = + new WatcherFeatureSetUsage(licenseState.isWatcherAllowed(), true, mergedCounters.toNestedMap()); + listener.onResponse(new XPackUsageFeatureResponse(usage)); + }, listener::onFailure)); + } + } else { + WatcherFeatureSetUsage usage = + new WatcherFeatureSetUsage(licenseState.isWatcherAllowed(), false, Collections.emptyMap()); + listener.onResponse(new XPackUsageFeatureResponse(usage)); + } + } +} diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherFeatureSetTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherInfoTransportActionTests.java similarity index 92% rename from x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherFeatureSetTests.java rename to x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherInfoTransportActionTests.java index d654bc6bfabd0..a64d9d60a8920 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherFeatureSetTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherInfoTransportActionTests.java @@ -47,7 +47,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class WatcherFeatureSetTests extends ESTestCase { +public class WatcherInfoTransportActionTests extends ESTestCase { private XPackLicenseState licenseState; private Client client; @@ -63,7 +63,8 @@ public void init() throws Exception { } public void testAvailable() { - WatcherFeatureSet featureSet = new WatcherFeatureSet(Settings.EMPTY, licenseState); + WatcherInfoTransportAction featureSet = new WatcherInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, licenseState); boolean available = randomBoolean(); when(licenseState.isWatcherAllowed()).thenReturn(available); assertThat(featureSet.available(), is(available)); @@ -79,7 +80,8 @@ public void testEnabled() { } else { settings.put("xpack.watcher.enabled", enabled); } - WatcherFeatureSet featureSet = new WatcherFeatureSet(settings.build(), licenseState); + WatcherInfoTransportAction featureSet = new WatcherInfoTransportAction( + mock(TransportService.class), mock(ActionFilters.class), settings.build(), licenseState); assertThat(featureSet.enabled(), is(enabled)); } @@ -110,7 +112,7 @@ public void testUsageStats() throws Exception { return null; }).when(client).execute(eq(WatcherStatsAction.INSTANCE), any(), any()); - var usageAction = new WatcherFeatureSet.UsageTransportAction(mock(TransportService.class), null, null, + var usageAction = new WatcherUsageTransportAction(mock(TransportService.class), null, null, mock(ActionFilters.class), null, Settings.EMPTY, licenseState, client); PlainActionFuture future = new PlainActionFuture<>(); usageAction.masterOperation(null, null, future); From d1afd8a11611fa0102967d0891427cfacde773ff Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Thu, 20 Jun 2019 11:57:40 -0700 Subject: [PATCH 02/12] fix javadoc --- .../xpack/core/action/XPackInfoFeatureAction.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureAction.java index 8c7ee957bd5bc..170ab11c16ee2 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureAction.java @@ -12,11 +12,11 @@ import java.util.List; /** - * A base action for for usage of a feature plugin. + * A base action for info about a feature plugin. * * This action is implemented by each feature plugin, bound to the public constants here. The - * {@link XPackUsageAction} implementationn iterates over the {@link #ALL} list of actions to form - * the complete usage result. + * {@link XPackInfoAction} implementation iterates over the {@link #ALL} list of actions to form + * the complete info result. */ public class XPackInfoFeatureAction extends Action { From 00037820518710b82238e4370d1477f4ddd07fef Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Thu, 20 Jun 2019 12:04:03 -0700 Subject: [PATCH 03/12] fix dataframe info action registration --- .../main/java/org/elasticsearch/xpack/dataframe/DataFrame.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrame.java b/x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrame.java index 3828f15b34995..d5d3ecab5b0f5 100644 --- a/x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrame.java +++ b/x-pack/plugin/data-frame/src/main/java/org/elasticsearch/xpack/dataframe/DataFrame.java @@ -39,6 +39,7 @@ import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.xpack.core.XPackPlugin; import org.elasticsearch.xpack.core.XPackSettings; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; import org.elasticsearch.xpack.core.dataframe.action.DeleteDataFrameTransformAction; import org.elasticsearch.xpack.core.dataframe.action.GetDataFrameTransformsAction; @@ -126,7 +127,7 @@ public List getRestHandlers(final Settings settings, final RestCont @Override public List> getActions() { var usageAction = new ActionHandler<>(XPackUsageFeatureAction.DATA_FRAME, DataFrameUsageTransportAction.class); - var infoAction = new ActionHandler<>(XPackUsageFeatureAction.DATA_FRAME, DataFrameUsageTransportAction.class); + var infoAction = new ActionHandler<>(XPackInfoFeatureAction.DATA_FRAME, DataFrameInfoTransportAction.class); if (enabled == false) { return Arrays.asList(usageAction, infoAction); } From c7fa06f553cfe7c61c2d50fa844cfaa9b25c7c92 Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Fri, 21 Jun 2019 11:30:22 -0700 Subject: [PATCH 04/12] rework subactions iteration --- .../core/action/TransportXPackInfoAction.java | 35 ++++++------------- .../action/TransportXPackInfoActionTests.java | 18 +++++++++- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackInfoAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackInfoAction.java index 00a81051a6478..91d2e97bf0ad6 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackInfoAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackInfoAction.java @@ -14,17 +14,15 @@ import org.elasticsearch.license.LicenseService; import org.elasticsearch.protocol.xpack.XPackInfoRequest; import org.elasticsearch.protocol.xpack.XPackInfoResponse; +import org.elasticsearch.protocol.xpack.XPackInfoResponse.FeatureSetsInfo; import org.elasticsearch.protocol.xpack.XPackInfoResponse.FeatureSetsInfo.FeatureSet; import org.elasticsearch.protocol.xpack.XPackInfoResponse.LicenseInfo; import org.elasticsearch.tasks.Task; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; import org.elasticsearch.xpack.core.XPackBuild; -import org.elasticsearch.xpack.core.common.IteratingActionListener; import java.util.HashSet; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReferenceArray; public class TransportXPackInfoAction extends HandledTransportAction { @@ -60,28 +58,17 @@ protected void doExecute(Task task, XPackInfoRequest request, ActionListener(XPackInfoFeatureAction.ALL.size()); - final XPackInfoResponse.BuildInfo finalBuildInfo = buildInfo; - final LicenseInfo finalLicenseInfo = licenseInfo; - - ActionListener finalListener = ActionListener.wrap(ignore -> { - var featureSetsSet = new HashSet(featureSets.length()); - for (int i = 0; i < featureSets.length(); i++) { - featureSetsSet.add(featureSets.get(i)); - } - var featureSetsInfo = new XPackInfoResponse.FeatureSetsInfo(featureSetsSet); - listener.onResponse(new XPackInfoResponse(finalBuildInfo, finalLicenseInfo, featureSetsInfo)); - }, listener::onFailure); - - new IteratingActionListener<>(finalListener, (infoAction, iteratingListener) -> - client.executeLocally(infoAction, request, ActionListener.wrap(response -> - featureSets.set(position.getAndIncrement(), response.getInfo()), iteratingListener::onFailure)), - XPackInfoFeatureAction.ALL, - threadPool.getThreadContext()).run(); - } else { - listener.onResponse(new XPackInfoResponse(buildInfo, licenseInfo, null)); + var featureSets = new HashSet(); + for (var infoAction : XPackInfoFeatureAction.ALL) { + // local actions are executed directly, not on a separate thread, so no thread safe collection is necessary + client.executeLocally(infoAction, request, + ActionListener.wrap(response -> featureSets.add(response.getInfo()), listener::onFailure)); + } + featureSetsInfo = new FeatureSetsInfo(featureSets); } + + listener.onResponse(new XPackInfoResponse(buildInfo, licenseInfo, featureSetsInfo)); } } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/action/TransportXPackInfoActionTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/action/TransportXPackInfoActionTests.java index 09fc9c94c2353..bc1e14ba3a41a 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/action/TransportXPackInfoActionTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/action/TransportXPackInfoActionTests.java @@ -17,9 +17,13 @@ import org.elasticsearch.protocol.xpack.license.LicenseStatus; import org.elasticsearch.tasks.Task; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.threadpool.TestThreadPool; +import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.Transport; import org.elasticsearch.transport.TransportService; import org.elasticsearch.xpack.core.XPackFeatureSet; +import org.junit.After; +import org.junit.Before; import java.util.Collections; import java.util.EnumSet; @@ -40,6 +44,17 @@ import static org.mockito.Mockito.when; public class TransportXPackInfoActionTests extends ESTestCase { + private ThreadPool threadPool; + + @Before + public void setupThreadpool() { + threadPool = new TestThreadPool("test"); + } + + @After + public void cleanupThreadpool() { + threadPool.close(); + } public void testDoExecute() throws Exception { @@ -58,7 +73,7 @@ public void testDoExecute() throws Exception { TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null, TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet()); TransportXPackInfoAction action = new TransportXPackInfoAction(transportService, mock(ActionFilters.class), - licenseService, mock(NodeClient.class), null); + licenseService, mock(NodeClient.class), threadPool); License license = mock(License.class); long expiryDate = randomLong(); @@ -81,6 +96,7 @@ public void testDoExecute() throws Exception { for (int i = 0; i < maxCategoryCount; i++) { categories.add(randomFrom(XPackInfoRequest.Category.values())); } + categories.add(XPackInfoRequest.Category.FEATURES); request.setCategories(categories); final CountDownLatch latch = new CountDownLatch(1); From 248892cadb20577dd2863eb4fc7993b7f2bf4e2f Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Fri, 21 Jun 2019 12:20:25 -0700 Subject: [PATCH 05/12] fix unit test --- .../core/action/TransportXPackInfoAction.java | 15 +++-- .../action/TransportXPackInfoActionTests.java | 59 ++++++++----------- 2 files changed, 36 insertions(+), 38 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackInfoAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackInfoAction.java index 91d2e97bf0ad6..d252cec4b6afd 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackInfoAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackInfoAction.java @@ -18,26 +18,31 @@ import org.elasticsearch.protocol.xpack.XPackInfoResponse.FeatureSetsInfo.FeatureSet; import org.elasticsearch.protocol.xpack.XPackInfoResponse.LicenseInfo; import org.elasticsearch.tasks.Task; -import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; import org.elasticsearch.xpack.core.XPackBuild; import java.util.HashSet; +import java.util.List; public class TransportXPackInfoAction extends HandledTransportAction { private final LicenseService licenseService; private final NodeClient client; - private final ThreadPool threadPool; + private final List infoActions; @Inject public TransportXPackInfoAction(TransportService transportService, ActionFilters actionFilters, LicenseService licenseService, - NodeClient client, ThreadPool threadPool) { + NodeClient client) { super(XPackInfoAction.NAME, transportService, actionFilters, XPackInfoRequest::new); this.licenseService = licenseService; this.client = client; - this.threadPool = threadPool; + this.infoActions = infoActions(); + } + + // overrideable for tests + protected List infoActions() { + return XPackInfoFeatureAction.ALL; } @Override @@ -61,7 +66,7 @@ protected void doExecute(Task task, XPackInfoRequest request, ActionListener(); - for (var infoAction : XPackInfoFeatureAction.ALL) { + for (var infoAction : infoActions) { // local actions are executed directly, not on a separate thread, so no thread safe collection is necessary client.executeLocally(infoAction, request, ActionListener.wrap(response -> featureSets.add(response.getInfo()), listener::onFailure)); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/action/TransportXPackInfoActionTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/action/TransportXPackInfoActionTests.java index bc1e14ba3a41a..a5f27f73ab3d7 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/action/TransportXPackInfoActionTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/action/TransportXPackInfoActionTests.java @@ -6,9 +6,9 @@ package org.elasticsearch.xpack.core.action; import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.support.ActionFilters; import org.elasticsearch.client.node.NodeClient; -import org.elasticsearch.common.settings.Settings; import org.elasticsearch.license.License; import org.elasticsearch.license.LicenseService; import org.elasticsearch.protocol.xpack.XPackInfoRequest; @@ -17,20 +17,14 @@ import org.elasticsearch.protocol.xpack.license.LicenseStatus; import org.elasticsearch.tasks.Task; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.threadpool.TestThreadPool; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.Transport; import org.elasticsearch.transport.TransportService; -import org.elasticsearch.xpack.core.XPackFeatureSet; -import org.junit.After; -import org.junit.Before; -import java.util.Collections; +import java.util.ArrayList; import java.util.EnumSet; -import java.util.HashSet; +import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; @@ -40,40 +34,39 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.core.IsNull.notNullValue; import static org.hamcrest.core.IsNull.nullValue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.stub; import static org.mockito.Mockito.when; public class TransportXPackInfoActionTests extends ESTestCase { - private ThreadPool threadPool; - - @Before - public void setupThreadpool() { - threadPool = new TestThreadPool("test"); - } - - @After - public void cleanupThreadpool() { - threadPool.close(); - } public void testDoExecute() throws Exception { LicenseService licenseService = mock(LicenseService.class); - final Set featureSets = new HashSet<>(); + NodeClient client = mock(NodeClient.class); + Map featureSets = new HashMap<>(); int featureSetCount = randomIntBetween(0, 5); - for (int i = 0; i < featureSetCount; i++) { - XPackFeatureSet fs = mock(XPackFeatureSet.class); - when(fs.name()).thenReturn(randomAlphaOfLength(5)); - when(fs.available()).thenReturn(randomBoolean()); - when(fs.enabled()).thenReturn(randomBoolean()); - featureSets.add(fs); + for (XPackInfoFeatureAction infoAction : randomSubsetOf(featureSetCount, XPackInfoFeatureAction.ALL)) { + FeatureSet featureSet = new FeatureSet(randomAlphaOfLength(5), randomBoolean(), randomBoolean()); + featureSets.put(infoAction, featureSet); + stub(client.executeLocally(eq(infoAction), any(ActionRequest.class), any(ActionListener.class))).toAnswer(answer -> { + @SuppressWarnings("unchecked") + var listener = (ActionListener)answer.getArguments()[2]; + listener.onResponse(new XPackInfoFeatureResponse(featureSet)); + return null; + }); } - TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null, - TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet()); - TransportXPackInfoAction action = new TransportXPackInfoAction(transportService, mock(ActionFilters.class), - licenseService, mock(NodeClient.class), threadPool); + TransportXPackInfoAction action = new TransportXPackInfoAction(mock(TransportService.class), mock(ActionFilters.class), + licenseService, client) { + @Override + protected List infoActions() { + return new ArrayList<>(featureSets.keySet()); + } + }; License license = mock(License.class); long expiryDate = randomLong(); @@ -144,7 +137,7 @@ public void onFailure(Exception e) { assertThat(response.get().getFeatureSetsInfo(), notNullValue()); Map features = response.get().getFeatureSetsInfo().getFeatureSets(); assertThat(features.size(), is(featureSets.size())); - for (XPackFeatureSet fs : featureSets) { + for (FeatureSet fs : featureSets.values()) { assertThat(features, hasKey(fs.name())); assertThat(features.get(fs.name()).name(), equalTo(fs.name())); assertThat(features.get(fs.name()).available(), equalTo(fs.available())); From 28ad7afd599c5e7dfcda3680759eda504e86e803 Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Fri, 21 Jun 2019 12:22:41 -0700 Subject: [PATCH 06/12] add javadoc --- .../xpack/core/action/XPackInfoFeatureTransportAction.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureTransportAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureTransportAction.java index f352240783534..672128a2fd8be 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureTransportAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureTransportAction.java @@ -13,6 +13,12 @@ import org.elasticsearch.tasks.Task; import org.elasticsearch.transport.TransportService; +/** + * A base class to implement {@link XPackInfoFeatureAction} actions. + * + * Extend this class and implement the abstract methods, and register the appropriate + * {@link XPackInfoFeatureAction} to the subclass of this class. + */ public abstract class XPackInfoFeatureTransportAction extends HandledTransportAction { public XPackInfoFeatureTransportAction(String name, TransportService transportService, ActionFilters actionFilters) { From 5ea68edc99d2287130ab61668504e459d856685c Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Fri, 21 Jun 2019 12:23:12 -0700 Subject: [PATCH 07/12] fix accidental newline --- .../xpack/core/action/TransportXPackUsageAction.java | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackUsageAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackUsageAction.java index 02927c48e4ae6..42f14ee7cba2a 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackUsageAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportXPackUsageAction.java @@ -59,7 +59,6 @@ protected XPackUsageResponse newResponse() { } @Override - protected void masterOperation(XPackUsageRequest request, ClusterState state, ActionListener listener) { final ActionListener> usageActionListener = new ActionListener<>() { @Override From c0391fe974178e08f7f332aa81114cc4d464b47e Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Fri, 21 Jun 2019 16:53:03 -0700 Subject: [PATCH 08/12] don't pass null for license state --- .../elasticsearch/xpack/ccr/CCRInfoTransportActionTests.java | 4 ---- .../IndexLifecycleInfoTransportActionTests.java | 4 ---- 2 files changed, 8 deletions(-) diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRInfoTransportActionTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRInfoTransportActionTests.java index 80a2fb35c318a..542f720bc2a82 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRInfoTransportActionTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRInfoTransportActionTests.java @@ -52,10 +52,6 @@ public void testAvailable() { when(licenseState.isCcrAllowed()).thenReturn(true); assertThat(featureSet.available(), equalTo(true)); - - featureSet = new CCRInfoTransportAction( - mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, null); - assertThat(featureSet.available(), equalTo(false)); } public void testEnabled() { diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleInfoTransportActionTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleInfoTransportActionTests.java index 0e305fd6fffe1..914b902a85f6f 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleInfoTransportActionTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleInfoTransportActionTests.java @@ -62,10 +62,6 @@ public void testAvailable() { when(licenseState.isIndexLifecycleAllowed()).thenReturn(true); assertThat(featureSet.available(), equalTo(true)); - - featureSet = new IndexLifecycleInfoTransportAction( - mock(TransportService.class), mock(ActionFilters.class), Settings.EMPTY, null); - assertThat(featureSet.available(), equalTo(false)); } public void testEnabled() { From e289aeace2489fa8797f4cc47ba03f3762dcd461 Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Sat, 22 Jun 2019 08:46:54 -0700 Subject: [PATCH 09/12] fix watcher assertion --- .../org/elasticsearch/xpack/watcher/WatcherPluginTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherPluginTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherPluginTests.java index 50f0d9223c3c4..519228fe81bce 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherPluginTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherPluginTests.java @@ -68,7 +68,7 @@ public void testWatcherDisabledTests() throws Exception { List> executorBuilders = watcher.getExecutorBuilders(settings); assertThat(executorBuilders, hasSize(0)); assertThat(watcher.createGuiceModules(), hasSize(2)); - assertThat(watcher.getActions(), hasSize(1)); + assertThat(watcher.getActions(), hasSize(2)); assertThat(watcher.getRestHandlers(settings, null, null, null, null, null, null), hasSize(0)); // ensure index module is not called, even if watches index is tried From 63e396d6a4efb2063af6e105b8f6e5ca1b16a933 Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Sat, 22 Jun 2019 13:27:36 -0700 Subject: [PATCH 10/12] fix null actionfilters --- .../elasticsearch/xpack/ccr/CCRInfoTransportActionTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRInfoTransportActionTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRInfoTransportActionTests.java index 542f720bc2a82..f1d2898c237da 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRInfoTransportActionTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/CCRInfoTransportActionTests.java @@ -61,7 +61,7 @@ public void testEnabled() { assertThat(featureSet.enabled(), equalTo(false)); settings = Settings.builder().put("xpack.ccr.enabled", true); - featureSet = new CCRInfoTransportAction(mock(TransportService.class), null, settings.build(), licenseState); + featureSet = new CCRInfoTransportAction(mock(TransportService.class), mock(ActionFilters.class), settings.build(), licenseState); assertThat(featureSet.enabled(), equalTo(true)); } From 85afdf646c48fcdffb4dd36e1573f8b96eadd38a Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Sat, 22 Jun 2019 15:20:50 -0700 Subject: [PATCH 11/12] fix security test --- .../elasticsearch/xpack/core/XPackPlugin.java | 9 +++++++- .../xpack/security/LocalStateSecurity.java | 22 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java index 436802294e7f3..9632577b4fb47 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java @@ -47,6 +47,8 @@ import org.elasticsearch.plugins.EnginePlugin; import org.elasticsearch.plugins.ExtensiblePlugin; import org.elasticsearch.plugins.RepositoryPlugin; +import org.elasticsearch.protocol.xpack.XPackInfoRequest; +import org.elasticsearch.protocol.xpack.XPackInfoResponse; import org.elasticsearch.protocol.xpack.XPackUsageRequest; import org.elasticsearch.repositories.Repository; import org.elasticsearch.rest.RestController; @@ -252,7 +254,7 @@ public Collection createComponents(Client client, ClusterService cluster @Override public List> getActions() { List> actions = new ArrayList<>(); - actions.add(new ActionHandler<>(XPackInfoAction.INSTANCE, TransportXPackInfoAction.class)); + actions.add(new ActionHandler<>(XPackInfoAction.INSTANCE, getInfoAction())); actions.add(new ActionHandler<>(XPackUsageAction.INSTANCE, getUsageAction())); actions.add(new ActionHandler<>(TransportFreezeIndexAction.FreezeIndexAction.INSTANCE, TransportFreezeIndexAction.class)); @@ -265,6 +267,11 @@ protected Class return TransportXPackUsageAction.class; } + // overridable for tests + protected Class> getInfoAction() { + return TransportXPackInfoAction.class; + } + @Override public List> getClientActions() { List> actions = new ArrayList<>(); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/LocalStateSecurity.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/LocalStateSecurity.java index c2520fa62467f..c81c418bb4a36 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/LocalStateSecurity.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/LocalStateSecurity.java @@ -14,11 +14,15 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.license.LicenseService; import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.protocol.xpack.XPackInfoRequest; +import org.elasticsearch.protocol.xpack.XPackInfoResponse; import org.elasticsearch.protocol.xpack.XPackUsageRequest; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; import org.elasticsearch.xpack.core.LocalStateCompositeXPackPlugin; +import org.elasticsearch.xpack.core.action.TransportXPackInfoAction; import org.elasticsearch.xpack.core.action.TransportXPackUsageAction; +import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction; import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction; import org.elasticsearch.xpack.core.action.XPackUsageResponse; import org.elasticsearch.xpack.core.ssl.SSLService; @@ -43,6 +47,19 @@ protected List usageActions() { } } + public static class SecurityTransportXPackInfoAction extends TransportXPackInfoAction { + @Inject + public SecurityTransportXPackInfoAction(TransportService transportService, ActionFilters actionFilters, + LicenseService licenseService, NodeClient client) { + super(transportService, actionFilters, licenseService, client); + } + + @Override + protected List infoActions() { + return Collections.singletonList(XPackInfoFeatureAction.SECURITY); + } + } + public LocalStateSecurity(final Settings settings, final Path configPath) throws Exception { super(settings, configPath); LocalStateSecurity thisVar = this; @@ -75,4 +92,9 @@ protected XPackLicenseState getLicenseState() { protected Class> getUsageAction() { return SecurityTransportXPackUsageAction.class; } + + @Override + protected Class> getInfoAction() { + return SecurityTransportXPackInfoAction.class; + } } From 48c6c521d4753f60adf88d09fa6fb987ab878083 Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Sat, 22 Jun 2019 16:37:25 -0700 Subject: [PATCH 12/12] fix sql test --- .../java/org/elasticsearch/xpack/sql/plugin/SqlPluginTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plugin/SqlPluginTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plugin/SqlPluginTests.java index 451d509a65774..43102609831b3 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plugin/SqlPluginTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plugin/SqlPluginTests.java @@ -30,7 +30,7 @@ public void testSqlDisabled() { SqlPlugin plugin = new SqlPlugin(settings); assertThat(plugin.createComponents(mock(Client.class), "cluster", new NamedWriteableRegistry(Cursors.getNamedWriteables())), empty()); - assertThat(plugin.getActions(), hasSize(1)); // usage action + assertThat(plugin.getActions(), hasSize(2)); // usage action assertThat(plugin.getRestHandlers(Settings.EMPTY, mock(RestController.class), new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS), IndexScopedSettings.DEFAULT_SCOPED_SETTINGS, new SettingsFilter(Collections.emptyList()),