From 5c08cb2503fcadfb4cccef9094111e379ba4eac7 Mon Sep 17 00:00:00 2001 From: Jonathan Buttner Date: Thu, 30 Oct 2025 17:59:59 -0400 Subject: [PATCH 1/8] Starting CCM index --- .../xpack/inference/InferencePlugin.java | 11 ++++ .../services/elastic/ccm/CCMIndex.java | 59 ++++++++++++++++++ .../elastic/ccm/CCMStorageService.java | 13 ++++ .../services/elastic/ccm/CcmIndexModel.java | 62 +++++++++++++++++++ 4 files changed, 145 insertions(+) create mode 100644 x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndex.java create mode 100644 x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java create mode 100644 x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CcmIndexModel.java diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java index 60592c5dd1dbd..23e8f02a78aa1 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java @@ -134,6 +134,7 @@ import org.elasticsearch.xpack.inference.services.elastic.ElasticInferenceServiceComponents; import org.elasticsearch.xpack.inference.services.elastic.ElasticInferenceServiceSettings; import org.elasticsearch.xpack.inference.services.elastic.authorization.ElasticInferenceServiceAuthorizationRequestHandler; +import org.elasticsearch.xpack.inference.services.elastic.ccm.CCMIndex; import org.elasticsearch.xpack.inference.services.elasticsearch.ElasticsearchInternalService; import org.elasticsearch.xpack.inference.services.googleaistudio.GoogleAiStudioService; import org.elasticsearch.xpack.inference.services.googlevertexai.GoogleVertexAiService; @@ -518,6 +519,16 @@ public Collection getSystemIndexDescriptors(Settings sett .setSettings(getSecretsIndexSettings()) .setOrigin(ClientHelper.INFERENCE_ORIGIN) .setNetNew() + .build(), + SystemIndexDescriptor.builder() + .setType(SystemIndexDescriptor.Type.INTERNAL_MANAGED) + .setIndexPattern(CCMIndex.INDEX_PATTERN) + .setPrimaryIndex(CCMIndex.INDEX_NAME) + .setDescription("Contains Elastic Inference Service settings") + .setMappings(CCMIndex.mappings()) + .setSettings(CCMIndex.settings()) + .setOrigin(ClientHelper.INFERENCE_ORIGIN) + .setNetNew() .build() ); } diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndex.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndex.java new file mode 100644 index 0000000000000..eed05bfd837e1 --- /dev/null +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndex.java @@ -0,0 +1,59 @@ +/* + * 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.xpack.inference.services.elastic.ccm; + +import org.elasticsearch.cluster.metadata.IndexMetadata; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.indices.SystemIndexDescriptor; +import org.elasticsearch.xcontent.XContentBuilder; + +import java.io.IOException; +import java.io.UncheckedIOException; + +import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME; +import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder; + +public class CCMIndex { + + private CCMIndex() {} + + public static final String INDEX_NAME = ".ccm-inference"; + public static final String INDEX_PATTERN = INDEX_NAME + "*"; + + // Increment this version number when the mappings change + private static final int INDEX_MAPPING_VERSION = 1; + + public static Settings settings() { + return builder().build(); + } + + // Public to allow tests to create the index with custom settings + public static Settings.Builder builder() { + return Settings.builder().put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1).put(IndexMetadata.SETTING_AUTO_EXPAND_REPLICAS, "0-1"); + } + + public static XContentBuilder mappings() { + try { + return jsonBuilder().startObject() + .startObject(SINGLE_MAPPING_NAME) + .startObject("_meta") + .field(SystemIndexDescriptor.VERSION_META_KEY, INDEX_MAPPING_VERSION) + .endObject() + .field("dynamic", "strict") + .startObject("properties") + .startObject("api_key") + .field("type", "keyword") + .endObject() + .endObject() + .endObject() + .endObject(); + } catch (IOException e) { + throw new UncheckedIOException("Failed to build mappings for index " + INDEX_NAME, e); + } + } +} diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java new file mode 100644 index 0000000000000..d5c54abf754fa --- /dev/null +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java @@ -0,0 +1,13 @@ +/* + * 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.xpack.inference.services.elastic.ccm; + +public class CCMStorageService { + + public CCMStorageService() {} +} diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CcmIndexModel.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CcmIndexModel.java new file mode 100644 index 0000000000000..74bc066dd8f07 --- /dev/null +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CcmIndexModel.java @@ -0,0 +1,62 @@ +/* + * 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.xpack.inference.services.elastic.ccm; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.common.settings.SecureString; +import org.elasticsearch.xcontent.ConstructingObjectParser; +import org.elasticsearch.xcontent.ParseField; +import org.elasticsearch.xcontent.ToXContent; +import org.elasticsearch.xcontent.ToXContentObject; +import org.elasticsearch.xcontent.XContentBuilder; + +import java.io.IOException; +import java.util.Objects; + +import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg; + +public record CcmIndexModel(SecureString apiKey) implements Writeable, ToXContentObject { + + private static final String API_KEY_FIELD = "api_key"; + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( + CcmIndexModel.class.getSimpleName(), + true, + args -> new CcmIndexModel(new SecureString(((String) args[0]).toCharArray())) + ); + + static { + PARSER.declareString(constructorArg(), new ParseField(API_KEY_FIELD)); + } + + public static CcmIndexModel parse(org.elasticsearch.xcontent.XContentParser parser) throws IOException { + return PARSER.parse(parser, null); + } + + CcmIndexModel(String apiKey) { + this(new SecureString(Objects.requireNonNull(apiKey).toCharArray())); + } + + public CcmIndexModel(StreamInput in) throws IOException { + this(in.readSecureString()); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeSecureString(apiKey); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException { + builder.startObject(); + builder.field(API_KEY_FIELD, apiKey.toString()); + builder.endObject(); + return builder; + } +} From 5935f7252d8e3db29a35d117827de3485c8e7b09 Mon Sep 17 00:00:00 2001 From: Jonathan Buttner Date: Mon, 3 Nov 2025 14:29:31 -0500 Subject: [PATCH 2/8] Renaming --- .../elastic/ccm/{CcmIndexModel.java => CCMIndexModel.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/{CcmIndexModel.java => CCMIndexModel.java} (100%) diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CcmIndexModel.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndexModel.java similarity index 100% rename from x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CcmIndexModel.java rename to x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndexModel.java From 6e2efe6efbcb226c9c13a3b165da3a52149fff43 Mon Sep 17 00:00:00 2001 From: Jonathan Buttner Date: Mon, 3 Nov 2025 17:51:46 -0500 Subject: [PATCH 3/8] Building request --- .../ccm/{CCMIndexModel.java => CCMModel.java} | 14 ++++---- .../elastic/ccm/CCMStorageService.java | 33 ++++++++++++++++++- 2 files changed, 39 insertions(+), 8 deletions(-) rename x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/{CCMIndexModel.java => CCMModel.java} (75%) diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndexModel.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMModel.java similarity index 75% rename from x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndexModel.java rename to x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMModel.java index 74bc066dd8f07..de2af8b8130b5 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndexModel.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMModel.java @@ -22,28 +22,28 @@ import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg; -public record CcmIndexModel(SecureString apiKey) implements Writeable, ToXContentObject { +public record CCMModel(SecureString apiKey) implements Writeable, ToXContentObject { private static final String API_KEY_FIELD = "api_key"; - private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( - CcmIndexModel.class.getSimpleName(), + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( + CCMModel.class.getSimpleName(), true, - args -> new CcmIndexModel(new SecureString(((String) args[0]).toCharArray())) + args -> new CCMModel(new SecureString(((String) args[0]).toCharArray())) ); static { PARSER.declareString(constructorArg(), new ParseField(API_KEY_FIELD)); } - public static CcmIndexModel parse(org.elasticsearch.xcontent.XContentParser parser) throws IOException { + public static CCMModel parse(org.elasticsearch.xcontent.XContentParser parser) throws IOException { return PARSER.parse(parser, null); } - CcmIndexModel(String apiKey) { + CCMModel(String apiKey) { this(new SecureString(Objects.requireNonNull(apiKey).toCharArray())); } - public CcmIndexModel(StreamInput in) throws IOException { + public CCMModel(StreamInput in) throws IOException { this(in.readSecureString()); } diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java index d5c54abf754fa..9b9f5a3e574dc 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java @@ -7,7 +7,38 @@ package org.elasticsearch.xpack.inference.services.elastic.ccm; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.elasticsearch.action.support.WriteRequest; +import org.elasticsearch.client.internal.Client; +import org.elasticsearch.client.internal.OriginSettingClient; +import org.elasticsearch.xcontent.XContentFactory; +import org.elasticsearch.xpack.core.ClientHelper; + +import java.io.IOException; + public class CCMStorageService { - public CCMStorageService() {} + private static final Logger logger = LogManager.getLogger(CCMStorageService.class); + private static final String CCM_DOC_ID = "ccm_config"; + + private final Client client; + + public CCMStorageService(Client client) { + this.client = new OriginSettingClient(client, ClientHelper.INFERENCE_ORIGIN); + } + + public void store(CCMModel model) { + try (var xContentBuilder = XContentFactory.jsonBuilder()) { + var source = model.toXContent(xContentBuilder, null); + var builder = client.prepareIndex() + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .setIndex(CCMIndex.INDEX_NAME) + .setSource(source).setId(CCM_DOC_ID).execute(); + + } catch (IOException e) { + + } + + } } From 371a086aa67586a8b6bad928809193a9a1f41bb8 Mon Sep 17 00:00:00 2001 From: Jonathan Buttner Date: Tue, 4 Nov 2025 11:15:59 -0500 Subject: [PATCH 4/8] Adding feature flag and tests --- .../test/cluster/FeatureFlag.java | 3 +- .../integration/CCMStorageServiceIT.java | 113 ++++++++++++++++++ .../xpack/inference/InferencePlugin.java | 80 ++++++++----- .../services/elastic/ccm/CCMFeatureFlag.java | 22 ++++ .../services/elastic/ccm/CCMModel.java | 14 ++- .../elastic/ccm/CCMStorageService.java | 51 ++++++-- .../services/elastic/ccm/CCMIndexTests.java | 36 ++++++ .../services/elastic/ccm/CCMModelTests.java | 82 +++++++++++++ 8 files changed, 357 insertions(+), 44 deletions(-) create mode 100644 x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/CCMStorageServiceIT.java create mode 100644 x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMFeatureFlag.java create mode 100644 x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndexTests.java create mode 100644 x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMModelTests.java diff --git a/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/FeatureFlag.java b/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/FeatureFlag.java index 168b5a15743c1..a1a0486aecfc8 100644 --- a/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/FeatureFlag.java +++ b/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/FeatureFlag.java @@ -26,7 +26,8 @@ public enum FeatureFlag { Version.fromString("9.2.0"), null ), - RANDOM_SAMPLING("es.random_sampling_feature_flag_enabled=true", Version.fromString("9.2.0"), null); + RANDOM_SAMPLING("es.random_sampling_feature_flag_enabled=true", Version.fromString("9.2.0"), null), + INFERENCE_API_CCM("es.inference_api_ccm_feature_flag_enabled=true", Version.fromString("9.3.0"), null); public final String systemProperty; public final Version from; diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/CCMStorageServiceIT.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/CCMStorageServiceIT.java new file mode 100644 index 0000000000000..1d21ce43dd9fe --- /dev/null +++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/CCMStorageServiceIT.java @@ -0,0 +1,113 @@ +/* + * 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.xpack.inference.integration; + +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.ResourceNotFoundException; +import org.elasticsearch.action.DocWriteResponse; +import org.elasticsearch.action.support.PlainActionFuture; +import org.elasticsearch.action.support.WriteRequest; +import org.elasticsearch.common.settings.SecureString; +import org.elasticsearch.core.TimeValue; +import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.test.ESSingleNodeTestCase; +import org.elasticsearch.xcontent.XContentType; +import org.elasticsearch.xpack.inference.LocalStateInferencePlugin; +import org.elasticsearch.xpack.inference.services.elastic.ccm.CCMIndex; +import org.elasticsearch.xpack.inference.services.elastic.ccm.CCMModel; +import org.elasticsearch.xpack.inference.services.elastic.ccm.CCMStorageService; +import org.junit.Before; + +import java.util.Collection; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; + +public class CCMStorageServiceIT extends ESSingleNodeTestCase { + private CCMStorageService ccmStorageService; + + @Before + public void createComponents() { + ccmStorageService = node().injector().getInstance(CCMStorageService.class); + } + + @Override + protected Collection> getPlugins() { + return pluginList(LocalStateInferencePlugin.class); + } + + public void testStoreAndGetCCMModel() { + var ccmModel = new CCMModel(new SecureString("secret".toCharArray())); + var storeListener = new PlainActionFuture(); + ccmStorageService.store(ccmModel, storeListener); + + assertNull(storeListener.actionGet(TimeValue.THIRTY_SECONDS)); + + var getListener = new PlainActionFuture(); + ccmStorageService.get(getListener); + + assertThat(getListener.actionGet(TimeValue.THIRTY_SECONDS), is(ccmModel)); + } + + public void testGet_ThrowsResourceNotFoundException_WhenCCMIndexDoesNotExist() { + var getListener = new PlainActionFuture(); + ccmStorageService.get(getListener); + + var exception = expectThrows( + ResourceNotFoundException.class, + () -> getListener.actionGet(TimeValue.THIRTY_SECONDS) + ); + assertThat(exception.getMessage(), is("CCM configuration not found")); + } + + public void testGet_ThrowsResourceNotFoundException_WhenCCMConfigurationDocumentDoesNotExist() { + storeCorruptCCMModel("id"); + + var getListener = new PlainActionFuture(); + ccmStorageService.get(getListener); + + var exception = expectThrows( + ResourceNotFoundException.class, + () -> getListener.actionGet(TimeValue.THIRTY_SECONDS) + ); + assertThat(exception.getMessage(), is("CCM configuration not found")); + } + + public void testGetCCMModel_ThrowsException_WhenStoredModelIsCorrupted() { + storeCorruptCCMModel(CCMStorageService.CCM_DOC_ID); + + var getListener = new PlainActionFuture(); + ccmStorageService.get(getListener); + + var exception = expectThrows( + ElasticsearchException.class, + () -> getListener.actionGet(TimeValue.THIRTY_SECONDS) + ); + assertThat(exception.getMessage(), containsString("Failed to retrieve CCM configuration")); + assertThat(exception.getCause().getMessage(), containsString("Required [api_key]")); + } + + private void storeCorruptCCMModel(String id) { + var corruptedSource = """ + { + + } + """; + + var response = client().prepareIndex() + .setSource(corruptedSource, XContentType.JSON) + .setIndex(CCMIndex.INDEX_NAME) + .setId(id) + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .execute().actionGet(TimeValue.THIRTY_SECONDS); + + assertThat(response.getResult(), is(DocWriteResponse.Result.CREATED)); + } + + +} diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java index 23e8f02a78aa1..cef4bd7a718ae 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java @@ -134,7 +134,9 @@ import org.elasticsearch.xpack.inference.services.elastic.ElasticInferenceServiceComponents; import org.elasticsearch.xpack.inference.services.elastic.ElasticInferenceServiceSettings; import org.elasticsearch.xpack.inference.services.elastic.authorization.ElasticInferenceServiceAuthorizationRequestHandler; +import org.elasticsearch.xpack.inference.services.elastic.ccm.CCMFeatureFlag; import org.elasticsearch.xpack.inference.services.elastic.ccm.CCMIndex; +import org.elasticsearch.xpack.inference.services.elastic.ccm.CCMStorageService; import org.elasticsearch.xpack.inference.services.elasticsearch.ElasticsearchInternalService; import org.elasticsearch.xpack.inference.services.googleaistudio.GoogleAiStudioService; import org.elasticsearch.xpack.inference.services.googlevertexai.GoogleVertexAiService; @@ -161,6 +163,7 @@ import java.util.Set; import java.util.function.Predicate; import java.util.function.Supplier; +import java.util.stream.Stream; import static java.util.Collections.singletonList; import static org.elasticsearch.xpack.inference.action.filter.ShardBulkInferenceActionFilter.INDICES_INFERENCE_BATCH_SIZE; @@ -398,6 +401,10 @@ public Collection createComponents(PluginServices services) { ) ); + if (CCMFeatureFlag.FEATURE_FLAG.isEnabled()) { + components.add(new CCMStorageService(services.client())); + } + return components; } @@ -486,6 +493,20 @@ public List getNamedXContent() { @Override public Collection getSystemIndexDescriptors(Settings settings) { + List ccmIndexDescriptor = CCMFeatureFlag.FEATURE_FLAG.isEnabled() + ? List.of( + SystemIndexDescriptor.builder() + .setType(SystemIndexDescriptor.Type.INTERNAL_MANAGED) + .setIndexPattern(CCMIndex.INDEX_PATTERN) + .setPrimaryIndex(CCMIndex.INDEX_NAME) + .setDescription("Contains Elastic Inference Service Cloud Connected Mode settings") + .setMappings(CCMIndex.mappings()) + .setSettings(CCMIndex.settings()) + .setOrigin(ClientHelper.INFERENCE_ORIGIN) + .setNetNew() + .build() + ) + : List.of(); var inferenceIndexV1Descriptor = SystemIndexDescriptor.builder() .setType(SystemIndexDescriptor.Type.INTERNAL_MANAGED) @@ -498,39 +519,32 @@ public Collection getSystemIndexDescriptors(Settings sett .setOrigin(ClientHelper.INFERENCE_ORIGIN) .build(); - return List.of( - SystemIndexDescriptor.builder() - .setType(SystemIndexDescriptor.Type.INTERNAL_MANAGED) - .setIndexPattern(InferenceIndex.INDEX_PATTERN) - .setAliasName(InferenceIndex.INDEX_ALIAS) - .setPrimaryIndex(InferenceIndex.INDEX_NAME) - .setDescription("Contains inference service and model configuration") - .setMappings(InferenceIndex.mappings()) - .setSettings(getIndexSettings()) - .setOrigin(ClientHelper.INFERENCE_ORIGIN) - .setPriorSystemIndexDescriptors(List.of(inferenceIndexV1Descriptor)) - .build(), - SystemIndexDescriptor.builder() - .setType(SystemIndexDescriptor.Type.INTERNAL_MANAGED) - .setIndexPattern(InferenceSecretsIndex.INDEX_PATTERN) - .setPrimaryIndex(InferenceSecretsIndex.INDEX_NAME) - .setDescription("Contains inference service secrets") - .setMappings(InferenceSecretsIndex.mappings()) - .setSettings(getSecretsIndexSettings()) - .setOrigin(ClientHelper.INFERENCE_ORIGIN) - .setNetNew() - .build(), - SystemIndexDescriptor.builder() - .setType(SystemIndexDescriptor.Type.INTERNAL_MANAGED) - .setIndexPattern(CCMIndex.INDEX_PATTERN) - .setPrimaryIndex(CCMIndex.INDEX_NAME) - .setDescription("Contains Elastic Inference Service settings") - .setMappings(CCMIndex.mappings()) - .setSettings(CCMIndex.settings()) - .setOrigin(ClientHelper.INFERENCE_ORIGIN) - .setNetNew() - .build() - ); + return Stream.of( + List.of( + SystemIndexDescriptor.builder() + .setType(SystemIndexDescriptor.Type.INTERNAL_MANAGED) + .setIndexPattern(InferenceIndex.INDEX_PATTERN) + .setAliasName(InferenceIndex.INDEX_ALIAS) + .setPrimaryIndex(InferenceIndex.INDEX_NAME) + .setDescription("Contains inference service and model configuration") + .setMappings(InferenceIndex.mappings()) + .setSettings(getIndexSettings()) + .setOrigin(ClientHelper.INFERENCE_ORIGIN) + .setPriorSystemIndexDescriptors(List.of(inferenceIndexV1Descriptor)) + .build(), + SystemIndexDescriptor.builder() + .setType(SystemIndexDescriptor.Type.INTERNAL_MANAGED) + .setIndexPattern(InferenceSecretsIndex.INDEX_PATTERN) + .setPrimaryIndex(InferenceSecretsIndex.INDEX_NAME) + .setDescription("Contains inference service secrets") + .setMappings(InferenceSecretsIndex.mappings()) + .setSettings(getSecretsIndexSettings()) + .setOrigin(ClientHelper.INFERENCE_ORIGIN) + .setNetNew() + .build() + ), + ccmIndexDescriptor + ).flatMap(List::stream).toList(); } // Overridable for tests diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMFeatureFlag.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMFeatureFlag.java new file mode 100644 index 0000000000000..7f57caa077fdc --- /dev/null +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMFeatureFlag.java @@ -0,0 +1,22 @@ +/* + * 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.xpack.inference.services.elastic.ccm; + +import org.elasticsearch.common.util.FeatureFlag; + +public class CCMFeatureFlag { + + /** + * {@link org.elasticsearch.xpack.inference.services.custom.CustomService} feature flag. When the feature is complete, + * this flag will be removed. + * Enable feature via JVM option: `-Des.inference_api_ccm_feature_flag_enabled=true`. + */ + public static final FeatureFlag FEATURE_FLAG = new FeatureFlag("inference_api_ccm"); + + private CCMFeatureFlag() {} +} diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMModel.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMModel.java index de2af8b8130b5..15f681f144f6d 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMModel.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMModel.java @@ -7,15 +7,19 @@ package org.elasticsearch.xpack.inference.services.elastic.ccm; +import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.settings.SecureString; +import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.xcontent.ConstructingObjectParser; import org.elasticsearch.xcontent.ParseField; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.xcontent.XContentParserConfiguration; +import org.elasticsearch.xcontent.XContentType; import java.io.IOException; import java.util.Objects; @@ -39,8 +43,8 @@ public static CCMModel parse(org.elasticsearch.xcontent.XContentParser parser) t return PARSER.parse(parser, null); } - CCMModel(String apiKey) { - this(new SecureString(Objects.requireNonNull(apiKey).toCharArray())); + public CCMModel { + Objects.requireNonNull(apiKey); } public CCMModel(StreamInput in) throws IOException { @@ -59,4 +63,10 @@ public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params par builder.endObject(); return builder; } + + public static CCMModel fromXContentBytes(BytesReference bytes) throws IOException { + try (var parser = XContentHelper.createParserNotCompressed(XContentParserConfiguration.EMPTY, bytes, XContentType.JSON)) { + return parse(parser); + } + } } diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java index 9b9f5a3e574dc..1e89cd1b3d02b 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java @@ -9,9 +9,15 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.ResourceNotFoundException; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.support.WriteRequest; import org.elasticsearch.client.internal.Client; import org.elasticsearch.client.internal.OriginSettingClient; +import org.elasticsearch.index.IndexNotFoundException; +import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.XContentFactory; import org.elasticsearch.xpack.core.ClientHelper; @@ -20,7 +26,7 @@ public class CCMStorageService { private static final Logger logger = LogManager.getLogger(CCMStorageService.class); - private static final String CCM_DOC_ID = "ccm_config"; + public static final String CCM_DOC_ID = "ccm_config"; private final Client client; @@ -28,17 +34,46 @@ public CCMStorageService(Client client) { this.client = new OriginSettingClient(client, ClientHelper.INFERENCE_ORIGIN); } - public void store(CCMModel model) { - try (var xContentBuilder = XContentFactory.jsonBuilder()) { - var source = model.toXContent(xContentBuilder, null); - var builder = client.prepareIndex() + public void store(CCMModel model, ActionListener listener) { + try { + client.prepareIndex() .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) .setIndex(CCMIndex.INDEX_NAME) - .setSource(source).setId(CCM_DOC_ID).execute(); - - } catch (IOException e) { + .setSource(createSource(model)) + .setId(CCM_DOC_ID) + .execute(listener.delegateFailureIgnoreResponseAndWrap(delegate -> delegate.onResponse(null))); + } catch (Exception e) { + logger.warn("Failed to persist CCM configurations", e); + listener.onFailure(e); + } + } + private XContentBuilder createSource(CCMModel model) throws IOException { + try (var xContentBuilder = XContentFactory.jsonBuilder()) { + return model.toXContent(xContentBuilder, null); } + } + + public void get(ActionListener listener) { + var ccmConfigNotFound = new ResourceNotFoundException("CCM configuration not found"); + + var getResponseListener = ActionListener.wrap(response -> { + if (response.isExists() == false) { + listener.onFailure(ccmConfigNotFound); + return; + } + listener.onResponse(CCMModel.fromXContentBytes(response.getSourceAsBytesRef())); + }, e -> { + if (e instanceof IndexNotFoundException) { + listener.onFailure(ccmConfigNotFound); + return; + } + + var message = "Failed to retrieve CCM configuration"; + logger.warn(message, e); + listener.onFailure(new ElasticsearchException(message, e)); + }); + client.prepareGet().setIndex(CCMIndex.INDEX_NAME).setId(CCM_DOC_ID).execute(getResponseListener); } } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndexTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndexTests.java new file mode 100644 index 0000000000000..981cafb51b148 --- /dev/null +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndexTests.java @@ -0,0 +1,36 @@ +/* + * 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.xpack.inference.services.elastic.ccm; + +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.test.ESTestCase; + +import java.io.IOException; + +import static org.hamcrest.CoreMatchers.is; + +public class CCMIndexTests extends ESTestCase { + public void testMappings() throws IOException { + assertThat(Strings.toString(CCMIndex.mappings()), is(XContentHelper.stripWhitespace(""" + { + "_doc": { + "_meta": { + "managed_index_mappings_version": 1 + }, + "dynamic": "strict", + "properties": { + "api_key": { + "type": "keyword" + } + } + } + } + """))); + } +} diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMModelTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMModelTests.java new file mode 100644 index 0000000000000..dfd945b48c314 --- /dev/null +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMModelTests.java @@ -0,0 +1,82 @@ +/* + * 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.xpack.inference.services.elastic.ccm; + +import org.elasticsearch.TransportVersion; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.bytes.BytesArray; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.common.settings.SecureString; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.xcontent.XContentFactory; +import org.elasticsearch.xcontent.XContentType; +import org.elasticsearch.xpack.core.ml.AbstractBWCWireSerializationTestCase; + +import java.io.IOException; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; + +public class CCMModelTests extends AbstractBWCWireSerializationTestCase { + + public void testToXContent() throws IOException { + var model = new CCMModel(new SecureString("secret".toCharArray())); + var builder = XContentFactory.contentBuilder(XContentType.JSON); + model.toXContent(builder, null); + + assertThat(Strings.toString(builder), is(XContentHelper.stripWhitespace(""" + { + "api_key": "secret" + } + """))); + } + + public void testFromXContentBytes() throws IOException { + String json = """ + { + "api_key": "test_key" + } + """; + var model = CCMModel.fromXContentBytes(new BytesArray(json)); + + assertThat(model.apiKey().toString(), is("test_key")); + } + + public void testFromXContentBytes_ThrowsException_WhenApiKeyMissing() { + String json = """ + { + } + """; + var exception = expectThrows( + IllegalArgumentException.class, + () -> CCMModel.fromXContentBytes(new BytesArray(json)) + ); + assertThat(exception.getMessage(), containsString("Required [api_key]")); + } + + @Override + protected CCMModel mutateInstanceForVersion(CCMModel instance, TransportVersion version) { + return instance; + } + + @Override + protected Writeable.Reader instanceReader() { + return CCMModel::new; + } + + @Override + protected CCMModel createTestInstance() { + return new CCMModel(new SecureString(randomAlphaOfLength(10).toCharArray())); + } + + @Override + protected CCMModel mutateInstance(CCMModel instance) throws IOException { + var originalString = instance.apiKey().toString(); + return new CCMModel(new SecureString((originalString + "modified").toCharArray())); + } +} From e691bd21dcf976839f9eff6782853b65cbfedd9d Mon Sep 17 00:00:00 2001 From: elasticsearchmachine Date: Tue, 4 Nov 2025 16:34:54 +0000 Subject: [PATCH 5/8] [CI] Auto commit changes from spotless --- .../integration/CCMStorageServiceIT.java | 19 +++++-------------- .../services/elastic/ccm/CCMModelTests.java | 5 +---- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/CCMStorageServiceIT.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/CCMStorageServiceIT.java index 1d21ce43dd9fe..b17c91d785e16 100644 --- a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/CCMStorageServiceIT.java +++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/CCMStorageServiceIT.java @@ -58,10 +58,7 @@ public void testGet_ThrowsResourceNotFoundException_WhenCCMIndexDoesNotExist() { var getListener = new PlainActionFuture(); ccmStorageService.get(getListener); - var exception = expectThrows( - ResourceNotFoundException.class, - () -> getListener.actionGet(TimeValue.THIRTY_SECONDS) - ); + var exception = expectThrows(ResourceNotFoundException.class, () -> getListener.actionGet(TimeValue.THIRTY_SECONDS)); assertThat(exception.getMessage(), is("CCM configuration not found")); } @@ -71,10 +68,7 @@ public void testGet_ThrowsResourceNotFoundException_WhenCCMConfigurationDocument var getListener = new PlainActionFuture(); ccmStorageService.get(getListener); - var exception = expectThrows( - ResourceNotFoundException.class, - () -> getListener.actionGet(TimeValue.THIRTY_SECONDS) - ); + var exception = expectThrows(ResourceNotFoundException.class, () -> getListener.actionGet(TimeValue.THIRTY_SECONDS)); assertThat(exception.getMessage(), is("CCM configuration not found")); } @@ -84,10 +78,7 @@ public void testGetCCMModel_ThrowsException_WhenStoredModelIsCorrupted() { var getListener = new PlainActionFuture(); ccmStorageService.get(getListener); - var exception = expectThrows( - ElasticsearchException.class, - () -> getListener.actionGet(TimeValue.THIRTY_SECONDS) - ); + var exception = expectThrows(ElasticsearchException.class, () -> getListener.actionGet(TimeValue.THIRTY_SECONDS)); assertThat(exception.getMessage(), containsString("Failed to retrieve CCM configuration")); assertThat(exception.getCause().getMessage(), containsString("Required [api_key]")); } @@ -104,10 +95,10 @@ private void storeCorruptCCMModel(String id) { .setIndex(CCMIndex.INDEX_NAME) .setId(id) .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) - .execute().actionGet(TimeValue.THIRTY_SECONDS); + .execute() + .actionGet(TimeValue.THIRTY_SECONDS); assertThat(response.getResult(), is(DocWriteResponse.Result.CREATED)); } - } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMModelTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMModelTests.java index dfd945b48c314..0b90af3b77fcf 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMModelTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMModelTests.java @@ -52,10 +52,7 @@ public void testFromXContentBytes_ThrowsException_WhenApiKeyMissing() { { } """; - var exception = expectThrows( - IllegalArgumentException.class, - () -> CCMModel.fromXContentBytes(new BytesArray(json)) - ); + var exception = expectThrows(IllegalArgumentException.class, () -> CCMModel.fromXContentBytes(new BytesArray(json))); assertThat(exception.getMessage(), containsString("Required [api_key]")); } From 6df47f8f61c8a032df176e952045a40dd20ce41b Mon Sep 17 00:00:00 2001 From: Jonathan Buttner Date: Tue, 4 Nov 2025 14:16:49 -0500 Subject: [PATCH 6/8] Adding alias --- .../java/org/elasticsearch/xpack/inference/InferencePlugin.java | 1 + .../xpack/inference/services/elastic/ccm/CCMIndex.java | 1 + 2 files changed, 2 insertions(+) diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java index 9742ca79cc57a..b477c151906b5 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java @@ -504,6 +504,7 @@ public Collection getSystemIndexDescriptors(Settings sett SystemIndexDescriptor.builder() .setType(SystemIndexDescriptor.Type.INTERNAL_MANAGED) .setIndexPattern(CCMIndex.INDEX_PATTERN) + .setAliasName(CCMIndex.INDEX_ALIAS) .setPrimaryIndex(CCMIndex.INDEX_NAME) .setDescription("Contains Elastic Inference Service Cloud Connected Mode settings") .setMappings(CCMIndex.mappings()) diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndex.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndex.java index eed05bfd837e1..f01bbe74015f2 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndex.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndex.java @@ -24,6 +24,7 @@ private CCMIndex() {} public static final String INDEX_NAME = ".ccm-inference"; public static final String INDEX_PATTERN = INDEX_NAME + "*"; + public static final String INDEX_ALIAS = ".ccm-inference-alias"; // Increment this version number when the mappings change private static final int INDEX_MAPPING_VERSION = 1; From 499da1e983b219476fd9a9ce6859b06a2f866922 Mon Sep 17 00:00:00 2001 From: Jonathan Buttner Date: Tue, 4 Nov 2025 15:18:49 -0500 Subject: [PATCH 7/8] Using search instead of get in case of rollover --- .../xpack/inference/InferencePlugin.java | 1 - .../inference/services/elastic/ccm/CCMIndex.java | 1 - .../services/elastic/ccm/CCMStorageService.java | 16 +++++++++++----- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java index b477c151906b5..9742ca79cc57a 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferencePlugin.java @@ -504,7 +504,6 @@ public Collection getSystemIndexDescriptors(Settings sett SystemIndexDescriptor.builder() .setType(SystemIndexDescriptor.Type.INTERNAL_MANAGED) .setIndexPattern(CCMIndex.INDEX_PATTERN) - .setAliasName(CCMIndex.INDEX_ALIAS) .setPrimaryIndex(CCMIndex.INDEX_NAME) .setDescription("Contains Elastic Inference Service Cloud Connected Mode settings") .setMappings(CCMIndex.mappings()) diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndex.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndex.java index f01bbe74015f2..eed05bfd837e1 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndex.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMIndex.java @@ -24,7 +24,6 @@ private CCMIndex() {} public static final String INDEX_NAME = ".ccm-inference"; public static final String INDEX_PATTERN = INDEX_NAME + "*"; - public static final String INDEX_ALIAS = ".ccm-inference-alias"; // Increment this version number when the mappings change private static final int INDEX_MAPPING_VERSION = 1; diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java index 1e89cd1b3d02b..d08eea6d01caa 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java @@ -12,11 +12,12 @@ import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ResourceNotFoundException; import org.elasticsearch.action.ActionListener; -import org.elasticsearch.action.get.GetResponse; +import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.support.WriteRequest; import org.elasticsearch.client.internal.Client; import org.elasticsearch.client.internal.OriginSettingClient; import org.elasticsearch.index.IndexNotFoundException; +import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.XContentFactory; import org.elasticsearch.xpack.core.ClientHelper; @@ -57,12 +58,14 @@ private XContentBuilder createSource(CCMModel model) throws IOException { public void get(ActionListener listener) { var ccmConfigNotFound = new ResourceNotFoundException("CCM configuration not found"); - var getResponseListener = ActionListener.wrap(response -> { - if (response.isExists() == false) { + var searchListener = ActionListener.wrap(searchResponse -> { + if (searchResponse.getHits().getHits().length == 0) { listener.onFailure(ccmConfigNotFound); return; } - listener.onResponse(CCMModel.fromXContentBytes(response.getSourceAsBytesRef())); + + assert searchResponse.getHits().getHits().length == 1; + listener.onResponse(CCMModel.fromXContentBytes(searchResponse.getHits().getHits()[0].getSourceRef())); }, e -> { if (e instanceof IndexNotFoundException) { listener.onFailure(ccmConfigNotFound); @@ -74,6 +77,9 @@ public void get(ActionListener listener) { listener.onFailure(new ElasticsearchException(message, e)); }); - client.prepareGet().setIndex(CCMIndex.INDEX_NAME).setId(CCM_DOC_ID).execute(getResponseListener); + client.prepareSearch(CCMIndex.INDEX_PATTERN) + .setSize(1) + .setTrackTotalHits(false) + .setQuery(QueryBuilders.idsQuery().addIds(CCM_DOC_ID)).execute(searchListener); } } From 80d2433894572cd446cb07aec355237c60ee0cf7 Mon Sep 17 00:00:00 2001 From: elasticsearchmachine Date: Tue, 4 Nov 2025 20:24:34 +0000 Subject: [PATCH 8/8] [CI] Auto commit changes from spotless --- .../inference/services/elastic/ccm/CCMStorageService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java index d08eea6d01caa..bf78a5b49485f 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ccm/CCMStorageService.java @@ -80,6 +80,7 @@ public void get(ActionListener listener) { client.prepareSearch(CCMIndex.INDEX_PATTERN) .setSize(1) .setTrackTotalHits(false) - .setQuery(QueryBuilders.idsQuery().addIds(CCM_DOC_ID)).execute(searchListener); + .setQuery(QueryBuilders.idsQuery().addIds(CCM_DOC_ID)) + .execute(searchListener); } }