Skip to content

Commit

Permalink
[Connector API] Implement _features endpoint (elastic#109248)
Browse files Browse the repository at this point in the history
  • Loading branch information
jedrazb authored Jun 4, 2024
1 parent 191caca commit d543d91
Show file tree
Hide file tree
Showing 13 changed files with 552 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"connector.update_features": {
"documentation": {
"url": "https://www.elastic.co/guide/en/elasticsearch/reference/master/update-connector-features-api.html",
"description": "Updates the connector features in the connector document."
},
"stability": "experimental",
"visibility": "public",
"headers": {
"accept": [
"application/json"
],
"content_type": [
"application/json"
]
},
"url": {
"paths": [
{
"path": "/_connector/{connector_id}/_features",
"methods": [
"PUT"
],
"parts": {
"connector_id": {
"type": "string",
"description": "The unique identifier of the connector to be updated."
}
}
}
]
},
"body": {
"description": "An object containing the connector's features definition.",
"required": true
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
setup:
- requires:
cluster_features: ["gte_v8.15.0"]
reason: Introduced in 8.15.0

- do:
connector.put:
connector_id: test-connector
body:
index_name: search-1-test
name: my-connector
language: pl
is_native: false
service_type: super-connector

---
"Update Connector Features":
- do:
connector.update_features:
connector_id: test-connector
body:
features:
document_level_security: { enabled: true }
native_connector_api_keys: { enabled: true }
incremental_sync: { enabled: false }
sync_rules:
basic: { enabled: true }
advanced: { enabled: false }


- match: { result: updated }

- do:
connector.get:
connector_id: test-connector

- match: { features.document_level_security.enabled: true }
- match: { features.native_connector_api_keys.enabled: true }
- match: { features.incremental_sync.enabled: false }
- match: { features.sync_rules.basic.enabled: true }
- match: { features.sync_rules.advanced.enabled: false }

---
"Update Connector Features - Partial Update":
- do:
connector.update_features:
connector_id: test-connector
body:
features:
document_level_security: { enabled: true }


- match: { result: updated }

- do:
connector.get:
connector_id: test-connector

- match: { features.document_level_security.enabled: true }


- do:
connector.update_features:
connector_id: test-connector
body:
features:
native_connector_api_keys: { enabled: true }


- match: { result: updated }

- do:
connector.get:
connector_id: test-connector

# Assert that existing feature remains unchanged
- match: { features.document_level_security.enabled: true }
- match: { features.native_connector_api_keys.enabled: true }

---
"Update Connector Features - 404 when connector doesn't exist":
- do:
catch: "missing"
connector.update_features:
connector_id: test-non-existent-connector
body:
features:
native_connector_api_keys: { enabled: true }

---
"Update Connector Features - 400 status code when connector_id is empty":
- do:
catch: "bad_request"
connector.update_features:
connector_id: ""
body:
features:
native_connector_api_keys: { enabled: true }

---
"Update Connector Features - 400 status code when payload unknown":
- do:
catch: "bad_request"
connector.update_features:
connector_id: test-connector
body:
featuresss:
not_a_feature: 12423
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import org.elasticsearch.xpack.application.connector.action.RestUpdateConnectorApiKeyIdAction;
import org.elasticsearch.xpack.application.connector.action.RestUpdateConnectorConfigurationAction;
import org.elasticsearch.xpack.application.connector.action.RestUpdateConnectorErrorAction;
import org.elasticsearch.xpack.application.connector.action.RestUpdateConnectorFeaturesAction;
import org.elasticsearch.xpack.application.connector.action.RestUpdateConnectorFilteringAction;
import org.elasticsearch.xpack.application.connector.action.RestUpdateConnectorFilteringValidationAction;
import org.elasticsearch.xpack.application.connector.action.RestUpdateConnectorIndexNameAction;
Expand All @@ -78,6 +79,7 @@
import org.elasticsearch.xpack.application.connector.action.TransportUpdateConnectorApiKeyIdAction;
import org.elasticsearch.xpack.application.connector.action.TransportUpdateConnectorConfigurationAction;
import org.elasticsearch.xpack.application.connector.action.TransportUpdateConnectorErrorAction;
import org.elasticsearch.xpack.application.connector.action.TransportUpdateConnectorFeaturesAction;
import org.elasticsearch.xpack.application.connector.action.TransportUpdateConnectorFilteringAction;
import org.elasticsearch.xpack.application.connector.action.TransportUpdateConnectorFilteringValidationAction;
import org.elasticsearch.xpack.application.connector.action.TransportUpdateConnectorIndexNameAction;
Expand All @@ -93,6 +95,7 @@
import org.elasticsearch.xpack.application.connector.action.UpdateConnectorApiKeyIdAction;
import org.elasticsearch.xpack.application.connector.action.UpdateConnectorConfigurationAction;
import org.elasticsearch.xpack.application.connector.action.UpdateConnectorErrorAction;
import org.elasticsearch.xpack.application.connector.action.UpdateConnectorFeaturesAction;
import org.elasticsearch.xpack.application.connector.action.UpdateConnectorFilteringAction;
import org.elasticsearch.xpack.application.connector.action.UpdateConnectorFilteringValidationAction;
import org.elasticsearch.xpack.application.connector.action.UpdateConnectorIndexNameAction;
Expand Down Expand Up @@ -267,6 +270,7 @@ protected XPackLicenseState getLicenseState() {
new ActionHandler<>(UpdateConnectorApiKeyIdAction.INSTANCE, TransportUpdateConnectorApiKeyIdAction.class),
new ActionHandler<>(UpdateConnectorConfigurationAction.INSTANCE, TransportUpdateConnectorConfigurationAction.class),
new ActionHandler<>(UpdateConnectorErrorAction.INSTANCE, TransportUpdateConnectorErrorAction.class),
new ActionHandler<>(UpdateConnectorFeaturesAction.INSTANCE, TransportUpdateConnectorFeaturesAction.class),
new ActionHandler<>(UpdateConnectorFilteringAction.INSTANCE, TransportUpdateConnectorFilteringAction.class),
new ActionHandler<>(UpdateConnectorActiveFilteringAction.INSTANCE, TransportUpdateConnectorActiveFilteringAction.class),
new ActionHandler<>(
Expand Down Expand Up @@ -368,6 +372,7 @@ public List<RestHandler> getRestHandlers(
new RestUpdateConnectorConfigurationAction(),
new RestUpdateConnectorErrorAction(),
new RestUpdateConnectorActiveFilteringAction(),
new RestUpdateConnectorFeaturesAction(),
new RestUpdateConnectorFilteringValidationAction(),
new RestUpdateConnectorFilteringAction(),
new RestUpdateConnectorIndexNameAction(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ public Connector(StreamInput in) throws IOException {
static final ParseField CUSTOM_SCHEDULING_FIELD = new ParseField("custom_scheduling");
public static final ParseField DESCRIPTION_FIELD = new ParseField("description");
public static final ParseField ERROR_FIELD = new ParseField("error");
static final ParseField FEATURES_FIELD = new ParseField("features");
public static final ParseField FEATURES_FIELD = new ParseField("features");
public static final ParseField FILTERING_FIELD = new ParseField("filtering");
public static final ParseField INDEX_NAME_FIELD = new ParseField("index_name");
public static final ParseField IS_NATIVE_FIELD = new ParseField("is_native");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,22 @@ public static ConnectorFeatures fromXContentBytes(BytesReference source, XConten
}
}

public FeatureEnabled getDocumentLevelSecurityEnabled() {
return documentLevelSecurityEnabled;
}

public FeatureEnabled getIncrementalSyncEnabled() {
return incrementalSyncEnabled;
}

public FeatureEnabled getNativeConnectorAPIKeysEnabled() {
return nativeConnectorAPIKeysEnabled;
}

public SyncRulesFeatures getSyncRulesFeatures() {
return syncRulesFeatures;
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,33 @@ public void updateConnectorFiltering(String connectorId, List<ConnectorFiltering
}
}

/**
* Updates the features of a given {@link Connector}.
*
* @param connectorId The ID of the {@link Connector} to be updated.
* @param features An instance of {@link ConnectorFeatures}
* @param listener Listener to respond to a successful response or an error.
*/
public void updateConnectorFeatures(String connectorId, ConnectorFeatures features, ActionListener<UpdateResponse> listener) {
try {
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.FEATURES_FIELD.getPreferredName(), features))
);
client.update(updateRequest, new DelegatingIndexNotFoundActionListener<>(connectorId, listener, (l, updateResponse) -> {
if (updateResponse.getResult() == UpdateResponse.Result.NOT_FOUND) {
l.onFailure(new ResourceNotFoundException(connectorNotFoundErrorMsg(connectorId)));
return;
}
l.onResponse(updateResponse);
}));
} catch (Exception e) {
listener.onFailure(e);
}
}

/**
* Updates the draft filtering in a given {@link Connector}.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* 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.application.connector.action;

import org.elasticsearch.client.internal.node.NodeClient;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.Scope;
import org.elasticsearch.rest.ServerlessScope;
import org.elasticsearch.rest.action.RestToXContentListener;
import org.elasticsearch.xpack.application.EnterpriseSearch;

import java.util.List;

import static org.elasticsearch.rest.RestRequest.Method.PUT;

@ServerlessScope(Scope.PUBLIC)
public class RestUpdateConnectorFeaturesAction extends BaseRestHandler {

@Override
public String getName() {
return "connector_update_features_action";
}

@Override
public List<Route> routes() {
return List.of(new Route(PUT, "/" + EnterpriseSearch.CONNECTOR_API_ENDPOINT + "/{connector_id}/_features"));
}

@Override
protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) {
UpdateConnectorFeaturesAction.Request request = UpdateConnectorFeaturesAction.Request.fromXContentBytes(
restRequest.param("connector_id"),
restRequest.content(),
restRequest.getXContentType()
);
return channel -> client.execute(
UpdateConnectorFeaturesAction.INSTANCE,
request,
new RestToXContentListener<>(channel, ConnectorUpdateActionResponse::status)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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.application.connector.action;

import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.HandledTransportAction;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.util.concurrent.EsExecutors;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.xpack.application.connector.ConnectorIndexService;

public class TransportUpdateConnectorFeaturesAction extends HandledTransportAction<
UpdateConnectorFeaturesAction.Request,
ConnectorUpdateActionResponse> {

protected final ConnectorIndexService connectorIndexService;

@Inject
public TransportUpdateConnectorFeaturesAction(TransportService transportService, ActionFilters actionFilters, Client client) {
super(
UpdateConnectorFeaturesAction.NAME,
transportService,
actionFilters,
UpdateConnectorFeaturesAction.Request::new,
EsExecutors.DIRECT_EXECUTOR_SERVICE
);
this.connectorIndexService = new ConnectorIndexService(client);
}

@Override
protected void doExecute(
Task task,
UpdateConnectorFeaturesAction.Request request,
ActionListener<ConnectorUpdateActionResponse> listener
) {
connectorIndexService.updateConnectorFeatures(
request.getConnectorId(),
request.getFeatures(),
listener.map(r -> new ConnectorUpdateActionResponse(r.getResult()))
);
}
}
Loading

0 comments on commit d543d91

Please sign in to comment.