From e640ce3c89ed02862e08e142c0b79e97156602bf Mon Sep 17 00:00:00 2001 From: Jedr Blaszyk Date: Fri, 29 Nov 2024 18:33:47 +0100 Subject: [PATCH 1/2] [Connector APIs] Enforce manage connector index prefix --- .../entsearch/connector/10_connector_put.yml | 17 ++- .../130_connector_update_index_name.yml | 42 ++++++ .../connector/140_connector_update_native.yml | 44 +++++- .../entsearch/connector/15_connector_post.yml | 16 ++- .../entsearch/connector/20_connector_list.yml | 70 +++++----- .../connector/ConnectorIndexService.java | 131 +++++++++++++----- .../connector/ConnectorTemplateRegistry.java | 2 + .../action/ConnectorActionRequest.java | 25 ++++ .../connector/action/PostConnectorAction.java | 4 + .../connector/action/PutConnectorAction.java | 4 + .../connector/ConnectorIndexServiceTests.java | 41 +++++- .../connector/ConnectorTestUtils.java | 8 ++ .../action/PostConnectorActionTests.java | 20 ++- .../action/PutConnectorActionTests.java | 21 ++- 14 files changed, 365 insertions(+), 80 deletions(-) diff --git a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/10_connector_put.yml b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/10_connector_put.yml index b0f850d09f76d..c2334fe29fc62 100644 --- a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/10_connector_put.yml +++ b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/10_connector_put.yml @@ -58,7 +58,7 @@ setup: connector.put: connector_id: test-connector-native body: - index_name: search-test + index_name: content-search-test is_native: true - match: { result: 'created' } @@ -68,7 +68,7 @@ setup: connector_id: test-connector-native - match: { id: test-connector-native } - - match: { index_name: search-test } + - match: { index_name: content-search-test } - match: { is_native: true } - match: { sync_now: false } - match: { status: needs_configuration } @@ -151,6 +151,19 @@ setup: is_native: false service_type: super-connector +--- +'Create Connector - Invalid Managed Connector Index Prefix': + - do: + catch: "bad_request" + connector.put: + connector_id: test-connector-test-managed + body: + index_name: wrong-prefix-index + name: my-connector + language: pl + is_native: true + service_type: super-connector + --- 'Create Connector - Id returned as part of response': - do: diff --git a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/130_connector_update_index_name.yml b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/130_connector_update_index_name.yml index 4ffa5435a3d7b..06136a887bd13 100644 --- a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/130_connector_update_index_name.yml +++ b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/130_connector_update_index_name.yml @@ -125,3 +125,45 @@ setup: connector_id: test-connector - match: { index_name: search-1-test } + + +--- +"Update Managed Connector Index Name": + - do: + connector.put: + connector_id: test-connector-1 + body: + is_native: true + service_type: super-connector + + - do: + connector.update_index_name: + connector_id: test-connector-1 + body: + index_name: content-search-2-test + + + - match: { result: updated } + + - do: + connector.get: + connector_id: test-connector-1 + + - match: { index_name: content-search-2-test } + + +--- +"Update Managed Connector Index Name - Bad Prefix": + - do: + connector.put: + connector_id: test-connector-2 + body: + is_native: true + service_type: super-connector + + - do: + catch: "bad_request" + connector.update_index_name: + connector_id: test-connector-2 + body: + index_name: wrong-prefix-search-2-test diff --git a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/140_connector_update_native.yml b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/140_connector_update_native.yml index 77c57532ad479..6811c3340ce42 100644 --- a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/140_connector_update_native.yml +++ b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/140_connector_update_native.yml @@ -7,7 +7,7 @@ setup: connector.put: connector_id: test-connector body: - index_name: search-1-test + index_name: content-search-1-test name: my-connector language: pl is_native: false @@ -29,7 +29,6 @@ setup: connector_id: test-connector - match: { is_native: true } - - match: { status: configured } - do: connector.update_native: @@ -44,7 +43,6 @@ setup: connector_id: test-connector - match: { is_native: false } - - match: { status: configured } --- "Update Connector Native - 404 when connector doesn't exist": @@ -75,3 +73,43 @@ setup: field_1: test field_2: something +--- +"Update Connector Native - changing connector to Elastic-managed wrong index name": + + - do: + connector.put: + connector_id: test-connector-1 + body: + is_native: false + index_name: super-connector + + - do: + catch: "bad_request" + connector.update_native: + connector_id: test-connector-1 + body: + is_native: true + +--- +"Update Connector Native - changing connector to Elastic-managed correct index name": + + - do: + connector.put: + connector_id: test-connector-1 + body: + is_native: false + index_name: content-super-connector + + - do: + connector.update_native: + connector_id: test-connector-1 + body: + is_native: true + + - match: { result: updated } + + - do: + connector.get: + connector_id: test-connector-1 + + - match: { is_native: true } diff --git a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/15_connector_post.yml b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/15_connector_post.yml index 1cbff6a35e18b..8299cf5aef0b8 100644 --- a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/15_connector_post.yml +++ b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/15_connector_post.yml @@ -71,7 +71,7 @@ setup: - do: connector.post: body: - index_name: search-test + index_name: content-search-test is_native: true - set: { id: id } @@ -82,7 +82,7 @@ setup: connector_id: $id - match: { id: $id } - - match: { index_name: search-test } + - match: { index_name: content-search-test } - match: { is_native: true } - match: { sync_now: false } - match: { status: needs_configuration } @@ -102,6 +102,18 @@ setup: is_native: false service_type: super-connector +--- +'Create Connector - Invalid Managed Connector Index Prefix': + - do: + catch: "bad_request" + connector.post: + body: + index_name: wrong-prefix-index + name: my-connector + language: pl + is_native: true + service_type: super-connector + --- 'Create Connector - Index name used by another connector': - do: diff --git a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/20_connector_list.yml b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/20_connector_list.yml index 10e4620ca5603..697b0ee419181 100644 --- a/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/20_connector_list.yml +++ b/x-pack/plugin/ent-search/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/entsearch/connector/20_connector_list.yml @@ -26,7 +26,7 @@ setup: connector.put: connector_id: connector-b body: - index_name: search-2-test + index_name: content-search-2-test name: my-connector-2 language: en is_native: true @@ -40,13 +40,13 @@ setup: - match: { count: 3 } # Alphabetical order by index_name for results - - match: { results.0.id: "connector-a" } - - match: { results.0.index_name: "search-1-test" } - - match: { results.0.language: "pl" } + - match: { results.0.id: "connector-b" } + - match: { results.0.index_name: "content-search-2-test" } + - match: { results.0.language: "en" } - - match: { results.1.id: "connector-b" } - - match: { results.1.index_name: "search-2-test" } - - match: { results.1.language: "en" } + - match: { results.1.id: "connector-a" } + - match: { results.1.index_name: "search-1-test" } + - match: { results.1.language: "pl" } - match: { results.2.id: "connector-c" } - match: { results.2.index_name: "search-3-test" } @@ -62,9 +62,9 @@ setup: - match: { count: 3 } # Alphabetical order by index_name for results - - match: { results.0.id: "connector-b" } - - match: { results.0.index_name: "search-2-test" } - - match: { results.0.language: "en" } + - match: { results.0.id: "connector-a" } + - match: { results.0.index_name: "search-1-test" } + - match: { results.0.language: "pl" } - match: { results.1.id: "connector-c" } - match: { results.1.index_name: "search-3-test" } @@ -79,13 +79,13 @@ setup: - match: { count: 3 } # Alphabetical order by index_name for results - - match: { results.0.id: "connector-a" } - - match: { results.0.index_name: "search-1-test" } - - match: { results.0.language: "pl" } + - match: { results.0.id: "connector-b" } + - match: { results.0.index_name: "content-search-2-test" } + - match: { results.0.language: "en" } - - match: { results.1.id: "connector-b" } - - match: { results.1.index_name: "search-2-test" } - - match: { results.1.language: "en" } + - match: { results.1.id: "connector-a" } + - match: { results.1.index_name: "search-1-test" } + - match: { results.1.language: "pl" } --- "List Connector - empty": @@ -118,11 +118,11 @@ setup: - do: connector.list: - index_name: search-1-test,search-2-test + index_name: search-1-test,content-search-2-test - match: { count: 2 } - - match: { results.0.index_name: "search-1-test" } - - match: { results.1.index_name: "search-2-test" } + - match: { results.0.index_name: "content-search-2-test" } + - match: { results.1.index_name: "search-1-test" } --- @@ -147,8 +147,8 @@ setup: connector_name: my-connector-1,my-connector-2 - match: { count: 2 } - - match: { results.0.name: "my-connector-1" } - - match: { results.1.name: "my-connector-2" } + - match: { results.0.name: "my-connector-2" } + - match: { results.1.name: "my-connector-1" } --- @@ -156,10 +156,10 @@ setup: - do: connector.list: connector_name: my-connector-1,my-connector-2 - index_name: search-2-test + index_name: content-search-2-test - match: { count: 1 } - - match: { results.0.index_name: "search-2-test" } + - match: { results.0.index_name: "content-search-2-test" } - match: { results.0.name: "my-connector-2" } @@ -230,13 +230,13 @@ setup: - match: { count: 3 } # Alphabetical order by index_name for results - - match: { results.0.id: "connector-a" } - - match: { results.0.index_name: "search-1-test" } - - match: { results.0.language: "pl" } + - match: { results.0.id: "connector-b" } + - match: { results.0.index_name: "content-search-2-test" } + - match: { results.0.language: "en" } - - match: { results.1.id: "connector-b" } - - match: { results.1.index_name: "search-2-test" } - - match: { results.1.language: "en" } + - match: { results.1.id: "connector-a" } + - match: { results.1.index_name: "search-1-test" } + - match: { results.1.language: "pl" } - match: { results.2.id: "connector-c" } - match: { results.2.index_name: "search-3-test" } @@ -255,13 +255,13 @@ setup: - match: { count: 3 } # Alphabetical order by index_name for results - - match: { results.0.id: "connector-a" } - - match: { results.0.index_name: "search-1-test" } - - match: { results.0.language: "pl" } + - match: { results.0.id: "connector-b" } + - match: { results.0.index_name: "content-search-2-test" } + - match: { results.0.language: "en" } - - match: { results.1.id: "connector-b" } - - match: { results.1.index_name: "search-2-test" } - - match: { results.1.language: "en" } + - match: { results.1.id: "connector-a" } + - match: { results.1.index_name: "search-1-test" } + - match: { results.1.language: "pl" } - match: { results.2.id: "connector-c" } - match: { results.2.index_name: "search-3-test" } diff --git a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/ConnectorIndexService.java b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/ConnectorIndexService.java index 5e1fde0dfb942..8899a5555a7a2 100644 --- a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/ConnectorIndexService.java +++ b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/ConnectorIndexService.java @@ -76,6 +76,7 @@ import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.xpack.application.connector.ConnectorFiltering.fromXContentBytesConnectorFiltering; import static org.elasticsearch.xpack.application.connector.ConnectorFiltering.sortFilteringRulesByOrder; +import static org.elasticsearch.xpack.application.connector.ConnectorTemplateRegistry.MANAGED_CONNECTOR_INDEX_PREFIX; /** * A service that manages persistent {@link Connector} configurations. @@ -807,8 +808,8 @@ public void updateConnectorLastSyncStats(UpdateConnectorLastSyncStatsAction.Requ } /** - * Updates the is_native property of a {@link Connector}. It always sets the {@link ConnectorStatus} to - * CONFIGURED. + * Updates the is_native property of a {@link Connector}. It sets the {@link ConnectorStatus} to + * CONFIGURED when connector is in CONNECTED state to indicate that connector needs to reconnect. * * @param request The request for updating the connector's is_native property. * @param listener The listener for handling responses, including successful updates or errors. @@ -816,29 +817,57 @@ public void updateConnectorLastSyncStats(UpdateConnectorLastSyncStatsAction.Requ public void updateConnectorNative(UpdateConnectorNativeAction.Request request, ActionListener listener) { try { String connectorId = request.getConnectorId(); + boolean isNative = request.isNative(); - final UpdateRequest updateRequest = new UpdateRequest(CONNECTOR_INDEX_NAME, connectorId).doc( - new IndexRequest(CONNECTOR_INDEX_NAME).opType(DocWriteRequest.OpType.INDEX) - .id(connectorId) - .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) - .source( - Map.of( - Connector.IS_NATIVE_FIELD.getPreferredName(), - request.isNative(), - Connector.STATUS_FIELD.getPreferredName(), - ConnectorStatus.CONFIGURED.toString() - ) - ) + getConnector(connectorId, listener.delegateFailure((l, connector) -> { - ); - client.update(updateRequest, new DelegatingIndexNotFoundActionListener<>(connectorId, listener, (l, updateResponse) -> { - if (updateResponse.getResult() == UpdateResponse.Result.NOT_FOUND) { - l.onFailure(new ResourceNotFoundException(connectorNotFoundErrorMsg(connectorId))); + String indexName = getConnectorIndexNameFromSearchResult(connector); + + // Ensure attached content index is prefixed correctly + if (isNative && indexName != null && isValidManagedConnectorIndexName(indexName) == false) { + l.onFailure( + new ElasticsearchStatusException( + "The index name [" + + indexName + + "] attached to the connector [" + + connectorId + + "] must start with the required prefix: [" + + MANAGED_CONNECTOR_INDEX_PREFIX + + "] to be Elastic-managed. Please update the attached index first to comply with this requirement.", + RestStatus.BAD_REQUEST + ) + ); return; } - l.onResponse(updateResponse); - })); + ConnectorStatus status = getConnectorStatusFromSearchResult(connector); + + // If connector was connected already, change its status to CONFIGURED as we need to re-connect + if (status == ConnectorStatus.CONNECTED) { + status = ConnectorStatus.CONFIGURED; + } + + final UpdateRequest updateRequest = new UpdateRequest(CONNECTOR_INDEX_NAME, connectorId).doc( + new IndexRequest(CONNECTOR_INDEX_NAME).opType(DocWriteRequest.OpType.INDEX) + .id(connectorId) + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source( + Map.of( + Connector.IS_NATIVE_FIELD.getPreferredName(), + isNative, + Connector.STATUS_FIELD.getPreferredName(), + status.toString() + ) + ) + ); + client.update(updateRequest, new DelegatingIndexNotFoundActionListener<>(connectorId, listener, (ll, updateResponse) -> { + if (updateResponse.getResult() == UpdateResponse.Result.NOT_FOUND) { + ll.onFailure(new ResourceNotFoundException(connectorNotFoundErrorMsg(connectorId))); + return; + } + ll.onResponse(updateResponse); + })); + })); } catch (Exception e) { listener.onFailure(e); } @@ -896,22 +925,44 @@ public void updateConnectorIndexName(UpdateConnectorIndexNameAction.Request requ return; } - final UpdateRequest updateRequest = new UpdateRequest(CONNECTOR_INDEX_NAME, connectorId).doc( - new IndexRequest(CONNECTOR_INDEX_NAME).opType(DocWriteRequest.OpType.INDEX) - .id(connectorId) - .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) - .source(new HashMap<>() { - { - put(Connector.INDEX_NAME_FIELD.getPreferredName(), request.getIndexName()); - } - }) - ); - client.update(updateRequest, new DelegatingIndexNotFoundActionListener<>(connectorId, listener, (ll, updateResponse) -> { - if (updateResponse.getResult() == UpdateResponse.Result.NOT_FOUND) { - ll.onFailure(new ResourceNotFoundException(connectorNotFoundErrorMsg(connectorId))); + getConnector(connectorId, l.delegateFailure((ll, connector) -> { + + Boolean isManagedConnector = getConnectorIsNativeFlagFromSearchResult(connector); + + if (isManagedConnector && (isValidManagedConnectorIndexName(indexName) == false)) { + ll.onFailure( + new ElasticsearchStatusException( + "Index attached to an Elastic-managed connector must start with the prefix: [" + + MANAGED_CONNECTOR_INDEX_PREFIX + + "]. The index name in the payload [" + + indexName + + "] doesn't comply with this requirement.", + RestStatus.BAD_REQUEST + ) + ); return; } - ll.onResponse(updateResponse); + + final UpdateRequest updateRequest = new UpdateRequest(CONNECTOR_INDEX_NAME, connectorId).doc( + new IndexRequest(CONNECTOR_INDEX_NAME).opType(DocWriteRequest.OpType.INDEX) + .id(connectorId) + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(new HashMap<>() { + { + put(Connector.INDEX_NAME_FIELD.getPreferredName(), request.getIndexName()); + } + }) + ); + client.update( + updateRequest, + new DelegatingIndexNotFoundActionListener<>(connectorId, listener, (lll, updateResponse) -> { + if (updateResponse.getResult() == UpdateResponse.Result.NOT_FOUND) { + lll.onFailure(new ResourceNotFoundException(connectorNotFoundErrorMsg(connectorId))); + return; + } + lll.onResponse(updateResponse); + }) + ); })); })); @@ -1064,6 +1115,18 @@ private ConnectorStatus getConnectorStatusFromSearchResult(ConnectorSearchResult return ConnectorStatus.connectorStatus((String) searchResult.getResultMap().get(Connector.STATUS_FIELD.getPreferredName())); } + private Boolean getConnectorIsNativeFlagFromSearchResult(ConnectorSearchResult searchResult) { + return (Boolean) searchResult.getResultMap().get(Connector.IS_NATIVE_FIELD.getPreferredName()); + } + + private String getConnectorIndexNameFromSearchResult(ConnectorSearchResult searchResult) { + return (String) searchResult.getResultMap().get(Connector.INDEX_NAME_FIELD.getPreferredName()); + } + + private boolean isValidManagedConnectorIndexName(String indexName) { + return indexName.startsWith(MANAGED_CONNECTOR_INDEX_PREFIX); + } + @SuppressWarnings("unchecked") private Map getConnectorConfigurationFromSearchResult(ConnectorSearchResult searchResult) { return (Map) searchResult.getResultMap().get(Connector.CONFIGURATION_FIELD.getPreferredName()); diff --git a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/ConnectorTemplateRegistry.java b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/ConnectorTemplateRegistry.java index 9b8cc7cfdbe4f..e630f929bc09b 100644 --- a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/ConnectorTemplateRegistry.java +++ b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/ConnectorTemplateRegistry.java @@ -45,6 +45,8 @@ public class ConnectorTemplateRegistry extends IndexTemplateRegistry { public static final String ACCESS_CONTROL_INDEX_NAME_PATTERN = ".search-acl-filter-*"; public static final String ACCESS_CONTROL_TEMPLATE_NAME = "search-acl-filter"; + public static final String MANAGED_CONNECTOR_INDEX_PREFIX = "content-"; + // Pipeline constants public static final String ENT_SEARCH_GENERIC_PIPELINE_NAME = "ent-search-generic-ingestion"; diff --git a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/action/ConnectorActionRequest.java b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/action/ConnectorActionRequest.java index 1799121505da5..a92ad6aa9616a 100644 --- a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/action/ConnectorActionRequest.java +++ b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/action/ConnectorActionRequest.java @@ -19,6 +19,7 @@ import java.io.IOException; import static org.elasticsearch.action.ValidateActions.addValidationError; +import static org.elasticsearch.xpack.application.connector.ConnectorTemplateRegistry.MANAGED_CONNECTOR_INDEX_PREFIX; /** * Abstract base class for action requests targeting the connectors index. Implements {@link org.elasticsearch.action.IndicesRequest} @@ -52,6 +53,30 @@ public ActionRequestValidationException validateIndexName(String indexName, Acti return validationException; } + /** + * Validates that the given index name starts with the required prefix for Elastic-managed connectors. + * If the index name does not start with the required prefix, the validation exception is updated with an error message. + * + * @param indexName The index name to validate. If null, no validation is performed. + * @param validationException The exception to accumulate validation errors. + * @return The updated or original {@code validationException} with any new validation errors added, + * if the index name does not start with the required prefix. + */ + public ActionRequestValidationException validateManagedConnectorIndexPrefix( + String indexName, + ActionRequestValidationException validationException + ) { + if (indexName != null) { + if (indexName.startsWith(MANAGED_CONNECTOR_INDEX_PREFIX) == false) { + return addValidationError( + "Index attached to an Elastic-managed connector must start with the prefix: [" + MANAGED_CONNECTOR_INDEX_PREFIX + "]", + validationException + ); + } + } + return validationException; + } + @Override public String[] indices() { return new String[] { ConnectorTemplateRegistry.CONNECTOR_INDEX_NAME_PATTERN }; diff --git a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/action/PostConnectorAction.java b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/action/PostConnectorAction.java index fad349cd31877..b1c38637298c4 100644 --- a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/action/PostConnectorAction.java +++ b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/action/PostConnectorAction.java @@ -127,6 +127,10 @@ public ActionRequestValidationException validate() { validationException = validateIndexName(indexName, validationException); + if (Boolean.TRUE.equals(isNative)) { + validationException = validateManagedConnectorIndexPrefix(indexName, validationException); + } + return validationException; } diff --git a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/action/PutConnectorAction.java b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/action/PutConnectorAction.java index 687a801ab8fd6..f3e8ed6b6e76d 100644 --- a/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/action/PutConnectorAction.java +++ b/x-pack/plugin/ent-search/src/main/java/org/elasticsearch/xpack/application/connector/action/PutConnectorAction.java @@ -147,6 +147,10 @@ public ActionRequestValidationException validate() { validationException = validateIndexName(indexName, validationException); + if (Boolean.TRUE.equals(isNative)) { + validationException = validateManagedConnectorIndexPrefix(indexName, validationException); + } + return validationException; } diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorIndexServiceTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorIndexServiceTests.java index 12abca3a78591..60c8ea6c9c6a2 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorIndexServiceTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorIndexServiceTests.java @@ -56,6 +56,7 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; +import static org.elasticsearch.xpack.application.connector.ConnectorTemplateRegistry.MANAGED_CONNECTOR_INDEX_PREFIX; import static org.elasticsearch.xpack.application.connector.ConnectorTestUtils.getRandomConnectorFeatures; import static org.elasticsearch.xpack.application.connector.ConnectorTestUtils.getRandomCronExpression; import static org.elasticsearch.xpack.application.connector.ConnectorTestUtils.randomConnectorFeatureEnabled; @@ -649,7 +650,7 @@ public void testUpdateConnectorScheduling_OnlyFullSchedule() throws Exception { } public void testUpdateConnectorIndexName() throws Exception { - Connector connector = ConnectorTestUtils.getRandomConnector(); + Connector connector = ConnectorTestUtils.getRandomSelfManagedConnector(); String connectorId = randomUUID(); ConnectorCreateActionResponse resp = awaitCreateConnector(connectorId, connector); @@ -670,7 +671,7 @@ public void testUpdateConnectorIndexName() throws Exception { } public void testUpdateConnectorIndexName_WithTheSameIndexName() throws Exception { - Connector connector = ConnectorTestUtils.getRandomConnector(); + Connector connector = ConnectorTestUtils.getRandomSelfManagedConnector(); String connectorId = randomUUID(); ConnectorCreateActionResponse resp = awaitCreateConnector(connectorId, connector); @@ -685,6 +686,42 @@ public void testUpdateConnectorIndexName_WithTheSameIndexName() throws Exception assertThat(updateResponse.getResult(), equalTo(DocWriteResponse.Result.NOOP)); } + public void testUpdateConnectorIndexName_ForManagedConnector_WithIllegalIndexName() throws Exception { + Connector connector = ConnectorTestUtils.getRandomElasticManagedConnector(); + String connectorId = randomUUID(); + + ConnectorCreateActionResponse resp = awaitCreateConnector(connectorId, connector); + assertThat(resp.status(), anyOf(equalTo(RestStatus.CREATED), equalTo(RestStatus.OK))); + + UpdateConnectorIndexNameAction.Request updateIndexNameRequest = new UpdateConnectorIndexNameAction.Request( + connectorId, + "wrong-prefix-" + randomAlphaOfLengthBetween(3, 10) + ); + + expectThrows(ElasticsearchStatusException.class, () -> awaitUpdateConnectorIndexName(updateIndexNameRequest)); + } + + public void testUpdateConnectorIndexName_ForManagedConnector_WithPrefixedIndexName() throws Exception { + Connector connector = ConnectorTestUtils.getRandomElasticManagedConnector(); + String connectorId = randomUUID(); + + ConnectorCreateActionResponse resp = awaitCreateConnector(connectorId, connector); + assertThat(resp.status(), anyOf(equalTo(RestStatus.CREATED), equalTo(RestStatus.OK))); + + String newIndexName = "xd" + MANAGED_CONNECTOR_INDEX_PREFIX + randomAlphaOfLengthBetween(3, 10); + + UpdateConnectorIndexNameAction.Request updateIndexNameRequest = new UpdateConnectorIndexNameAction.Request( + connectorId, + newIndexName + ); + + DocWriteResponse updateResponse = awaitUpdateConnectorIndexName(updateIndexNameRequest); + assertThat(updateResponse.status(), equalTo(RestStatus.OK)); + + Connector indexedConnector = awaitGetConnector(connectorId); + assertThat(newIndexName, equalTo(indexedConnector.getIndexName())); + } + public void testUpdateConnectorServiceType() throws Exception { Connector connector = ConnectorTestUtils.getRandomConnector(); String connectorId = randomUUID(); diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorTestUtils.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorTestUtils.java index f052ef79d82fb..c134b05e74495 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorTestUtils.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorTestUtils.java @@ -343,6 +343,14 @@ public static Connector getRandomConnectorWithDetachedIndex() { return getRandomConnectorBuilder().setIndexName(null).build(); } + public static Connector getRandomSelfManagedConnector() { + return getRandomConnectorBuilder().setIsNative(false).build(); + } + + public static Connector getRandomElasticManagedConnector() { + return getRandomConnectorBuilder().setIsNative(true).build(); + } + public static Connector getRandomConnectorWithServiceTypeNotDefined() { return getRandomConnectorBuilder().setServiceType(null).build(); } diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/action/PostConnectorActionTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/action/PostConnectorActionTests.java index 0f0e83f2b9c51..e482bf3f6bb74 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/action/PostConnectorActionTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/action/PostConnectorActionTests.java @@ -20,7 +20,7 @@ public void testValidate_WhenConnectorIdAndIndexNamePresent_ExpectNoValidationEr PostConnectorAction.Request request = new PostConnectorAction.Request( randomAlphaOfLength(10), randomAlphaOfLength(10), - randomBoolean(), + false, randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10) @@ -30,6 +30,24 @@ public void testValidate_WhenConnectorIdAndIndexNamePresent_ExpectNoValidationEr assertThat(exception, nullValue()); } + public void testValidate_WrongIndexNamePresentForManagedConnector_ExpectValidationError() { + PostConnectorAction.Request requestWithIllegalIndexName = new PostConnectorAction.Request( + randomAlphaOfLength(10), + "wrong-prefix-" + randomAlphaOfLength(10), + true, + randomAlphaOfLength(10), + randomAlphaOfLength(10), + randomAlphaOfLength(10) + ); + ActionRequestValidationException exception = requestWithIllegalIndexName.validate(); + + assertThat(exception, notNullValue()); + assertThat( + exception.getMessage(), + containsString("Index attached to an Elastic-managed connector must start with the prefix: [content-]") + ); + } + public void testValidate_WhenMalformedIndexName_ExpectValidationError() { PostConnectorAction.Request requestWithMissingConnectorId = new PostConnectorAction.Request( randomAlphaOfLength(10), diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/action/PutConnectorActionTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/action/PutConnectorActionTests.java index 873e102e40931..10ab049413565 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/action/PutConnectorActionTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/action/PutConnectorActionTests.java @@ -21,7 +21,7 @@ public void testValidate_WhenConnectorIdAndIndexNamePresent_ExpectNoValidationEr randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10), - randomBoolean(), + false, randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10) @@ -31,6 +31,25 @@ public void testValidate_WhenConnectorIdAndIndexNamePresent_ExpectNoValidationEr assertThat(exception, nullValue()); } + public void testValidate_WrongIndexNamePresentForManagedConnector_ExpectValidationError() { + PutConnectorAction.Request requestWithIllegalIndexName = new PutConnectorAction.Request( + randomAlphaOfLength(10), + randomAlphaOfLength(10), + "wrong-prefix-" + randomAlphaOfLength(10), + true, + randomAlphaOfLength(10), + randomAlphaOfLength(10), + randomAlphaOfLength(10) + ); + ActionRequestValidationException exception = requestWithIllegalIndexName.validate(); + + assertThat(exception, notNullValue()); + assertThat( + exception.getMessage(), + containsString("Index attached to an Elastic-managed connector must start with the prefix: [content-]") + ); + } + public void testValidate_WhenMalformedIndexName_ExpectValidationError() { PutConnectorAction.Request requestWithMissingConnectorId = new PutConnectorAction.Request( randomAlphaOfLength(10), From 57d083fa6897942a31318fd7ada853a17e82f9de Mon Sep 17 00:00:00 2001 From: Jedr Blaszyk Date: Mon, 2 Dec 2024 09:32:28 +0100 Subject: [PATCH 2/2] Update ConnectorIndexServiceTests to check for prefix --- muted-tests.yml | 2 - .../connector/ConnectorIndexServiceTests.java | 37 ++++++++++++++++++- .../connector/ConnectorTestUtils.java | 4 ++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/muted-tests.yml b/muted-tests.yml index 96631d15f374f..8707541c58460 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -115,8 +115,6 @@ tests: - class: org.elasticsearch.search.SearchServiceTests method: testParseSourceValidation issue: https://github.com/elastic/elasticsearch/issues/115936 -- class: org.elasticsearch.xpack.application.connector.ConnectorIndexServiceTests - issue: https://github.com/elastic/elasticsearch/issues/116087 - class: org.elasticsearch.backwards.MixedClusterClientYamlTestSuiteIT method: test {p0=cat.shards/10_basic/Help} issue: https://github.com/elastic/elasticsearch/issues/116110 diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorIndexServiceTests.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorIndexServiceTests.java index 60c8ea6c9c6a2..37554462d5607 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorIndexServiceTests.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorIndexServiceTests.java @@ -708,7 +708,7 @@ public void testUpdateConnectorIndexName_ForManagedConnector_WithPrefixedIndexNa ConnectorCreateActionResponse resp = awaitCreateConnector(connectorId, connector); assertThat(resp.status(), anyOf(equalTo(RestStatus.CREATED), equalTo(RestStatus.OK))); - String newIndexName = "xd" + MANAGED_CONNECTOR_INDEX_PREFIX + randomAlphaOfLengthBetween(3, 10); + String newIndexName = MANAGED_CONNECTOR_INDEX_PREFIX + randomAlphaOfLengthBetween(3, 10); UpdateConnectorIndexNameAction.Request updateIndexNameRequest = new UpdateConnectorIndexNameAction.Request( connectorId, @@ -793,7 +793,7 @@ public void testUpdateConnectorNameOrDescription() throws Exception { } public void testUpdateConnectorNative() throws Exception { - Connector connector = ConnectorTestUtils.getRandomConnector(); + Connector connector = ConnectorTestUtils.getRandomConnectorWithDetachedIndex(); String connectorId = randomUUID(); ConnectorCreateActionResponse resp = awaitCreateConnector(connectorId, connector); @@ -810,6 +810,39 @@ public void testUpdateConnectorNative() throws Exception { assertThat(isNative, equalTo(indexedConnector.isNative())); } + public void testUpdateConnectorNativeTrue_WhenIllegalIndexPrefix() throws Exception { + Connector connector = ConnectorTestUtils.getRandomConnectorWithAttachedIndex("wrong-prefix-" + randomAlphaOfLength(10)); + String connectorId = randomUUID(); + + ConnectorCreateActionResponse resp = awaitCreateConnector(connectorId, connector); + assertThat(resp.status(), anyOf(equalTo(RestStatus.CREATED), equalTo(RestStatus.OK))); + + boolean isNative = true; + + UpdateConnectorNativeAction.Request updateNativeRequest = new UpdateConnectorNativeAction.Request(connectorId, isNative); + + expectThrows(ElasticsearchStatusException.class, () -> awaitUpdateConnectorNative(updateNativeRequest)); + } + + public void testUpdateConnectorNativeTrue_WithCorrectIndexPrefix() throws Exception { + Connector connector = ConnectorTestUtils.getRandomConnectorWithAttachedIndex( + MANAGED_CONNECTOR_INDEX_PREFIX + randomAlphaOfLength(10) + ); + String connectorId = randomUUID(); + + ConnectorCreateActionResponse resp = awaitCreateConnector(connectorId, connector); + assertThat(resp.status(), anyOf(equalTo(RestStatus.CREATED), equalTo(RestStatus.OK))); + + boolean isNative = true; + + UpdateConnectorNativeAction.Request updateNativeRequest = new UpdateConnectorNativeAction.Request(connectorId, isNative); + DocWriteResponse updateResponse = awaitUpdateConnectorNative(updateNativeRequest); + assertThat(updateResponse.status(), equalTo(RestStatus.OK)); + + Connector indexedConnector = awaitGetConnector(connectorId); + assertThat(isNative, equalTo(indexedConnector.isNative())); + } + public void testUpdateConnectorStatus() throws Exception { Connector connector = ConnectorTestUtils.getRandomConnector(); String connectorId = randomUUID(); diff --git a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorTestUtils.java b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorTestUtils.java index c134b05e74495..c563bc0a14ee3 100644 --- a/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorTestUtils.java +++ b/x-pack/plugin/ent-search/src/test/java/org/elasticsearch/xpack/application/connector/ConnectorTestUtils.java @@ -343,6 +343,10 @@ public static Connector getRandomConnectorWithDetachedIndex() { return getRandomConnectorBuilder().setIndexName(null).build(); } + public static Connector getRandomConnectorWithAttachedIndex(String indexName) { + return getRandomConnectorBuilder().setIndexName(indexName).build(); + } + public static Connector getRandomSelfManagedConnector() { return getRandomConnectorBuilder().setIsNative(false).build(); }