Skip to content

[Inference API] Get _services skips EIS authorization call if CCM is not configured#139964

Merged
jonathan-buttner merged 10 commits intoelastic:mainfrom
jonathan-buttner:ia-skip-eis-in-services
Jan 9, 2026
Merged

[Inference API] Get _services skips EIS authorization call if CCM is not configured#139964
jonathan-buttner merged 10 commits intoelastic:mainfrom
jonathan-buttner:ia-skip-eis-in-services

Conversation

@jonathan-buttner
Copy link
Contributor

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.

@jonathan-buttner jonathan-buttner added >non-issue auto-backport Automatically create backport pull requests when merged Feature:GenAI Features around GenAI :SearchOrg/Inference Label for the Search Inference team Team:Search - Inference v9.3.0 v9.3.1 labels Dec 23, 2025
@jonathan-buttner jonathan-buttner marked this pull request as ready for review December 23, 2025 20:59
@elasticsearchmachine
Copy link
Collaborator

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(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds good to me

var countdownListener = ActionListener.runAfter(listener, requestCompleteLatch::countDown);

try {
if (skipIfCcmNotConfigured == false || ccmFeature.isCcmSupportedEnvironment() == false) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
}

Comment on lines 135 to 136
var isCcmEnabledListener = ActionListener.<Boolean>wrap(response -> {
if (response == null || response == false) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick, but for better readability, consider renaming response to enabled.


assertNoAuthHeader(webServer.requests());

authHandler.waitForAuthRequestCompletion(TimeValue.THIRTY_SECONDS);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines 300 to 301
// There should be no requests made to EIS because it is not configured
assertThat(webServer.requests().size(), is(0));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines 290 to 292
var responseData = getEisAuthorizationResponseWithMultipleEndpoints(eisGatewayUrl);

webServer.enqueue(new MockResponse().setResponseCode(200).setBody(responseData.responseJson()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be logged at a higher level than debug?

@jonathan-buttner jonathan-buttner enabled auto-merge (squash) January 9, 2026 16:55
@jonathan-buttner jonathan-buttner merged commit 3efea49 into elastic:main Jan 9, 2026
35 checks passed
@elasticsearchmachine
Copy link
Collaborator

💚 Backport successful

Status Branch Result
9.3

jonathan-buttner added a commit to jonathan-buttner/elasticsearch that referenced this pull request Jan 9, 2026
…not configured (elastic#139964)

* Skipping auth call if ccm is not configured

* Addressing feedback

* Increasing log level

* Fixing test
szybia added a commit to szybia/elasticsearch that referenced this pull request Jan 9, 2026
* 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)
  ...
elasticsearchmachine pushed a commit that referenced this pull request Jan 9, 2026
…not configured (#139964) (#140468)

* Skipping auth call if ccm is not configured

* Addressing feedback

* Increasing log level

* Fixing test
jimczi pushed a commit to jimczi/elasticsearch that referenced this pull request Jan 12, 2026
…not configured (elastic#139964)

* Skipping auth call if ccm is not configured

* Addressing feedback

* Increasing log level

* Fixing test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auto-backport Automatically create backport pull requests when merged Feature:GenAI Features around GenAI >non-issue :SearchOrg/Inference Label for the Search Inference team Team:Search - Inference v9.3.0 v9.3.1 v9.4.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants