[Inference API] Get _services skips EIS authorization call if CCM is not configured#139964
Conversation
...rence/services/elastic/authorization/ElasticInferenceServiceAuthorizationRequestHandler.java
Show resolved
Hide resolved
|
Pinging @elastic/search-inference-team (Team:Search - Inference) |
| if (Strings.isNullOrEmpty(baseUrl)) { | ||
| logger.debug("The base URL for the authorization service is not valid, rejecting authorization."); | ||
| listener.onResponse(ElasticInferenceServiceAuthorizationModel.unauthorized()); | ||
| private void getAuthorizationHelper( |
There was a problem hiding this comment.
Nitpick, but this method name could be a little confusing, since it might imply that it returns an "authorization helper" rather than being a helper method. Maybe calling it "getOrSkipAuthorization()" would be better? Or just use "getAuthorization()" ?
| private void getAuthorizationHelper( | ||
| ActionListener<ElasticInferenceServiceAuthorizationModel> listener, | ||
| Sender sender, | ||
| boolean skipIfCcmNotConfigured |
There was a problem hiding this comment.
There's some inconsistency between using "configured" and "enabled" when talking about CCM, with some places preferring "configured" (getAuthorizationSkippingIfCcmNotConfigured(), skipIfCcmNotConfigured, logger.debug("CCM is not configured...), but others using "enabled" (isCcmEnabledListener, ccmService.isEnabled(isCcmEnabledListener)). Is there a meaningful difference between "configured" and "enabled" here, or would it be possible to simplify things by using "enabled" throughout?
There was a problem hiding this comment.
I'll refactor to stick to enabled and remove configured.
For the method name getAuthorizationSkippingIfCcmNotConfigured, this is a little more tricky because I'm trying to say that this method will retrieve the authorization information if ccm is enabled and we're in a supported environment. I'm going to switch it to getAuthorizationIfPermittedEnvironment. Let me know if you have a better idea though.
| var countdownListener = ActionListener.runAfter(listener, requestCompleteLatch::countDown); | ||
|
|
||
| try { | ||
| if (skipIfCcmNotConfigured == false || ccmFeature.isCcmSupportedEnvironment() == false) { |
There was a problem hiding this comment.
Just personal preference, but I find it easier to parse the boolean logic here if it gets refactored to:
if (skipIfCcmNotConfigured && ccmFeature.isCcmSupportedEnvironment()) {
var isCcmEnabledListener = ActionListener.<Boolean>wrap(response -> {
if (response == null || response == false) {
logger.debug("CCM is not configured, skipping authorization request to Elastic Inference Service.");
countdownListener.onResponse(ElasticInferenceServiceAuthorizationModel.unauthorized());
} else {
retrieveAuthorizationInformation(countdownListener, sender);
}
}, e -> {
logger.atDebug().withThrowable(e).log("Failed to determine if CCM is configured, returning unauthorized.");
countdownListener.onResponse(ElasticInferenceServiceAuthorizationModel.unauthorized());
});
ccmService.isEnabled(isCcmEnabledListener);
} else {
retrieveAuthorizationInformation(countdownListener, sender);
}
| var isCcmEnabledListener = ActionListener.<Boolean>wrap(response -> { | ||
| if (response == null || response == false) { |
There was a problem hiding this comment.
Nitpick, but for better readability, consider renaming response to enabled.
|
|
||
| assertNoAuthHeader(webServer.requests()); | ||
|
|
||
| authHandler.waitForAuthRequestCompletion(TimeValue.THIRTY_SECONDS); |
There was a problem hiding this comment.
Rather than using a hard-coded value for the timeout here, it would be better to use the ESTestCase.TEST_REQUEST_TIMEOUT constant (which is also 30 seconds). There is also a TIMEOUT constant defined in this class which can be replaced with the ESTestCase constant.
| // There should be no requests made to EIS because it is not configured | ||
| assertThat(webServer.requests().size(), is(0)); |
There was a problem hiding this comment.
This comment is a little misleading, since we would expect no requests made to EIS even if CCM was configured, because we're throwing an exception before we can send any requests. With that in mind, it might be good to have a test where CCM is enabled and we throw an exception, and then confirm that we don't send any requests in that scenario either.
Also, rather than asserting on the size being 0, asserting that the list is empty will provide a much more informative error message if the assertion fails, allowing us to see what unexpected objects were present instead of just knowing that the list's size was non-zero:
assertThat(webServer.requests(), empty());
|
|
||
| authHandler.waitForAuthRequestCompletion(TimeValue.THIRTY_SECONDS); | ||
|
|
||
| verify(mockCcmFeature, times(1)).isCcmSupportedEnvironment(); |
There was a problem hiding this comment.
The cause/effect is flipped here compared to how we'd normally want to use verify(), since it's not the case that we expect to call isCcmSupportedEnvironment() when we encounter an exception, but rather that calling isCcmSupportedEnvironment() is what causes the exception to be thrown in the first place. If we don't call isCcmSupportedEnvironment() then the test will fail because no exception will be thrown, so we don't need this verify check here.
| var mockCcmFeature = createMockCcmFeature(false); | ||
| var mockCcmService = createMockCcmService(false); | ||
|
|
||
| var authHandler = new ElasticInferenceServiceAuthorizationRequestHandler( |
There was a problem hiding this comment.
Everything past this line is duplicated in testGetAuthorizationSkipIfCcmNotConfigured_ReturnsAValidResponse_WhenCcmSupportedEnvironmentAndConfigured() and can probably be extracted to a common method if you pass in a boolean for whether you expect CCMService.isEnabled() to be called.
| var responseData = getEisAuthorizationResponseWithMultipleEndpoints(eisGatewayUrl); | ||
|
|
||
| webServer.enqueue(new MockResponse().setResponseCode(200).setBody(responseData.responseJson())); |
There was a problem hiding this comment.
We don't need to enqueue anything here, because we never send a request that would require a response.
| var logger = mock(Logger.class); | ||
|
|
||
| var mockCcmFeature = createMockCcmFeature(false); | ||
| var mockCcmService = createMockCcmService(false); |
There was a problem hiding this comment.
We can get some additional (possibly redundant) coverage by using createMockCcmService(randomBoolean()) here, since we expect the behaviour to be the same regardless of whether CCM is enabled, if the environment doesn't support it. I don't know if it's possible to actually configure things so that the environment doesn't support CMM but CMM is enabled, but it wouldn't hurt to have a test that confirms the behaviour just in case.
| retrieveAuthorizationInformation(countdownListener, sender); | ||
| } | ||
| }, e -> { | ||
| logger.atDebug().withThrowable(e).log("Failed to determine if CCM is configured, returning unauthorized."); |
There was a problem hiding this comment.
Should this be logged at a higher level than debug?
💚 Backport successful
|
…not configured (elastic#139964) * Skipping auth call if ccm is not configured * Addressing feedback * Increasing log level * Fixing test
* upstream/main: (76 commits) [Inference API] Get _services skips EIS authorization call if CCM is not configured (elastic#139964) Improve TSDB codec benchmarks with full encoder and compression metrics (elastic#140299) ESQL: Consolidate test `BlockLoaderContext`s (elastic#140403) ESQL: Improve Lookup Join performance with CachedDirectoryReader (elastic#139314) ES|QL: Add more examples for the match operator (elastic#139815) ESQL: Add timezone to add and sub operators, and ConfigurationAware planning support (elastic#140101) ESQL: Updated ToIp tests and generated documentation for map parameters (elastic#139994) Disable _delete_by_query and _update_by_query for CCS/stateful (elastic#140301) Remove unused method ElasticInferenceService.translateToChunkedResults (elastic#140442) logging hot threads on large queue of the management threadpool (elastic#140251) Search functions docs cleanup (elastic#140435) Unmute 350_point_in_time/point-in-time with index filter (elastic#140443) Remove unused methods (elastic#140222) Add CPS and `project_routing` support for `_mvt` (elastic#140053) Streamline `ShardDeleteResults` collection (elastic#140363) Fix Docker build to use --load for single-platform images (elastic#140402) Parametrize + test VectorScorerOSQBenchmark (elastic#140354) `RecyclerBytesStreamOutput` using absolute offsets (elastic#140303) Define bulk float native methods for vector scoring (elastic#139885) Make `TimeSeriesAggregate` `TimestampAware` (elastic#140270) ...
…not configured (elastic#139964) * Skipping auth call if ccm is not configured * Addressing feedback * Increasing log level * Fixing test
When GET _inference/_services is made, the services implementation makes an EIS authorization request to determine what task types the cluster is authorized for.
If the environment supports CCM but the user hasn't configured an api key yet the the request would produce a few warning logs. This PR adds logic to skip trying to make the authorization request if it is a CCM supported environment but the user hasn't configured the api key.
If it is not a CCM supported environment, or if the user has supplied the API key, then the authorization request will be made.