Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Connector API] Support hard deletes with new URL param in delete endpoint #120200

Merged
merged 9 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changelog/120200.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 120200
summary: "[Connector API] Support hard deletes with new URL param in delete endpoint"
area: Extract&Transform
type: feature
issues: []
5 changes: 4 additions & 1 deletion docs/reference/connector/apis/delete-connector-api.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ beta::[]
For the most up-to-date API details, refer to {api-es}/group/endpoint-connector[Connector APIs].
--

Soft-deletes a connector and removes associated sync jobs.
Deletes a connector and optionally removes associated sync jobs.

Note: this action doesn't delete any API key, ingest pipeline or data index associated with the connector. These need to be removed manually.

Expand All @@ -37,6 +37,9 @@ To get started with Connector APIs, check out <<es-connectors-tutorial-api, our
`<connector_id>`::
(Required, string)

`<hard>`::
(Optional, boolean) If `true`, the connector doc is deleted. If `false`, connector doc is marked as deleted (soft deletion). Defaults to `false`.

`delete_sync_jobs`::
(Optional, boolean) A flag indicating if associated sync jobs should be also removed. Defaults to `false`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
]
},
"params": {
"hard": {
"type": "boolean",
"default": false,
"description": "If true, the connector doc is deleted. If false, connector doc is marked as deleted (soft-deleted)."
},
"delete_sync_jobs": {
"type": "boolean",
"default": false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,9 +280,7 @@ setup:

---
"List Connectors - Soft deleted connectors / no deleted":
- requires:
cluster_features: ["connector_soft_deletes"]
Copy link
Member Author

Choose a reason for hiding this comment

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

we actually don't have this feature, I ended up deleting this 90862f2

reason: Soft deletes were introduced in 9.0 release


- do:
connector.list:
Expand All @@ -293,9 +291,7 @@ setup:

---
"List Connectors - Single soft deleted connector":
- requires:
cluster_features: ["connector_soft_deletes"]
reason: Soft deletes were introduced in 9.0 release


- do:
connector.delete:
Expand All @@ -312,11 +308,91 @@ setup:

- match: { count: 3 }


---
"List Connectors - Single hard deleted connector":


- do:
connector.delete:
connector_id: connector-a
hard: true

- do:
connector.list: {}

- match: { count: 2 }

- do:
connector.list:
include_deleted: true

- match: { count: 2 }


---
"List Connectors - All hard deleted connectors":


- do:
connector.delete:
connector_id: connector-a
hard: true

- do:
connector.delete:
connector_id: connector-b
hard: true

- do:
connector.delete:
connector_id: connector-c
hard: true

- do:
connector.list: {}

- match: { count: 0 }

- do:
connector.list:
include_deleted: true

- match: { count: 0 }

---
"List Connectors - 2 hard deleted connectors, 1 soft deleted":


- do:
connector.delete:
connector_id: connector-a
hard: false

- do:
connector.delete:
connector_id: connector-b
hard: true

- do:
connector.delete:
connector_id: connector-c
hard: true

- do:
connector.list: {}

- match: { count: 0 }

- do:
connector.list:
include_deleted: true

- match: { count: 1 }

---
"List Connectors - Soft deleted connectors":
- requires:
cluster_features: ["connector_soft_deletes"]
reason: Soft deletes were introduced in 9.0 release


- do:
connector.delete:
Expand Down Expand Up @@ -353,9 +429,7 @@ setup:

---
"List Connectors - Soft deleted with from":
- requires:
cluster_features: ["connector_soft_deletes"]
reason: Soft deletes were introduced in 9.0 release


- do:
connector.delete:
Expand Down Expand Up @@ -387,9 +461,7 @@ setup:

---
"List Connector - Soft deleted with size":
- requires:
cluster_features: ["connector_soft_deletes"]
reason: Soft deletes were introduced in 9.0 release


- do:
connector.delete:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,31 @@ setup:
connector_id: test-connector-to-delete


---
"Delete Connector - Hard Delete":
- do:
connector.put:
connector_id: test-connector-hard-delete
body:
index_name: search-2-test
name: my-hard-delete-connector
language: en
is_native: false
service_type: super-connector

- do:
connector.delete:
connector_id: test-connector-hard-delete
hard: true

- match: { acknowledged: true }

- do:
catch: "missing"
connector.get:
connector_id: test-connector-hard-delete
include_deleted: true

---
"Delete Connector - deletes associated sync jobs":

Expand Down Expand Up @@ -107,12 +132,9 @@ setup:
connector.delete:
connector_id: test-nonexistent-connector


---
"Delete Connector - Supports soft deletes":
- requires:
cluster_features: ["connector_soft_deletes"]
reason: Soft deletes were introduced in 9.0 release


- do:
connector.delete:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.DelegatingActionListener;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
Expand Down Expand Up @@ -232,40 +234,71 @@ public void getConnector(String connectorId, boolean includeDeleted, ActionListe
}

/**
* Soft deletes the {@link Connector} and optionally removes the related instances of {@link ConnectorSyncJob} in the underlying index.
* Deletes the {@link Connector} and optionally removes the related instances of {@link ConnectorSyncJob} in the underlying index.
*
* @param connectorId The id of the {@link Connector}.
* @param hardDelete If set to true, the {@link Connector} is permanently deleted; otherwise, it is soft-deleted.
* @param shouldDeleteSyncJobs The flag indicating if {@link ConnectorSyncJob} should also be deleted.
* @param listener The action listener to invoke on response/failure.
*/
public void deleteConnector(String connectorId, boolean shouldDeleteSyncJobs, ActionListener<UpdateResponse> listener) {
public void deleteConnector(
String connectorId,
boolean hardDelete,
boolean shouldDeleteSyncJobs,
ActionListener<DocWriteResponse> listener
) {

try {
// ensure that if connector is soft-deleted, deleting it again results in 404
getConnector(connectorId, false, listener.delegateFailure((l, connector) -> {
final UpdateRequest updateRequest = new UpdateRequest(CONNECTOR_INDEX_NAME, connectorId).setRefreshPolicy(
WriteRequest.RefreshPolicy.IMMEDIATE
)
.doc(
new IndexRequest(CONNECTOR_INDEX_NAME).opType(DocWriteRequest.OpType.INDEX)
.id(connectorId)
.source(Map.of(Connector.IS_DELETED_FIELD.getPreferredName(), true))
);
clientWithOrigin.update(updateRequest, new DelegatingIndexNotFoundActionListener<>(connectorId, l, (ll, updateResponse) -> {
if (updateResponse.getResult() == UpdateResponse.Result.NOT_FOUND) {
ll.onFailure(new ResourceNotFoundException(connectorNotFoundErrorMsg(connectorId)));
return;
}
if (shouldDeleteSyncJobs) {
new ConnectorSyncJobIndexService(clientWithOrigin).deleteAllSyncJobsByConnectorId(
connectorId,
ll.map(r -> updateResponse)
if (hardDelete) {
final DeleteRequest deleteRequest = new DeleteRequest(CONNECTOR_INDEX_NAME).id(connectorId)
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);

clientWithOrigin.delete(
deleteRequest,
new DelegatingIndexNotFoundActionListener<>(connectorId, listener, (l, deleteResponse) -> {
if (deleteResponse.getResult() == DocWriteResponse.Result.NOT_FOUND) {
l.onFailure(new ResourceNotFoundException(connectorNotFoundErrorMsg(connectorId)));
return;
}
if (shouldDeleteSyncJobs) {
new ConnectorSyncJobIndexService(clientWithOrigin).deleteAllSyncJobsByConnectorId(
connectorId,
l.map(r -> deleteResponse)
);
} else {
l.onResponse(deleteResponse);
}
})
);
} else {
getConnector(connectorId, false, listener.delegateFailure((l, connector) -> {
final UpdateRequest updateRequest = new UpdateRequest(CONNECTOR_INDEX_NAME, connectorId).setRefreshPolicy(
WriteRequest.RefreshPolicy.IMMEDIATE
)
.doc(
new IndexRequest(CONNECTOR_INDEX_NAME).opType(DocWriteRequest.OpType.INDEX)
.id(connectorId)
.source(Map.of(Connector.IS_DELETED_FIELD.getPreferredName(), true))
);
} else {
ll.onResponse(updateResponse);
}
clientWithOrigin.update(
updateRequest,
new DelegatingIndexNotFoundActionListener<>(connectorId, l, (ll, updateResponse) -> {
if (updateResponse.getResult() == UpdateResponse.Result.NOT_FOUND) {
ll.onFailure(new ResourceNotFoundException(connectorNotFoundErrorMsg(connectorId)));
return;
}
if (shouldDeleteSyncJobs) {
new ConnectorSyncJobIndexService(clientWithOrigin).deleteAllSyncJobsByConnectorId(
connectorId,
ll.map(r -> updateResponse)
);
} else {
ll.onResponse(updateResponse);
}
})
);
}));
}));
}
} catch (Exception e) {
listener.onFailure(e);
}
Expand Down
Loading