Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a warning header when a license is about to expire #64948

Merged
merged 21 commits into from
Dec 4, 2020
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
f85a624
This change adds a warning header when a license is about to expire
BigPandaToo Nov 11, 2020
af38237
Merge branch 'master' into Warning_header
elasticmachine Nov 11, 2020
70461a2
Merge branch 'master' into Warning_header
elasticmachine Nov 11, 2020
f6e3ceb
Merge branch 'master' into Warning_header
elasticmachine Nov 11, 2020
e52f231
Merge branch 'master' into Warning_header
elasticmachine Nov 12, 2020
1002999
This change adds realm name of the realm used to perform authenticati…
BigPandaToo Nov 12, 2020
7b1b8da
Adding doc for the new API introduced by #64517 - /_security/saml/met…
BigPandaToo Nov 17, 2020
ffcd72b
Merge branch 'master' into Warning_header
elasticmachine Nov 17, 2020
34efa0e
Adding a warning header when a license is about to expire
BigPandaToo Nov 19, 2020
fbbd2fa
Merge branch 'master' into Warning_header
elasticmachine Nov 23, 2020
a57d4b1
Merge branch 'master' into Warning_header
elasticmachine Nov 23, 2020
1ecfa75
Addressing the PR feedback
BigPandaToo Nov 23, 2020
1ed1cb2
Merge branch 'master' into Warning_header
elasticmachine Nov 26, 2020
80ca874
Merge branch 'master' into Warning_header
elasticmachine Nov 26, 2020
07fa3e2
Switching back to adding the header during featureCheck to allow
BigPandaToo Nov 26, 2020
39e7ca7
Merge branch 'master' into Warning_header
elasticmachine Nov 30, 2020
d27df6f
Changing the wording for "expired" message to be consistent with the log
BigPandaToo Dec 1, 2020
a3f2eba
Merge branch 'master' into Warning_header
elasticmachine Dec 3, 2020
b8773e3
Small changes in the way we verify header in tests
BigPandaToo Dec 3, 2020
8dc8b9c
Nit changes
BigPandaToo Dec 4, 2020
a939ae8
Merge branch 'master' into Warning_header
elasticmachine Dec 4, 2020
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
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,12 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
/**
* Duration of grace period after a license has expired
*/
static final TimeValue GRACE_PERIOD_DURATION = days(7);
public static final TimeValue GRACE_PERIOD_DURATION = days(7);

/**
* Period before the license expires when warning starts being added to the response header
*/
public static final TimeValue LICENSE_EXPIRATION_WARNING_PERIOD = days(7);

public static final long BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS =
XPackInfoResponse.BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS;
Expand Down Expand Up @@ -475,7 +480,7 @@ private void updateLicenseState(LicensesMetadata licensesMetadata) {
protected void updateLicenseState(final License license, Version mostRecentTrialVersion) {
if (license == LicensesMetadata.LICENSE_TOMBSTONE) {
// implies license has been explicitly deleted
licenseState.update(License.OperationMode.MISSING, false, mostRecentTrialVersion);
licenseState.update(License.OperationMode.MISSING, false, license.expiryDate(), mostRecentTrialVersion);
return;
}
if (license != null) {
Expand All @@ -488,7 +493,7 @@ protected void updateLicenseState(final License license, Version mostRecentTrial
// date that is near Long.MAX_VALUE
active = time >= license.issueDate() && time - GRACE_PERIOD_DURATION.getMillis() < license.expiryDate();
}
licenseState.update(license.operationMode(), active, mostRecentTrialVersion);
licenseState.update(license.operationMode(), active, license.expiryDate(), mostRecentTrialVersion);

if (active) {
if (time < license.expiryDate()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
public interface LicenseStateListener {

/**
* Callback when the license state changes. See {@link XPackLicenseState#update(License.OperationMode, boolean, Version)}.
* Callback when the license state changes. See {@link XPackLicenseState#update(License.OperationMode, boolean, long, Version)}.
*/
void licenseStateChanged();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.elasticsearch.Version;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.logging.LoggerMessageFormat;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.License.OperationMode;
Expand Down Expand Up @@ -391,7 +392,7 @@ private static boolean isBasic(OperationMode mode) {
return mode == OperationMode.BASIC;
}

/** A wrapper for the license mode and state, to allow atomically swapping. */
/** A wrapper for the license mode, state, and expiration date, to allow atomically swapping. */
private static class Status {

/** The current "mode" of the license (ie license type). */
Expand All @@ -400,9 +401,13 @@ private static class Status {
/** True if the license is active, or false if it is expired. */
final boolean active;

Status(OperationMode mode, boolean active) {
/** The current expiration date of the license; Long.MAX_VALUE if not available yet. */
final long licenseExpiryDate;

Status(OperationMode mode, boolean active, long licenseExpiryDate) {
this.mode = mode;
this.active = active;
this.licenseExpiryDate = licenseExpiryDate;
}
}

Expand All @@ -416,7 +421,7 @@ private static class Status {
// XPackLicenseState. However, if status is read multiple times in a method, it can change in between
// reads. Methods should use `executeAgainstStatus` and `checkAgainstStatus` to ensure that the status
// is only read once.
private volatile Status status = new Status(OperationMode.TRIAL, true);
private volatile Status status = new Status(OperationMode.TRIAL, true, Long.MAX_VALUE);

public XPackLicenseState(Settings settings, LongSupplier epochMillisProvider) {
this.listeners = new CopyOnWriteArrayList<>();
Expand Down Expand Up @@ -464,12 +469,13 @@ private boolean checkAgainstStatus(Predicate<Status> statusPredicate) {
*
* @param mode The mode (type) of the current license.
* @param active True if the current license exists and is within its allowed usage period; false if it is expired or missing.
* @param expirationDate Expiration date of the current license.
* @param mostRecentTrialVersion If this cluster has, at some point commenced a trial, the most recent version on which they did that.
* May be {@code null} if they have never generated a trial license on this cluster, or the most recent
* trial was prior to this metadata being tracked (6.1)
*/
void update(OperationMode mode, boolean active, @Nullable Version mostRecentTrialVersion) {
status = new Status(mode, active);
void update(OperationMode mode, boolean active, long expirationDate, @Nullable Version mostRecentTrialVersion) {
status = new Status(mode, active, expirationDate);
listeners.forEach(LicenseStateListener::licenseStateChanged);
}

Expand Down Expand Up @@ -505,12 +511,15 @@ public boolean isActive() {
/**
* Checks whether the given feature is allowed, tracking the last usage time.
*/
@SuppressForbidden(reason = "Argument to Math.abs() is definitely not Long.MIN_VALUE")
BigPandaToo marked this conversation as resolved.
Show resolved Hide resolved
public boolean checkFeature(Feature feature) {
boolean allowed = isAllowed(feature);
LongAccumulator maxEpochAccumulator = lastUsed.get(feature);
long now = System.currentTimeMillis();
if (maxEpochAccumulator != null) {
maxEpochAccumulator.accumulate(epochMillisProvider.getAsLong());
}

return allowed;
}

Expand Down Expand Up @@ -627,6 +636,11 @@ public boolean isAllowedByLicense(OperationMode minimumMode, boolean needActive)
});
}

/** Return the current license expiration date. */
public long getLicenseExpiryDate() {
return executeAgainstStatus(status -> status.licenseExpiryDate);
}

/**
* A convenient method to test whether a feature is by license status.
* @see #isAllowedByLicense(OperationMode, boolean)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,21 +360,23 @@ public static class AssertingLicenseState extends XPackLicenseState {
public final List<License.OperationMode> modeUpdates = new ArrayList<>();
public final List<Boolean> activeUpdates = new ArrayList<>();
public final List<Version> trialVersionUpdates = new ArrayList<>();
public final List<Long> expirationDateUpdates = new ArrayList<>();

public AssertingLicenseState() {
super(Settings.EMPTY, () -> 0);
}

@Override
void update(License.OperationMode mode, boolean active, Version mostRecentTrialVersion) {
void update(License.OperationMode mode, boolean active, long expirationDate, Version mostRecentTrialVersion) {
modeUpdates.add(mode);
activeUpdates.add(active);
expirationDateUpdates.add(expirationDate);
trialVersionUpdates.add(mostRecentTrialVersion);
}
}

/**
* A license state that makes the {@link #update(License.OperationMode, boolean, Version)}
* A license state that makes the {@link #update(License.OperationMode, boolean, long, Version)}
* method public for use in tests.
*/
public static class UpdatableLicenseState extends XPackLicenseState {
Expand All @@ -387,8 +389,8 @@ public UpdatableLicenseState(Settings settings) {
}

@Override
public void update(License.OperationMode mode, boolean active, Version mostRecentTrialVersion) {
super.update(mode, active, mostRecentTrialVersion);
public void update(License.OperationMode mode, boolean active, long expirationDate, Version mostRecentTrialVersion) {
super.update(mode, active, expirationDate, mostRecentTrialVersion);
}
}

Expand Down
Loading