Skip to content

Commit

Permalink
Remove basic feature checks from license state (#59814) (#66645)
Browse files Browse the repository at this point in the history
The XPackLicenseState is a utility to handle checking the currently
configured license level against the required license level of each
licensed feature. Originally all licensed features were paid features
and licenses always had a limited time scope. However, since the basic
license was introduced, all users have an unlimited time use of basic
features; there is no actual "basic license", rather it is the base case
for the default distribution. Therefore, the checks on basic features in
license state are no-ops because the current license always at least
allows basic features, and the basic license cannot be expired.

This commit removes all of the features from the license state marked as
BASIC or MISSING (a level lower than BASIC that also predates the basic
license and is no longer relevant). It also adds an assertion that no
basic license features can be added to the license state in the future.
  • Loading branch information
rjernst authored Dec 19, 2020
1 parent c013239 commit a2995ed
Show file tree
Hide file tree
Showing 91 changed files with 256 additions and 1,006 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@

import org.elasticsearch.action.ActionListener;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.xpack.core.XPackFeatureSet;
import org.elasticsearch.xpack.core.XPackField;
import org.elasticsearch.xpack.core.analytics.AnalyticsFeatureSetUsage;
Expand All @@ -19,12 +17,10 @@

public class AnalyticsFeatureSet implements XPackFeatureSet {

private final XPackLicenseState licenseState;
private Client client;

@Inject
public AnalyticsFeatureSet(@Nullable XPackLicenseState licenseState, Client client) {
this.licenseState = licenseState;
public AnalyticsFeatureSet(Client client) {
this.client = client;
}

Expand All @@ -35,7 +31,7 @@ public String name() {

@Override
public boolean available() {
return licenseState != null && licenseState.isAllowed(XPackLicenseState.Feature.ANALYTICS);
return true;
}

@Override
Expand All @@ -52,7 +48,7 @@ public Map<String, Object> nativeCodeInfo() {
public void usage(ActionListener<XPackFeatureSet.Usage> listener) {
AnalyticsStatsAction.Request request = new AnalyticsStatsAction.Request();
client.execute(AnalyticsStatsAction.INSTANCE, request,
ActionListener.wrap(r -> listener.onResponse(new AnalyticsFeatureSetUsage(available(), enabled(), r)),
ActionListener.wrap(r -> listener.onResponse(new AnalyticsFeatureSetUsage(r)),
listener::onFailure));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,10 @@
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ContextParser;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.env.Environment;
import org.elasticsearch.env.NodeEnvironment;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.license.LicenseUtils;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.plugins.ActionPlugin;
import org.elasticsearch.plugins.MapperPlugin;
import org.elasticsearch.plugins.Plugin;
Expand All @@ -32,12 +29,12 @@
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.analytics.action.TransportAnalyticsStatsAction;
import org.elasticsearch.xpack.analytics.aggregations.AnalyticsAggregatorFactory;
import org.elasticsearch.xpack.analytics.normalize.NormalizePipelineAggregationBuilder;
import org.elasticsearch.xpack.analytics.boxplot.BoxplotAggregationBuilder;
import org.elasticsearch.xpack.analytics.boxplot.InternalBoxplot;
import org.elasticsearch.xpack.analytics.cumulativecardinality.CumulativeCardinalityPipelineAggregationBuilder;
import org.elasticsearch.xpack.analytics.mapper.HistogramFieldMapper;
import org.elasticsearch.xpack.analytics.movingPercentiles.MovingPercentilesPipelineAggregationBuilder;
import org.elasticsearch.xpack.analytics.normalize.NormalizePipelineAggregationBuilder;
import org.elasticsearch.xpack.analytics.rate.InternalRate;
import org.elasticsearch.xpack.analytics.rate.RateAggregationBuilder;
import org.elasticsearch.xpack.analytics.stringstats.InternalStringStats;
Expand All @@ -50,7 +47,6 @@
import org.elasticsearch.xpack.analytics.ttest.TTestAggregationBuilder;
import org.elasticsearch.xpack.analytics.ttest.TTestState;
import org.elasticsearch.xpack.analytics.ttest.UnpairedTTestState;
import org.elasticsearch.xpack.core.XPackField;
import org.elasticsearch.xpack.core.XPackPlugin;
import org.elasticsearch.xpack.core.analytics.action.AnalyticsStatsAction;

Expand All @@ -72,26 +68,24 @@ public AnalyticsPlugin(Settings settings) {
this.transportClientMode = XPackPlugin.transportClientMode(settings);
}

public static XPackLicenseState getLicenseState() { return XPackPlugin.getSharedLicenseState(); }

@Override
public List<PipelineAggregationSpec> getPipelineAggregations() {
List<PipelineAggregationSpec> pipelineAggs = new ArrayList<>();
pipelineAggs.add(new PipelineAggregationSpec(
CumulativeCardinalityPipelineAggregationBuilder.NAME,
CumulativeCardinalityPipelineAggregationBuilder::new,
usage.track(AnalyticsStatsAction.Item.CUMULATIVE_CARDINALITY,
checkLicense(CumulativeCardinalityPipelineAggregationBuilder.PARSER))));
CumulativeCardinalityPipelineAggregationBuilder.PARSER)));
pipelineAggs.add(new PipelineAggregationSpec(
MovingPercentilesPipelineAggregationBuilder.NAME,
MovingPercentilesPipelineAggregationBuilder::new,
usage.track(AnalyticsStatsAction.Item.MOVING_PERCENTILES,
checkLicense(MovingPercentilesPipelineAggregationBuilder.PARSER))));
MovingPercentilesPipelineAggregationBuilder.PARSER)));
pipelineAggs.add(new PipelineAggregationSpec(
NormalizePipelineAggregationBuilder.NAME,
NormalizePipelineAggregationBuilder::new,
usage.track(AnalyticsStatsAction.Item.NORMALIZE,
checkLicense(NormalizePipelineAggregationBuilder.PARSER))));
NormalizePipelineAggregationBuilder.PARSER)));
return pipelineAggs;
}

Expand All @@ -101,31 +95,31 @@ public List<AggregationSpec> getAggregations() {
new AggregationSpec(
StringStatsAggregationBuilder.NAME,
StringStatsAggregationBuilder::new,
usage.track(AnalyticsStatsAction.Item.STRING_STATS, checkLicense(StringStatsAggregationBuilder.PARSER)))
usage.track(AnalyticsStatsAction.Item.STRING_STATS, StringStatsAggregationBuilder.PARSER))
.addResultReader(InternalStringStats::new)
.setAggregatorRegistrar(StringStatsAggregationBuilder::registerAggregators),
new AggregationSpec(
BoxplotAggregationBuilder.NAME,
BoxplotAggregationBuilder::new,
usage.track(AnalyticsStatsAction.Item.BOXPLOT, checkLicense(BoxplotAggregationBuilder.PARSER)))
usage.track(AnalyticsStatsAction.Item.BOXPLOT, BoxplotAggregationBuilder.PARSER))
.addResultReader(InternalBoxplot::new)
.setAggregatorRegistrar(BoxplotAggregationBuilder::registerAggregators),
new AggregationSpec(
TopMetricsAggregationBuilder.NAME,
TopMetricsAggregationBuilder::new,
usage.track(AnalyticsStatsAction.Item.TOP_METRICS, checkLicense(TopMetricsAggregationBuilder.PARSER)))
usage.track(AnalyticsStatsAction.Item.TOP_METRICS, TopMetricsAggregationBuilder.PARSER))
.addResultReader(InternalTopMetrics::new)
.setAggregatorRegistrar(TopMetricsAggregationBuilder::registerAggregators),
new AggregationSpec(
TTestAggregationBuilder.NAME,
TTestAggregationBuilder::new,
usage.track(AnalyticsStatsAction.Item.T_TEST, checkLicense(TTestAggregationBuilder.PARSER)))
usage.track(AnalyticsStatsAction.Item.T_TEST, TTestAggregationBuilder.PARSER))
.addResultReader(InternalTTest::new)
.setAggregatorRegistrar(TTestAggregationBuilder::registerUsage),
new AggregationSpec(
RateAggregationBuilder.NAME,
RateAggregationBuilder::new,
usage.track(AnalyticsStatsAction.Item.RATE, checkLicense(RateAggregationBuilder.PARSER)))
usage.track(AnalyticsStatsAction.Item.RATE, RateAggregationBuilder.PARSER))
.addResultReader(InternalRate::new)
.setAggregatorRegistrar(RateAggregationBuilder::registerAggregators)
);
Expand Down Expand Up @@ -188,13 +182,4 @@ public List<NamedWriteableRegistry.Entry> getNamedWriteables() {
new NamedWriteableRegistry.Entry(TTestState.class, UnpairedTTestState.NAME, UnpairedTTestState::new)
);
}

private static <T> ContextParser<String, T> checkLicense(ContextParser<String, T> realParser) {
return (parser, name) -> {
if (getLicenseState().checkFeature(XPackLicenseState.Feature.ANALYTICS) == false) {
throw LicenseUtils.newComplianceException(XPackField.ANALYTICS);
}
return realParser.parse(parser, name);
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ private ObjectPath run(AnalyticsUsage... nodeUsages) throws IOException {
AnalyticsStatsAction.Response response = new AnalyticsStatsAction.Response(
new ClusterName("cluster_name"), nodeResponses, emptyList());

AnalyticsFeatureSetUsage usage = new AnalyticsFeatureSetUsage(true, true, response);
AnalyticsFeatureSetUsage usage = new AnalyticsFeatureSetUsage(response);
try (XContentBuilder builder = jsonBuilder()) {
usage.toXContent(builder, ToXContent.EMPTY_PARAMS);
return ObjectPath.createFromXContent(JsonXContent.jsonXContent, BytesReference.bytes(builder));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,29 +39,10 @@

public class StatsCollectorTests extends BaseCollectorTestCase {

public void testShouldCollectReturnsFalseIfMonitoringNotAllowed() {
final Settings settings = randomFrom(ccrEnabledSettings(), ccrDisabledSettings());
final boolean ccrAllowed = randomBoolean();
final boolean isElectedMaster = randomBoolean();
whenLocalNodeElectedMaster(isElectedMaster);

// this controls the blockage
when(licenseState.checkFeature(XPackLicenseState.Feature.MONITORING)).thenReturn(false);
when(licenseState.checkFeature(XPackLicenseState.Feature.CCR)).thenReturn(ccrAllowed);

final StatsCollector collector = createCollector(settings, clusterService, licenseState, client);

assertThat(collector.shouldCollect(isElectedMaster), is(false));
if (isElectedMaster) {
verify(licenseState).checkFeature(XPackLicenseState.Feature.MONITORING);
}
}

public void testShouldCollectReturnsFalseIfNotMaster() {
// regardless of CCR being enabled
final Settings settings = randomFrom(ccrEnabledSettings(), ccrDisabledSettings());

when(licenseState.checkFeature(XPackLicenseState.Feature.MONITORING)).thenReturn(randomBoolean());
when(licenseState.checkFeature(XPackLicenseState.Feature.CCR)).thenReturn(randomBoolean());
// this controls the blockage
final boolean isElectedMaster = false;
Expand All @@ -75,7 +56,6 @@ public void testShouldCollectReturnsFalseIfCCRIsDisabled() {
// this is controls the blockage
final Settings settings = ccrDisabledSettings();

when(licenseState.checkFeature(XPackLicenseState.Feature.MONITORING)).thenReturn(randomBoolean());
when(licenseState.checkFeature(XPackLicenseState.Feature.CCR)).thenReturn(randomBoolean());

final boolean isElectedMaster = randomBoolean();
Expand All @@ -84,16 +64,11 @@ public void testShouldCollectReturnsFalseIfCCRIsDisabled() {
final StatsCollector collector = createCollector(settings, clusterService, licenseState, client);

assertThat(collector.shouldCollect(isElectedMaster), is(false));

if (isElectedMaster) {
verify(licenseState).checkFeature(XPackLicenseState.Feature.MONITORING);
}
}

public void testShouldCollectReturnsFalseIfCCRIsNotAllowed() {
final Settings settings = randomFrom(ccrEnabledSettings(), ccrDisabledSettings());

when(licenseState.checkFeature(XPackLicenseState.Feature.MONITORING)).thenReturn(randomBoolean());
// this is controls the blockage
when(licenseState.checkFeature(XPackLicenseState.Feature.CCR)).thenReturn(false);
final boolean isElectedMaster = randomBoolean();
Expand All @@ -102,24 +77,17 @@ public void testShouldCollectReturnsFalseIfCCRIsNotAllowed() {
final StatsCollector collector = createCollector(settings, clusterService, licenseState, client);

assertThat(collector.shouldCollect(isElectedMaster), is(false));

if (isElectedMaster) {
verify(licenseState).checkFeature(XPackLicenseState.Feature.MONITORING);
}
}

public void testShouldCollectReturnsTrue() {
final Settings settings = ccrEnabledSettings();

when(licenseState.checkFeature(XPackLicenseState.Feature.MONITORING)).thenReturn(true);
when(licenseState.checkFeature(XPackLicenseState.Feature.CCR)).thenReturn(true);
final boolean isElectedMaster = true;

final StatsCollector collector = createCollector(settings, clusterService, licenseState, client);

assertThat(collector.shouldCollect(isElectedMaster), is(true));

verify(licenseState).checkFeature(XPackLicenseState.Feature.MONITORING);
}

public void testDoCollect() throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,21 +47,17 @@ public class XPackLicenseState {
* Each value defines the licensed state necessary for the feature to be allowed.
*/
public enum Feature {
SECURITY(OperationMode.BASIC, false),
SECURITY_IP_FILTERING(OperationMode.GOLD, false),
SECURITY_AUDITING(OperationMode.GOLD, false),
SECURITY_DLS_FLS(OperationMode.PLATINUM, false),
SECURITY_ALL_REALMS(OperationMode.PLATINUM, false),
SECURITY_STANDARD_REALMS(OperationMode.GOLD, false),
SECURITY_CUSTOM_ROLE_PROVIDERS(OperationMode.PLATINUM, true),
SECURITY_TOKEN_SERVICE(OperationMode.STANDARD, false),
SECURITY_API_KEY_SERVICE(OperationMode.MISSING, false),
SECURITY_AUTHORIZATION_REALM(OperationMode.PLATINUM, true),
SECURITY_AUTHORIZATION_ENGINE(OperationMode.PLATINUM, true),
SECURITY_STATS_AND_HEALTH(OperationMode.MISSING, true),

WATCHER(OperationMode.STANDARD, true),
MONITORING(OperationMode.MISSING, true),
// TODO: should just check WATCHER directly?
MONITORING_CLUSTER_ALERTS(OperationMode.STANDARD, true),
MONITORING_UPDATE_RETENTION(OperationMode.STANDARD, false),
Expand All @@ -72,44 +68,18 @@ public enum Feature {

MACHINE_LEARNING(OperationMode.PLATINUM, true),

TRANSFORM(OperationMode.MISSING, true),

ROLLUP(OperationMode.MISSING, true),

VOTING_ONLY(OperationMode.MISSING, true),

LOGSTASH(OperationMode.STANDARD, true),

DEPRECATION(OperationMode.MISSING, true),

ILM(OperationMode.MISSING, true),

ENRICH(OperationMode.MISSING, true),

EQL(OperationMode.MISSING, true),

SQL(OperationMode.MISSING, true),

JDBC(OperationMode.PLATINUM, true),

ODBC(OperationMode.PLATINUM, true),

FLATTENED(OperationMode.MISSING, true),

VECTORS(OperationMode.MISSING, true),

SPATIAL(OperationMode.MISSING, true),

SPATIAL_GEO_CENTROID(OperationMode.GOLD, true),

SPATIAL_GEO_GRID(OperationMode.GOLD, true),

SPATIAL_GEO_LINE(OperationMode.GOLD, true),

ANALYTICS(OperationMode.MISSING, true),

AGGREGATE_METRIC(OperationMode.MISSING, true),

SEARCHABLE_SNAPSHOTS(OperationMode.ENTERPRISE, true),

OPERATOR_PRIVILEGES(OperationMode.ENTERPRISE, true),
Expand All @@ -120,6 +90,7 @@ public enum Feature {
final boolean needsActive;

Feature(OperationMode minimumOperationMode, boolean needsActive) {
assert minimumOperationMode.compareTo(OperationMode.BASIC) > 0: minimumOperationMode.toString();
this.minimumOperationMode = minimumOperationMode;
this.needsActive = needsActive;
}
Expand Down Expand Up @@ -447,7 +418,7 @@ public XPackLicenseState(Settings settings, LongSupplier epochMillisProvider) {
// care to actually keep track of
Map<Feature, LongAccumulator> lastUsed = new EnumMap<>(Feature.class);
for (Feature feature : Feature.values()) {
if (feature.minimumOperationMode.compareTo(OperationMode.BASIC) > 0 && NON_TRACKED_FEATURES.contains(feature) == false) {
if (NON_TRACKED_FEATURES.contains(feature) == false) {
lastUsed.put(feature, new LongAccumulator(Long::max, 0));
}
}
Expand Down Expand Up @@ -519,7 +490,7 @@ public boolean allowForAllLicenses() {

// Package private for tests
/** Return true if the license is currently within its time boundaries, false otherwise. */
boolean isActive() {
public boolean isActive() {
return checkAgainstStatus(status -> status.active);
}

Expand Down Expand Up @@ -573,11 +544,6 @@ public static boolean isMachineLearningAllowedForOperationMode(final OperationMo
return isAllowedByOperationMode(operationMode, OperationMode.PLATINUM);
}

public static boolean isTransformAllowedForOperationMode(final OperationMode operationMode) {
// any license (basic and upwards)
return operationMode != License.OperationMode.MISSING;
}

public static boolean isFipsAllowedForOperationMode(final OperationMode operationMode) {
return isAllowedByOperationMode(operationMode, OperationMode.PLATINUM);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ public AggregateMetricFeatureSetUsage(StreamInput input) throws IOException {
super(input);
}

public AggregateMetricFeatureSetUsage(boolean available, boolean enabled) {
super(XPackField.AGGREGATE_METRIC, available, enabled);
public AggregateMetricFeatureSetUsage() {
super(XPackField.AGGREGATE_METRIC, true, true);
}

@Override public Version getMinimalSupportedVersion() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ public class AnalyticsFeatureSetUsage extends XPackFeatureSet.Usage {

private final AnalyticsStatsAction.Response response;

public AnalyticsFeatureSetUsage(boolean available, boolean enabled, AnalyticsStatsAction.Response response) {
super(XPackField.ANALYTICS, available, enabled);
public AnalyticsFeatureSetUsage(AnalyticsStatsAction.Response response) {
super(XPackField.ANALYTICS, true, true);
this.response = response;
}

Expand Down
Loading

0 comments on commit a2995ed

Please sign in to comment.