Skip to content
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
49 changes: 16 additions & 33 deletions CREATE_YOUR_FIRST_EXTENSION.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,60 +150,43 @@ These classes must implement _`ExtensionRestHandler`_, which is a functional int

The `BaseExtensionRestHandler` class provides many useful methods for exception handling in requests.

For the CRUD extension example, you'll implement one REST route for each option and delegate it to the appropriate handler function. Each route is an instance of `NamedRoute` and requires at least a method, path, and globally unique name.
For the CRUD extension example, you'll implement one REST route for each option and delegate it to the appropriate handler function.

```java
import java.util.List;
import java.util.function.Function;

import org.opensearch.rest.NamedRoute;
import org.opensearch.rest.RestRequest;
import org.opensearch.extensions.rest.ExtensionRestResponse;
import org.opensearch.rest.RestRequest.Method;
import org.opensearch.rest.RestResponse;
import org.opensearch.rest.RestRequest;
import org.opensearch.rest.RestStatus;
import org.opensearch.sdk.rest.BaseExtensionRestHandler;

public class CrudAction extends BaseExtensionRestHandler {

@Override
public List<NamedRoute> routes() {
protected List<RouteHandler> routeHandlers() {
return List.of(
new NamedRoute.Builder().method(Method.PUT)
.path("/sample")
.uniqueName("crud_extension:sample/create")
.handler(createHandler)
.build(),
new NamedRoute.Builder().method(Method.GET)
.path("/sample/{id}")
.uniqueName("crud_extension:sample/get")
.handler(readHandler)
.build(),
new NamedRoute.Builder().method(Method.POST)
.path("/sample/{id}")
.uniqueName("crud_extension:sample/post")
.handler(updateHandler)
.build(),
new NamedRoute.Builder().method(Method.DELETE)
.path("/sample/{id}")
.uniqueName("crud_extension:sample/delete")
.handler(deleteHandler)
.build()
new RouteHandler(Method.PUT, "/sample", createHandler),
new RouteHandler(Method.GET, "/sample/{id}", readHandler),
new RouteHandler(Method.POST, "/sample/{id}", updateHandler),
new RouteHandler(Method.DELETE, "/sample/{id}", deleteHandler)
);
}

Function<RestRequest, RestResponse> createHandler = (request) -> {
Function<RestRequest, ExtensionRestResponse> createHandler = (request) -> {
return new ExtensionRestResponse(request, RestStatus.OK, "To be implemented");
};

Function<RestRequest, RestResponse> readHandler = (request) -> {
Function<RestRequest, ExtensionRestResponse> readHandler = (request) -> {
return new ExtensionRestResponse(request, RestStatus.OK, "To be implemented");
};

Function<RestRequest, RestResponse> updateHandler = (request) -> {
Function<RestRequest, ExtensionRestResponse> updateHandler = (request) -> {
return new ExtensionRestResponse(request, RestStatus.OK, "To be implemented");
};

Function<RestRequest, RestResponse> deleteHandler = (request) -> {
Function<RestRequest, ExtensionRestResponse> deleteHandler = (request) -> {
return new ExtensionRestResponse(request, RestStatus.OK, "To be implemented");
};
}
Expand Down Expand Up @@ -278,7 +261,7 @@ return createJsonResponse(request, RestStatus.OK, "_id", response.id());
Finally, you have the following code for the create handler method:

```java
Function<RestRequest, RestResponse> createHandler = (request) -> {
Function<RestRequest, ExtensionRestResponse> createHandler = (request) -> {
IndexResponse response;
try {
// Create index if it doesn't exist
Expand Down Expand Up @@ -312,7 +295,7 @@ GetResponse<CrudData> response = client.get(new GetRequest.Builder().index("crud
Adding exception handling, the following is the full handler method:

```java
Function<RestRequest, RestResponse> readHandler = (request) -> {
Function<RestRequest, ExtensionRestResponse> readHandler = (request) -> {
GetResponse<CrudData> response;
// Parse ID from request
String id = request.param("id");
Expand All @@ -333,7 +316,7 @@ Function<RestRequest, RestResponse> readHandler = (request) -> {
You will create a new document similar to the one you created in the create handler, parse the ID as you did in the read handler, and then update that document. With exception handling, the following is the update handler method:

```java
Function<RestRequest, RestResponse> updateHandler = (request) -> {
Function<RestRequest, ExtensionRestResponse> updateHandler = (request) -> {
UpdateResponse<CrudData> response;
// Parse ID from request
String id = request.param("id");
Expand All @@ -360,7 +343,7 @@ Function<RestRequest, RestResponse> updateHandler = (request) -> {
You only need the ID to delete a document, so the delete handler method is implemented as follows:

```java
Function<RestRequest, RestResponse> deleteHandler = (request) -> {
Function<RestRequest, ExtensionRestResponse> deleteHandler = (request) -> {
DeleteResponse response;
// Parse ID from request
String id = request.param("id");
Expand Down
39 changes: 17 additions & 22 deletions DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,14 +146,14 @@ To **run OpenSearch from a compiled binary**, follow these steps:
- Start OpenSearch using `./bin/opensearch`.
- Send the below sample REST API to initialize an extension
```bash
curl -XPOST "localhost:9200/_extensions/initialize" -H "Content-Type:application/json" --data '{
"name":"hello-world",
"uniqueId":"hello-world",
"hostAddress":"127.0.0.1",
"port":"4532",
"version":"1.0",
"opensearchVersion":"3.0.0",
"minimumCompatibleVersion":"3.0.0",
curl -XPOST "localhost:9200/_extensions/initialize" -H "Content-Type:application/json" --data '{ \
"name":"hello-world", \
"uniqueId":"hello-world", \
"hostAddress":"127.0.0.1", \
"port":"4532", \
"version":"1.0", \
"opensearchVersion":"3.0.0", \
"minimumCompatibleVersion":"3.0.0", \
"dependencies":[{"uniqueId":"test1","version":"2.0.0"},{"uniqueId":"test2","version":"3.0.0"}] \
}'
```
Expand All @@ -162,20 +162,18 @@ To **run OpenSearch from Gradle**, follow these steps:
- Run `./gradlew run` to start OpenSearch.
- Send the below sample REST API to initialize an extension
```bash
curl -XPOST "localhost:9200/_extensions/initialize" -H "Content-Type:application/json" --data '{
"name":"hello-world",
"uniqueId":"hello-world",
"hostAddress":"127.0.0.1",
"port":"4532",
"version":"1.0",
"opensearchVersion":"3.0.0",
"minimumCompatibleVersion":"3.0.0",
"dependencies":[{"uniqueId":"test1","version":"2.0.0"},{"uniqueId":"test2","version":"3.0.0"}]
curl -XPOST "localhost:9200/_extensions/initialize" -H "Content-Type:application/json" --data '{ \
"name":"hello-world", \
"uniqueId":"hello-world", \
"hostAddress":"127.0.0.1", \
"port":"4532", \
"version":"1.0", \
"opensearchVersion":"3.0.0", \
"minimumCompatibleVersion":"3.0.0", \
"dependencies":[{"uniqueId":"test1","version":"2.0.0"},{"uniqueId":"test2","version":"3.0.0"}] \
}'
```

Note: If the Security plugin is initialized in OpenSearch, use admin credentials to send extension initialization request.

In response to the REST `/initialize` request, `ExtensionsManager` discovers the extension listening on a predefined port and executes the TCP handshake protocol to establish a data transfer connection. Then OpenSearch sends a request to the OpenSearch SDK for Java and, upon acknowledgment, the extension responds with its name. This name is logged in the terminal where OpenSearch is running:

```bash
Expand Down Expand Up @@ -303,9 +301,6 @@ The artifact will include extension settings for the sample Hello World extensio
opensearchPort: 9200
```

You can optionally add `routeNamePrefix:` as a value to the yml. This setting allows you to prefix all your registered NamedRoute names.
The value must be alphanumeric and can contain `_` in the name.

Start the sample extension with `./bin/opensearch-sdk-java`

### Submitting changes
Expand Down
28 changes: 2 additions & 26 deletions PLUGIN_MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,38 +67,14 @@ XContentParser parser = XContentType.JSON
Other potential initialization values are:
```java
this.environmentSettings = extensionsRunner.getEnvironmentSettings();
this.transportService = extensionsRunner.getSdkTransportService().getTransportService();
this.transportService = extensionsRunner.getExtensionTransportService();
this.restClient = anomalyDetectorExtension.getRestClient();
this.sdkClusterService = new SDKClusterService(extensionsRunner);
```

Many of these components are also available via Guice injection.

### Replace `Route` with `NamedRoute`
Change `routes()` to be NamedRoutes. Here is a sample of an existing route converted to a named route:
Before:
```
public List<Route> routes() {
return ImmutableList.of(
new Route(GET, "/uri")
);
}
```
With new scheme:
```
private Function<RestRequest, RestResponse> uriHandler = () -> {};
public List<NamedRoute> routes() {
return ImmutableList.of(
new NamedRoute.Builder().method(GET).path("/uri").uniqueName("extension:uri").handler(uriHandler).build()
);
}
```

You can optionally also add `actionNames()` to this route. These should correspond to any current actions defined as permissions in roles.
`actionNames()` serve as a valuable tool for converting plugins into extensions while maintaining compatibility with pre-defined reserved roles.
Ensure that these name-to-route mappings are easily accessible to the cluster admins to allow granting access to these APIs.

Change `prepareRequest()` to `handleRequest()`.
Optionally, change the `routes()` to `routeHandlers()`. Change `prepareRequest()` to `handleRequest()`.

### Replace `BytesRestResponse` with `ExtensionRestResponse`

Expand Down
25 changes: 10 additions & 15 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import java.nio.file.Files
import org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestFramework
import org.opensearch.gradle.test.RestIntegTestTask
import org.opensearch.gradle.testclusters.ExtensionsProperties

buildscript {
ext {
Expand Down Expand Up @@ -147,7 +146,6 @@ dependencies {
def javaxVersion = "1"
def guavaFailureAccessVersion = "1.0.1"
def aopallianceVersion = "1.0"
def slf4jVersion = "1.7.36"

api("org.opensearch:opensearch:${opensearchVersion}")
implementation("org.apache.logging.log4j:log4j-api:${log4jVersion}")
Expand Down Expand Up @@ -188,19 +186,16 @@ dependencies {
testRuntimeOnly("org.junit.platform:junit-platform-launcher:${junitPlatform}")

configurations.all {
resolutionStrategy {
force("jakarta.json:jakarta.json-api:${jakartaVersion}")
force("com.fasterxml.jackson.core:jackson-databind:${jacksonDatabindVersion}")
force("com.fasterxml.jackson.core:jackson-core:${jacksonDatabindVersion}")
force("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:${jacksonDatabindVersion}")
force("com.fasterxml.jackson.dataformat:jackson-dataformat-smile:${jacksonDatabindVersion}")
force("com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:${jacksonDatabindVersion}")
force("org.apache.logging.log4j:log4j-api:${log4jVersion}")
force("org.apache.logging.log4j:log4j-core:${log4jVersion}")
force("org.apache.logging.log4j:log4j-jul:${log4jVersion}")
force("org.opensearch.client:opensearch-rest-client:${opensearchVersion}")
force("org.slf4j:slf4j-api:${slf4jVersion}")
}
resolutionStrategy.force("jakarta.json:jakarta.json-api:${jakartaVersion}")
resolutionStrategy.force("com.fasterxml.jackson.core:jackson-databind:${jacksonDatabindVersion}")
resolutionStrategy.force("com.fasterxml.jackson.core:jackson-core:${jacksonDatabindVersion}")
resolutionStrategy.force("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:${jacksonDatabindVersion}")
resolutionStrategy.force("com.fasterxml.jackson.dataformat:jackson-dataformat-smile:${jacksonDatabindVersion}")
resolutionStrategy.force("com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:${jacksonDatabindVersion}")
resolutionStrategy.force("org.apache.logging.log4j:log4j-api:${log4jVersion}")
resolutionStrategy.force("org.apache.logging.log4j:log4j-core:${log4jVersion}")
resolutionStrategy.force("org.apache.logging.log4j:log4j-jul:${log4jVersion}")
resolutionStrategy.force("org.opensearch.client:opensearch-rest-client:${opensearchVersion}")
}
}

Expand Down
34 changes: 0 additions & 34 deletions config/certs/cert-gen.sh

This file was deleted.

Loading