-
Notifications
You must be signed in to change notification settings - Fork 24.9k
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
Convert remote license checker to use LicensedFeature #79876
Conversation
The RemoteClusterLicenseChecker pulls the license level of a remote cluster and checks it allows a local feature to communicate with that cluster. It does the check with a lambda, but these methods could be out of sync with the actual licensed feature. This commit converts the remote license checker to take in the feature object that should be checked.
Pinging @elastic/es-security (Team:Security) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a question for whether null
is equivalent to "alway-true" license checker.
* Constructs a remote cluster license checker with the specified license predicate for checking license compatibility. The predicate | ||
* does not need to check for the active license state as this is handled by the remote cluster license checker. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Constructs a remote cluster license checker with the specified license predicate for checking license compatibility. The predicate | |
* does not need to check for the active license state as this is handled by the remote cluster license checker. | |
* Constructs a remote cluster license checker with the specified licensed feature for checking license compatibility. The feature | |
* does not need to check for the active license state as this is handled by the remote cluster license checker. |
if (licenseInfo.getStatus() == LicenseStatus.ACTIVE == false | ||
|| isAllowedByOperationMode(License.OperationMode.parse(licenseInfo.getMode()), | ||
feature.getMinimumOperationMode()) == false) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not a real issue but I feel a bit itchy that we don't check whether the feature actual needs an Active license here. It does and requiring active license is a norm going forward. But for the sake of clarity in this particular scope, I'd have something like
if (licenseInfo.getStatus() == LicenseStatus.ACTIVE == false | |
|| isAllowedByOperationMode(License.OperationMode.parse(licenseInfo.getMode()), | |
feature.getMinimumOperationMode()) == false) { | |
if ((feature.isNeedsActive() && licenseInfo.getStatus() == LicenseStatus.ACTIVE == false) | |
|| isAllowedByOperationMode(License.OperationMode.parse(licenseInfo.getMode()), | |
feature.getMinimumOperationMode()) == false) { |
if (remoteClusterLicenseInfo.licenseInfo().getStatus() != LicenseStatus.ACTIVE) { | ||
error.append(String.format(Locale.ROOT, "the license on cluster [%s] is not active", remoteClusterLicenseInfo.clusterAlias())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, this assumes the feature requires an active license, which is true. But the assumption is somewhat disconnected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've adjusted this so that if the feature is present, it checks the isNeedsActive(). It also checks if the feature is not present, to match the current behavior where an active license is still needed for the BASIC functionality.
DiscoveryNode.isRemoteClusterClient(settings) | ||
/* transforms are BASIC so always allowed, no need to check license */ | ||
? new RemoteClusterLicenseChecker(client, mode -> true) : null, | ||
/* transforms are BASIC so always allowed, no need to check license */ | ||
null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am familiar with code for the transform feature. But it seems a null
license checker would disable CCS according to the following comment:
Line 267 in e82a70c
* @param remoteClusterLicenseChecker A RemoteClusterLicenseChecker or null if CCS is disabled |
So there is a difference between null
and a license checker that always return true
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, I misunderstood what null
meant here. I've changed the remote checker so that null
can be passed into the ctor to mean the checker is a noop.
DiscoveryNode.isRemoteClusterClient(settings) | ||
/* transforms are BASIC so always allowed, no need to check license */ | ||
? new RemoteClusterLicenseChecker(client, mode -> true) : null, | ||
/* transforms are BASIC so always allowed, no need to check license */ | ||
null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above
73fdae6
to
8912627
Compare
@ywangd This is read for another review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left a few more suggestions. Thanks!
if (((feature == null || feature.isNeedsActive()) && licenseInfo.getStatus() != LicenseStatus.ACTIVE) | ||
|| feature != null | ||
&& isAllowedByOperationMode( | ||
License.OperationMode.parse(licenseInfo.getMode()), | ||
feature.getMinimumOperationMode() | ||
) == false) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we break into smaller and more readable pieces? I had to copy/paste it into an IDE to parse it.
I also think the logic is incorrect when feature !=null
. When feature != null
, the second half of the condition is triggered and it bypasses the active license check because it is or
'd.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The formatting got destroyed by spotless. I will try to restructure, but I think the logic is correct. This entire conditional is a short-circuit, so the first part of the OR is whether the license is active. If it is active (first part evaluates to false), then the second part is checked, which is only necessary when feature != null
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK I think you are right. The whole thing is a negative check, i.e. it checks for violation instead of conformation. That's what got me confused initially. I think this is also a sign that the logic here is not easy to parse. I'd appreciate any improvement for readability.
x-pack/plugin/core/src/main/java/org/elasticsearch/license/RemoteClusterLicenseChecker.java
Outdated
Show resolved
Hide resolved
x-pack/plugin/core/src/main/java/org/elasticsearch/license/RemoteClusterLicenseChecker.java
Outdated
Show resolved
Hide resolved
? new RemoteClusterLicenseChecker(client, mode -> true) | ||
? new RemoteClusterLicenseChecker(client, null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exposing a null
feature to the caller does not seem to be very intuitive. I think a more descriptive approach is to have a static method that returns an instance of license checker, e.g. something like
RemoteClusterLicenseChecker.activeLicenseChecker(client)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given there are only 2 callers with null, I see this as a special case not warranting another method. I'm inclined to leave this for now.
@ywangd I pushed an update which makes the logic much simpler to understand. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Thanks for the iterations!
} else if (feature != null) { | ||
assert isAllowedByOperationMode( | ||
License.OperationMode.parse(remoteClusterLicenseInfo.licenseInfo().getMode()), | ||
feature.getMinimumOperationMode() | ||
) == false : "license must be incompatible to build error message"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: We no longer have a else
block which is for the impossible case of feature == null && licenseStatus == ACTIVE
. But should we add an assertion for it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will remove feature != null here. The isAllowed assertion now takes into account the null feature.
The RemoteClusterLicenseChecker pulls the license level of a remote cluster and checks it allows a local feature to communicate with that cluster. It does the check with a lambda, but these methods could be out of sync with the actual licensed feature. This commit converts the remote license checker to take in the feature object that should be checked.
💔 Backport failed
You can use sqren/backport to manually backport by running |
The RemoteClusterLicenseChecker pulls the license level of a remote cluster and checks it allows a local feature to communicate with that cluster. It does the check with a lambda, but these methods could be out of sync with the actual licensed feature. This commit converts the remote license checker to take in the feature object that should be checked.
The RemoteClusterLicenseChecker pulls the license level of a remote cluster and checks it allows a local feature to communicate with that cluster. It does the check with a lambda, but these methods could be out of sync with the actual licensed feature. This commit converts the remote license checker to take in the feature object that should be checked.
The RemoteClusterLicenseChecker pulls the license level of a remote cluster and checks it allows a local feature to communicate with that cluster. It does the check with a lambda, but these methods could be out of sync with the actual licensed feature. This commit converts the remote license checker to take in the feature object that should be checked.
…formance * upstream/master: (153 commits) [ML] update truncation default & adding field output when input is truncated (elastic#79942) [ML] stop using isAllowedByLicense for model license checks (elastic#79908) [ML] Retain built-in ML roles granting Kibana privileges (elastic#80014) [Transform] remove old mixed cluster BWC layers, not required for 8x (elastic#79927) Increase test timeout for CoordinatorTests testAllSearchesExecuted [Transform] add rolling upgrade tests for upgrade endpoint (elastic#79721) [ML] Update trained model docs for truncate parameter for bert tokenization (elastic#79652) `CoordinatorTests` sometimes needs three term bumps (elastic#79574) [ML] Account for service being triggered twice in tests (elastic#80000) SearchContext: remove unused variable (elastic#79917) Revert "Deprecate resolution loss on date field (elastic#78921)" (elastic#79914) Re-enable GeoIpDownloaderIT#testStartWithNoDatabases() (elastic#79907) Fix SnapshotBasedIndexRecoveryIT#testSeqNoBasedRecoveryIsUsedAfterPrimaryFailOver (elastic#79469) Fix RecoverySourceHandlerTests (elastic#79546) SQL: stabilize SqlSearchPageTimeoutIT (elastic#79928) Wait 3 seconds for the server to reload trust (elastic#79778) Skip automatically preserved request headers when rewriting (elastic#79973) Check whether stdout is a real console (elastic#79882) Convert remote license checker to use LicensedFeature (elastic#79876) Miscellaneous fixes for LDAP SDK v6 upgrade (elastic#79891) ... # Conflicts: # libs/x-content/src/main/java/org/elasticsearch/xcontent/support/filtering/FilterPath.java # libs/x-content/src/test/java/org/elasticsearch/xcontent/support/filtering/FilterPathGeneratorFilteringTests.java # libs/x-content/src/test/java/org/elasticsearch/xcontent/support/filtering/FilterPathTests.java
The RemoteClusterLicenseChecker pulls the license level of a remote
cluster and checks it allows a local feature to communicate with that
cluster. It does the check with a lambda, but these methods could be out
of sync with the actual licensed feature. This commit converts the
remote license checker to take in the feature object that should be
checked.