Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,9 @@ tasks.register("verifyVersions") {
* after the backport of the backcompat code is complete.
*/

boolean bwc_tests_enabled = true
boolean bwc_tests_enabled = false
// place a PR link here when committing bwc changes:
String bwc_tests_disabled_issue = ""
String bwc_tests_disabled_issue = "https://github.com/elastic/elasticsearch/pull/76622"
/*
* FIPS 140-2 behavior was fixed in 7.11.0. Before that there is no way to run elasticsearch in a
* JVM that is properly configured to be in fips mode with BCFIPS. For now we need to disable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,27 @@
public class GetFeatureUsageResponse extends ActionResponse implements ToXContentObject {

public static class FeatureUsageInfo implements Writeable {
private final String name;
private final ZonedDateTime lastUsedTime;
private final String context;
public final String licenseLevel;
final String family;
final String name;
final ZonedDateTime lastUsedTime;
final String context;
final String licenseLevel;

public FeatureUsageInfo(String name, ZonedDateTime lastUsedTime, @Nullable String context, String licenseLevel) {
public FeatureUsageInfo(@Nullable String family, String name, ZonedDateTime lastUsedTime,
@Nullable String context, String licenseLevel) {
this.family = family;
this.name = Objects.requireNonNull(name, "Feature name may not be null");
this.lastUsedTime = Objects.requireNonNull(lastUsedTime, "Last used time may not be null");
this.context = context;
this.licenseLevel = Objects.requireNonNull(licenseLevel, "License level may not be null");
}

public FeatureUsageInfo(StreamInput in) throws IOException {
if (in.getVersion().onOrAfter(Version.V_7_16_0)) {
this.family = in.readOptionalString();
} else {
this.family = null;
}
this.name = in.readString();
this.lastUsedTime = ZonedDateTime.ofInstant(Instant.ofEpochSecond(in.readLong()), ZoneOffset.UTC);
if (in.getVersion().onOrAfter(Version.V_7_15_0)) {
Expand All @@ -52,6 +60,9 @@ public FeatureUsageInfo(StreamInput in) throws IOException {

@Override
public void writeTo(StreamOutput out) throws IOException {
if (out.getVersion().onOrAfter(Version.V_7_16_0)) {
out.writeOptionalString(this.family);
}
out.writeString(name);
out.writeLong(lastUsedTime.toEpochSecond());
if (out.getVersion().onOrAfter(Version.V_7_15_0)) {
Expand Down Expand Up @@ -86,6 +97,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
builder.startArray("features");
for (FeatureUsageInfo feature : features) {
builder.startObject();
builder.field("family", feature.family);
builder.field("name", feature.name);
builder.field("context", feature.context);
builder.field("last_used", feature.lastUsedTime.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ public abstract class LicensedFeature {
*/
public static class Momentary extends LicensedFeature {

private Momentary(String name, License.OperationMode minimumOperationMode, boolean needsActive) {
super(name, minimumOperationMode, needsActive);
private Momentary(String family, String name, License.OperationMode minimumOperationMode, boolean needsActive) {
super(family, name, minimumOperationMode, needsActive);
}

/**
Expand All @@ -41,8 +41,8 @@ public boolean check(XPackLicenseState state) {
* A Persistent feature is one that is tracked starting when the license is checked, and later may be untracked.
*/
public static class Persistent extends LicensedFeature {
private Persistent(String name, License.OperationMode minimumOperationMode, boolean needsActive) {
super(name, minimumOperationMode, needsActive);
private Persistent(String family, String name, License.OperationMode minimumOperationMode, boolean needsActive) {
super(family, name, minimumOperationMode, needsActive);
}

/**
Expand All @@ -66,42 +66,44 @@ public void stopTracking(XPackLicenseState state, String contextName) {
}
}

final String family;
final String name;
final License.OperationMode minimumOperationMode;
final boolean needsActive;

public LicensedFeature(String name, License.OperationMode minimumOperationMode, boolean needsActive) {
protected LicensedFeature(String family, String name, License.OperationMode minimumOperationMode, boolean needsActive) {
this.family = family;
this.name = name;
this.minimumOperationMode = minimumOperationMode;
this.needsActive = needsActive;
}

/** Create a momentary feature for hte given license level */
public static Momentary momentary(String name, License.OperationMode licenseLevel) {
return new Momentary(name, licenseLevel, true);
public static Momentary momentary(String family, String name, License.OperationMode licenseLevel) {
return new Momentary(family, name, licenseLevel, true);
}

/** Create a persistent feature for the given license level */
public static Persistent persistent(String name, License.OperationMode licenseLevel) {
return new Persistent(name, licenseLevel, true);
public static Persistent persistent(String family, String name, License.OperationMode licenseLevel) {
return new Persistent(family, name, licenseLevel, true);
}

/**
* Creates a momentary feature, but one that is lenient as
* to whether the license needs to be active to allow the feature.
*/
@Deprecated
public static Momentary momentaryLenient(String name, License.OperationMode licenseLevel) {
return new Momentary(name, licenseLevel, false);
public static Momentary momentaryLenient(String family, String name, License.OperationMode licenseLevel) {
return new Momentary(family, name, licenseLevel, false);
}

/**
* Creates a persistent feature, but one that is lenient as
* to whether the license needs to be active to allow the feature.
*/
@Deprecated
public static Persistent persistentLenient(String name, License.OperationMode licenseLevel) {
return new Persistent(name, licenseLevel, false);
public static Persistent persistentLenient(String family, String name, License.OperationMode licenseLevel) {
return new Persistent(family, name, licenseLevel, false);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@ protected void doExecute(Task task, GetFeatureUsageRequest request, ActionListen
ZonedDateTime lastUsedTime = Instant.ofEpochMilli(lastUsed).atZone(ZoneOffset.UTC);
usageInfos.add(
new GetFeatureUsageResponse.FeatureUsageInfo(
usage.featureName(),
usage.feature().family,
usage.feature().name,
lastUsedTime,
usage.contextName(),
usage.minimumOperationMode().description()
usage.feature().minimumOperationMode.description()
)
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,11 @@ public enum Feature {

Feature(OperationMode minimumOperationMode, boolean needsActive) {
assert minimumOperationMode.compareTo(OperationMode.BASIC) > 0: minimumOperationMode.toString();
String name = name().toLowerCase(Locale.ROOT);
if (needsActive) {
this.feature = LicensedFeature.momentary(name().toLowerCase(Locale.ROOT), minimumOperationMode);
this.feature = LicensedFeature.momentary(name, name, minimumOperationMode);
} else {
this.feature = LicensedFeature.momentaryLenient(name().toLowerCase(Locale.ROOT), minimumOperationMode);
this.feature = LicensedFeature.momentaryLenient(name, name, minimumOperationMode);
}
}
}
Expand Down Expand Up @@ -659,16 +660,12 @@ public int hashCode() {
return Objects.hash(feature, context);
}

public String featureName() {
return feature.name;
public LicensedFeature feature() {
return feature;
}

public String contextName() {
return context;
}

public OperationMode minimumOperationMode() {
return feature.minimumOperationMode;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.license;

import org.elasticsearch.Version;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.license.GetFeatureUsageResponse.FeatureUsageInfo;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.VersionUtils;

import java.io.IOException;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.List;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;

public class GetFeatureUsageResponseTests extends ESTestCase {

public void assertStreamInputOutput(Version version, String family, String context) throws IOException {
ZonedDateTime zdt = ZonedDateTime.now();
FeatureUsageInfo fui = new FeatureUsageInfo(family, "feature", zdt, context, "gold");
GetFeatureUsageResponse originalResponse = new GetFeatureUsageResponse(List.of(fui));
BytesStreamOutput output = new BytesStreamOutput();
output.setVersion(version);
originalResponse.writeTo(output);

StreamInput input = output.bytes().streamInput();
input.setVersion(version);
GetFeatureUsageResponse finalResponse = new GetFeatureUsageResponse(input);
assertThat(finalResponse.getFeatures(), hasSize(1));
FeatureUsageInfo fui2 = finalResponse.getFeatures().get(0);
assertThat(fui2.family, equalTo(family));
assertThat(fui2.name, equalTo("feature"));
// time is truncated to nearest second
assertThat(fui2.lastUsedTime, equalTo(zdt.withZoneSameInstant(ZoneOffset.UTC).withNano(0)));
assertThat(fui2.context, equalTo(context));
assertThat(fui2.licenseLevel, equalTo("gold"));
}

public void testPre715StreamFormat() throws IOException {
assertStreamInputOutput(VersionUtils.getPreviousVersion(Version.V_7_15_0), null, null);
}

public void testStreamFormat() throws IOException {
assertStreamInputOutput(Version.CURRENT, "family", "context");
// family and context are optional
assertStreamInputOutput(Version.CURRENT, null, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ public void testCcrAckTrialOrPlatinumToNotTrialOrPlatinum() {
}

public void testLastUsedMomentaryFeature() {
LicensedFeature.Momentary goldFeature = LicensedFeature.momentary("goldFeature", GOLD);
LicensedFeature.Momentary goldFeature = LicensedFeature.momentary("family", "goldFeature", GOLD);
AtomicInteger currentTime = new AtomicInteger(100); // non zero start time
XPackLicenseState licenseState = new XPackLicenseState(currentTime::get);
Map<XPackLicenseState.FeatureUsage, Long> lastUsed = licenseState.getLastUsed();
Expand All @@ -459,7 +459,7 @@ public void testLastUsedMomentaryFeature() {
assertThat("feature.check tracks usage", lastUsed, aMapWithSize(1));

XPackLicenseState.FeatureUsage usage = Iterables.get(lastUsed.keySet(), 0);
assertThat(usage.featureName(), equalTo("goldFeature"));
assertThat(usage.feature().name, equalTo("goldFeature"));
assertThat(usage.contextName(), nullValue());
assertThat(lastUsed.get(usage), equalTo(100L));

Expand All @@ -471,7 +471,7 @@ public void testLastUsedMomentaryFeature() {
}

public void testLastUsedPersistentFeature() {
LicensedFeature.Persistent goldFeature = LicensedFeature.persistent("goldFeature", GOLD);
LicensedFeature.Persistent goldFeature = LicensedFeature.persistent("family", "goldFeature", GOLD);
AtomicInteger currentTime = new AtomicInteger(100); // non zero start time
XPackLicenseState licenseState = new XPackLicenseState(currentTime::get);
Map<XPackLicenseState.FeatureUsage, Long> lastUsed = licenseState.getLastUsed();
Expand All @@ -487,7 +487,7 @@ public void testLastUsedPersistentFeature() {
assertThat(lastUsed, aMapWithSize(1));

XPackLicenseState.FeatureUsage usage = Iterables.get(lastUsed.keySet(), 0);
assertThat(usage.featureName(), equalTo("goldFeature"));
assertThat(usage.feature().name, equalTo("goldFeature"));
assertThat(usage.contextName(), equalTo("somecontext"));
assertThat(lastUsed.get(usage), equalTo(200L));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,17 +351,17 @@ public class Security extends Plugin implements SystemIndexPlugin, IngestPlugin,

// TODO: ip filtering does not actually track license usage yet
public static final LicensedFeature.Momentary IP_FILTERING_FEATURE =
LicensedFeature.momentaryLenient("security_ip_filtering", License.OperationMode.GOLD);
LicensedFeature.momentaryLenient(null, "security_ip_filtering", License.OperationMode.GOLD);
public static final LicensedFeature.Momentary AUDITING_FEATURE =
LicensedFeature.momentaryLenient("security_auditing", License.OperationMode.GOLD);
LicensedFeature.momentaryLenient(null, "security_auditing", License.OperationMode.GOLD);

// Builtin realms (file/native) realms are Basic licensed, so don't need to be checked or tracked
// Standard realms (LDAP, AD, PKI, etc) are Gold+
// SSO realms are Platinum+
public static final LicensedFeature.Persistent STANDARD_REALMS_FEATURE =
LicensedFeature.persistentLenient("security_standard_realms", License.OperationMode.GOLD);
LicensedFeature.persistentLenient(null, "security_standard_realms", License.OperationMode.GOLD);
public static final LicensedFeature.Persistent ALL_REALMS_FEATURE =
LicensedFeature.persistentLenient("security_all_realms", License.OperationMode.PLATINUM);
LicensedFeature.persistentLenient(null, "security_all_realms", License.OperationMode.PLATINUM);

private static final Logger logger = LogManager.getLogger(Security.class);

Expand Down