diff --git a/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorDeleteAction.java b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorDeleteAction.java new file mode 100644 index 0000000000..dc0c1044f1 --- /dev/null +++ b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorDeleteAction.java @@ -0,0 +1,16 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.ml.common.transport.connector; + +import org.opensearch.action.ActionType; +import org.opensearch.action.delete.DeleteResponse; + +public class MLConnectorDeleteAction extends ActionType { + public static final MLConnectorDeleteAction INSTANCE = new MLConnectorDeleteAction(); + public static final String NAME = "cluster:admin/opensearch/ml/connectors/delete"; + + private MLConnectorDeleteAction() { super(NAME, DeleteResponse::new);} +} diff --git a/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorDeleteRequest.java b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorDeleteRequest.java new file mode 100644 index 0000000000..a3dd2d6f93 --- /dev/null +++ b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorDeleteRequest.java @@ -0,0 +1,71 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.ml.common.transport.connector; + +import lombok.Builder; +import lombok.Getter; +import org.opensearch.action.ActionRequest; +import org.opensearch.action.ActionRequestValidationException; +import org.opensearch.common.io.stream.InputStreamStreamInput; +import org.opensearch.common.io.stream.OutputStreamStreamOutput; +import org.opensearch.common.io.stream.StreamInput; +import org.opensearch.common.io.stream.StreamOutput; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UncheckedIOException; + +import static org.opensearch.action.ValidateActions.addValidationError; + +public class MLConnectorDeleteRequest extends ActionRequest { + @Getter + String connectorId; + + @Builder + public MLConnectorDeleteRequest(String connectorId) { + this.connectorId = connectorId; + } + + public MLConnectorDeleteRequest(StreamInput input) throws IOException { + super(input); + this.connectorId = input.readString(); + } + + @Override + public void writeTo(StreamOutput output) throws IOException { + super.writeTo(output); + output.writeString(connectorId); + } + + @Override + public ActionRequestValidationException validate() { + ActionRequestValidationException exception = null; + + if (this.connectorId == null) { + exception = addValidationError("ML connector id can't be null", exception); + } + + return exception; + } + + public static MLConnectorDeleteRequest fromActionRequest(ActionRequest actionRequest) { + if (actionRequest instanceof MLConnectorDeleteRequest) { + return (MLConnectorDeleteRequest)actionRequest; + } + + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStreamStreamOutput osso = new OutputStreamStreamOutput(baos)) { + actionRequest.writeTo(osso); + try (StreamInput input = new InputStreamStreamInput(new ByteArrayInputStream(baos.toByteArray()))) { + return new MLConnectorDeleteRequest(input); + } + } catch (IOException e) { + throw new UncheckedIOException("failed to parse ActionRequest into MLConnectorDeleteRequest", e); + } + } + +} diff --git a/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorGetAction.java b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorGetAction.java new file mode 100644 index 0000000000..da29dd86fe --- /dev/null +++ b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorGetAction.java @@ -0,0 +1,16 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.ml.common.transport.connector; + +import org.opensearch.action.ActionType; + +public class MLConnectorGetAction extends ActionType { + public static final MLConnectorGetAction INSTANCE = new MLConnectorGetAction(); + public static final String NAME = "cluster:admin/opensearch/ml/connectors/get"; + + private MLConnectorGetAction() { super(NAME, MLConnectorGetResponse::new);} + +} diff --git a/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorGetRequest.java b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorGetRequest.java new file mode 100644 index 0000000000..6b4b7dead1 --- /dev/null +++ b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorGetRequest.java @@ -0,0 +1,75 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.ml.common.transport.connector; + +import lombok.Builder; +import lombok.Getter; +import org.opensearch.action.ActionRequest; +import org.opensearch.action.ActionRequestValidationException; +import org.opensearch.common.io.stream.InputStreamStreamInput; +import org.opensearch.common.io.stream.OutputStreamStreamOutput; +import org.opensearch.common.io.stream.StreamInput; +import org.opensearch.common.io.stream.StreamOutput; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UncheckedIOException; + +import static org.opensearch.action.ValidateActions.addValidationError; + +@Getter +public class MLConnectorGetRequest extends ActionRequest { + + String connectorId; + boolean returnContent; + + @Builder + public MLConnectorGetRequest(String connectorId, boolean returnContent) { + this.connectorId = connectorId; + this.returnContent = returnContent; + } + + public MLConnectorGetRequest(StreamInput in) throws IOException { + super(in); + this.connectorId = in.readString(); + this.returnContent = in.readBoolean(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeString(this.connectorId); + out.writeBoolean(returnContent); + } + + @Override + public ActionRequestValidationException validate() { + ActionRequestValidationException exception = null; + + if (this.connectorId == null) { + exception = addValidationError("ML connector id can't be null", exception); + } + + return exception; + } + + public static MLConnectorGetRequest fromActionRequest(ActionRequest actionRequest) { + if (actionRequest instanceof MLConnectorGetRequest) { + return (MLConnectorGetRequest) actionRequest; + } + + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStreamStreamOutput osso = new OutputStreamStreamOutput(baos)) { + actionRequest.writeTo(osso); + try (StreamInput input = new InputStreamStreamInput(new ByteArrayInputStream(baos.toByteArray()))) { + return new MLConnectorGetRequest(input); + } + } catch (IOException e) { + throw new UncheckedIOException("failed to parse ActionRequest into MLConnectorGetRequest", e); + } + } +} diff --git a/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorGetResponse.java b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorGetResponse.java new file mode 100644 index 0000000000..5bcedf5a52 --- /dev/null +++ b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorGetResponse.java @@ -0,0 +1,63 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.ml.common.transport.connector; + +import lombok.Builder; +import org.opensearch.action.ActionResponse; +import org.opensearch.common.io.stream.InputStreamStreamInput; +import org.opensearch.common.io.stream.OutputStreamStreamOutput; +import org.opensearch.common.io.stream.StreamInput; +import org.opensearch.common.io.stream.StreamOutput; +import org.opensearch.core.xcontent.ToXContent; +import org.opensearch.core.xcontent.ToXContentObject; +import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.ml.common.connector.Connector; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UncheckedIOException; + +public class MLConnectorGetResponse extends ActionResponse implements ToXContentObject { + Connector mlConnector; + + @Builder + public MLConnectorGetResponse(Connector mlConnector) { + this.mlConnector = mlConnector; + } + + public MLConnectorGetResponse(StreamInput in) throws IOException { + super(in); + mlConnector = Connector.fromStream(in); + } + + @Override + public void writeTo(StreamOutput out) throws IOException{ + mlConnector.writeTo(out); + } + + @Override + public XContentBuilder toXContent(XContentBuilder xContentBuilder, ToXContent.Params params) throws IOException { + return mlConnector.toXContent(xContentBuilder, params); + } + + public static MLConnectorGetResponse fromActionResponse(ActionResponse actionResponse) { + if (actionResponse instanceof MLConnectorGetResponse) { + return (MLConnectorGetResponse) actionResponse; + } + + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStreamStreamOutput osso = new OutputStreamStreamOutput(baos)) { + actionResponse.writeTo(osso); + try (StreamInput input = new InputStreamStreamInput(new ByteArrayInputStream(baos.toByteArray()))) { + return new MLConnectorGetResponse(input); + } + } catch (IOException e) { + throw new UncheckedIOException("failed to parse ActionResponse into MLConnectorGetResponse", e); + } + } + +} diff --git a/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorSearchAction.java b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorSearchAction.java new file mode 100644 index 0000000000..ed778b2c24 --- /dev/null +++ b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLConnectorSearchAction.java @@ -0,0 +1,19 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.ml.common.transport.connector; + +import org.opensearch.action.ActionType; +import org.opensearch.action.search.SearchResponse; + +public class MLConnectorSearchAction extends ActionType { + // External Action which used for public facing RestAPIs. + public static final String NAME = "cluster:admin/opensearch/ml/connectors/search"; + public static final MLConnectorSearchAction INSTANCE = new MLConnectorSearchAction(); + + private MLConnectorSearchAction() { + super(NAME, SearchResponse::new); + } +} diff --git a/common/src/main/java/org/opensearch/ml/common/transport/connector/MLCreateConnectorAction.java b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLCreateConnectorAction.java new file mode 100644 index 0000000000..66aae66800 --- /dev/null +++ b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLCreateConnectorAction.java @@ -0,0 +1,17 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.ml.common.transport.connector; + +import org.opensearch.action.ActionType; + +public class MLCreateConnectorAction extends ActionType { + public static MLCreateConnectorAction INSTANCE = new MLCreateConnectorAction(); + public static final String NAME = "cluster:admin/opensearch/ml/create_connector"; + + private MLCreateConnectorAction() { + super(NAME, MLCreateConnectorResponse::new); + } +} diff --git a/common/src/main/java/org/opensearch/ml/common/transport/connector/MLCreateConnectorInput.java b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLCreateConnectorInput.java new file mode 100644 index 0000000000..d2d9dfd80e --- /dev/null +++ b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLCreateConnectorInput.java @@ -0,0 +1,251 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.ml.common.transport.connector; + +import lombok.Builder; +import lombok.Data; +import org.opensearch.common.io.stream.StreamInput; +import org.opensearch.common.io.stream.StreamOutput; +import org.opensearch.common.io.stream.Writeable; +import org.opensearch.core.xcontent.ToXContentObject; +import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.core.xcontent.XContentParser; +import org.opensearch.ml.common.AccessMode; +import org.opensearch.ml.common.connector.ConnectorAction; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.opensearch.common.xcontent.XContentParserUtils.ensureExpectedToken; + +@Data +public class MLCreateConnectorInput implements ToXContentObject, Writeable { + public static final String CONNECTOR_NAME_FIELD = "name"; + public static final String CONNECTOR_DESCRIPTION_FIELD = "description"; + public static final String CONNECTOR_VERSION_FIELD = "version"; + public static final String CONNECTOR_PROTOCOL_FIELD = "protocol"; + + public static final String CONNECTOR_PARAMETERS_FIELD = "parameters"; + public static final String CONNECTOR_CREDENTIAL_FIELD = "credential"; + public static final String CONNECTOR_ACTIONS_FIELD = "actions"; + + public static final String BACKEND_ROLES_FIELD = "backend_roles"; + public static final String ADD_ALL_BACKEND_ROLES_FIELD = "add_all_backend_roles"; + public static final String OWNER_FIELD = "owner"; + public static final String ACCESS_MODE_FIELD = "access_mode"; + + public static final String DRY_RUN_CONNECTOR_NAME = "dryRunConnector"; + + private String name; + private String description; + private String version; + private String protocol; + private Map parameters; + private Map credential; + private List actions; + private List backendRoles; + private Boolean addAllBackendRoles; + private AccessMode access; + + @Builder(toBuilder = true) + public MLCreateConnectorInput(String name, + String description, + String version, + String protocol, + Map parameters, + Map credential, + List actions, + List backendRoles, + Boolean addAllBackendRoles, + AccessMode access + ) { + this.name = name; + this.description = description; + this.version = version; + this.protocol = protocol; + this.parameters = parameters; + this.credential = credential; + this.actions = actions; + this.backendRoles = backendRoles; + this.addAllBackendRoles = addAllBackendRoles; + this.access = access; + } + + public static MLCreateConnectorInput parse(XContentParser parser) throws IOException { + String name = null; + String description = null; + String version = null; + String protocol = null; + Map parameters = new HashMap<>(); + Map credential = new HashMap<>(); + List actions = null; + List backendRoles = null; + Boolean addAllBackendRoles = null; + AccessMode access = null; + + ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser); + while (parser.nextToken() != XContentParser.Token.END_OBJECT) { + String fieldName = parser.currentName(); + parser.nextToken(); + + switch (fieldName) { + case CONNECTOR_NAME_FIELD: + name = parser.text(); + break; + case CONNECTOR_DESCRIPTION_FIELD: + description = parser.text(); + break; + case CONNECTOR_VERSION_FIELD: + version = parser.text(); + break; + case CONNECTOR_PROTOCOL_FIELD: + protocol = parser.text(); + break; + case CONNECTOR_PARAMETERS_FIELD: + parameters = parser.mapStrings(); + break; + case CONNECTOR_CREDENTIAL_FIELD: + credential = parser.mapStrings(); + break; + case CONNECTOR_ACTIONS_FIELD: + actions = new ArrayList<>(); + ensureExpectedToken(XContentParser.Token.START_ARRAY, parser.currentToken(), parser); + while (parser.nextToken() != XContentParser.Token.END_ARRAY) { + actions.add(ConnectorAction.parse(parser)); + } + break; + case BACKEND_ROLES_FIELD: + ensureExpectedToken(XContentParser.Token.START_ARRAY, parser.currentToken(), parser); + backendRoles = new ArrayList<>(); + while (parser.nextToken() != XContentParser.Token.END_ARRAY) { + backendRoles.add(parser.text()); + } + break; + case ADD_ALL_BACKEND_ROLES_FIELD: + addAllBackendRoles = parser.booleanValue(); + break; + case ACCESS_MODE_FIELD: + access = AccessMode.from(parser.text()); + break; + default: + parser.skipChildren(); + break; + } + } + return new MLCreateConnectorInput(name, description, version, protocol, parameters, credential, actions, backendRoles, addAllBackendRoles, access); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + if (name != null) { + builder.field(CONNECTOR_NAME_FIELD, name); + } + if (description != null) { + builder.field(CONNECTOR_DESCRIPTION_FIELD, description); + } + if (version != null) { + builder.field(CONNECTOR_VERSION_FIELD, version); + } + if (protocol != null) { + builder.field(CONNECTOR_PROTOCOL_FIELD, protocol); + } + if (parameters != null) { + builder.field(CONNECTOR_PARAMETERS_FIELD, parameters); + } + if (credential != null) { + builder.field(CONNECTOR_CREDENTIAL_FIELD, credential); + } + if (actions != null) { + builder.field(CONNECTOR_ACTIONS_FIELD, actions); + } + if (backendRoles != null) { + builder.field(BACKEND_ROLES_FIELD, backendRoles); + } + if (addAllBackendRoles != null) { + builder.field(ADD_ALL_BACKEND_ROLES_FIELD, addAllBackendRoles); + } + if (access != null) { + builder.field(ACCESS_MODE_FIELD, access); + } + builder.endObject(); + return builder; + } + + @Override + public void writeTo(StreamOutput output) throws IOException { + output.writeString(name); + output.writeString(description); + output.writeString(version); + output.writeString(protocol); + if (parameters != null) { + output.writeBoolean(true); + output.writeMap(parameters, StreamOutput::writeString, StreamOutput::writeString); + } else { + output.writeBoolean(false); + } + if (credential != null) { + output.writeBoolean(true); + output.writeMap(credential, StreamOutput::writeString, StreamOutput::writeString); + } else { + output.writeBoolean(false); + } + if (actions != null) { + output.writeBoolean(true); + output.writeInt(actions.size()); + for (ConnectorAction action : actions) { + action.writeTo(output); + } + } else { + output.writeBoolean(false); + } + if (backendRoles != null) { + output.writeBoolean(true); + output.writeOptionalStringCollection(backendRoles); + } else { + output.writeBoolean(false); + } + if (addAllBackendRoles != null) { + output.writeBoolean(addAllBackendRoles); + } + if (access != null) { + output.writeBoolean(true); + output.writeEnum(access); + } else { + output.writeBoolean(false); + } + } + + public MLCreateConnectorInput(StreamInput input) throws IOException { + name = input.readString(); + description = input.readString(); + version = input.readString(); + protocol = input.readString(); + if (input.readBoolean()) { + parameters = input.readMap(s -> s.readString(), s -> s.readString()); + } + if (input.readBoolean()) { + credential = input.readMap(s -> s.readString(), s-> s.readString()); + } + if (input.readBoolean()) { + actions = new ArrayList<>(); + int size = input.readInt(); + for (int i = 0; i < size; i++) { + actions.add(new ConnectorAction(input)); + } + } + if (input.readBoolean()) { + this.backendRoles = input.readList(StreamInput::readString); + } + this.addAllBackendRoles = input.readOptionalBoolean(); + if (input.readBoolean()) { + this.access = input.readEnum(AccessMode.class); + } + } +} \ No newline at end of file diff --git a/common/src/main/java/org/opensearch/ml/common/transport/connector/MLCreateConnectorRequest.java b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLCreateConnectorRequest.java new file mode 100644 index 0000000000..fc4f8002ca --- /dev/null +++ b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLCreateConnectorRequest.java @@ -0,0 +1,69 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.ml.common.transport.connector; + +import lombok.Builder; +import lombok.Getter; +import org.opensearch.action.ActionRequest; +import org.opensearch.action.ActionRequestValidationException; +import org.opensearch.common.io.stream.InputStreamStreamInput; +import org.opensearch.common.io.stream.OutputStreamStreamOutput; +import org.opensearch.common.io.stream.StreamInput; +import org.opensearch.common.io.stream.StreamOutput; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UncheckedIOException; + +import static org.opensearch.action.ValidateActions.addValidationError; + +@Getter +public class MLCreateConnectorRequest extends ActionRequest { + private MLCreateConnectorInput mlCreateConnectorInput; + + @Builder + public MLCreateConnectorRequest(MLCreateConnectorInput mlCreateConnectorInput) { + this.mlCreateConnectorInput = mlCreateConnectorInput; + } + + public MLCreateConnectorRequest(StreamInput in) throws IOException { + super(in); + this.mlCreateConnectorInput = new MLCreateConnectorInput(in); + } + + @Override + public ActionRequestValidationException validate() { + ActionRequestValidationException exception = null; + if (mlCreateConnectorInput == null) { + exception = addValidationError("ML Connector input can't be null", exception); + } + + return exception; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + this.mlCreateConnectorInput.writeTo(out); + } + + public static MLCreateConnectorRequest fromActionRequest(ActionRequest actionRequest) { + if (actionRequest instanceof MLCreateConnectorRequest) { + return (MLCreateConnectorRequest) actionRequest; + } + + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStreamStreamOutput osso = new OutputStreamStreamOutput(baos)) { + actionRequest.writeTo(osso); + try (StreamInput input = new InputStreamStreamInput(new ByteArrayInputStream(baos.toByteArray()))) { + return new MLCreateConnectorRequest(input); + } + } catch (IOException e) { + throw new UncheckedIOException("Failed to parse ActionRequest into MLCreateConnectorRequest", e); + } + } +} \ No newline at end of file diff --git a/common/src/main/java/org/opensearch/ml/common/transport/connector/MLCreateConnectorResponse.java b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLCreateConnectorResponse.java new file mode 100644 index 0000000000..b91ad80e45 --- /dev/null +++ b/common/src/main/java/org/opensearch/ml/common/transport/connector/MLCreateConnectorResponse.java @@ -0,0 +1,45 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.ml.common.transport.connector; + +import lombok.Getter; +import org.opensearch.action.ActionResponse; +import org.opensearch.common.io.stream.StreamInput; +import org.opensearch.common.io.stream.StreamOutput; +import org.opensearch.core.xcontent.ToXContentObject; +import org.opensearch.core.xcontent.XContentBuilder; + +import java.io.IOException; + +@Getter +public class MLCreateConnectorResponse extends ActionResponse implements ToXContentObject { + public static final String Connector_ID_FIELD = "connector_id"; + public static final String STATUS_FIELD = "status"; + + private String connectorId; + + public MLCreateConnectorResponse(StreamInput in) throws IOException { + super(in); + this.connectorId = in.readString(); + } + + public MLCreateConnectorResponse(String taskId) { + this.connectorId = taskId; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeString(connectorId); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field(Connector_ID_FIELD, connectorId); + builder.endObject(); + return builder; + } +}