Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
20 changes: 10 additions & 10 deletions CREATE_YOUR_FIRST_EXTENSION.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,28 +164,28 @@ import org.opensearch.sdk.rest.BaseExtensionRestHandler;
public class CrudAction extends BaseExtensionRestHandler {

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

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

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

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

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

```java
Function<RestRequest, ExtensionRestResponse> createHandler = (request) -> {
Function<RestRequest, RestResponse> createHandler = (request) -> {
IndexResponse response;
try {
BooleanResponse exists = client.indices().exists(new ExistsRequest.Builder().index("crudsample").build());
Expand Down
36 changes: 19 additions & 17 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,18 +162,20 @@ 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
28 changes: 26 additions & 2 deletions PLUGIN_MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,38 @@ XContentParser parser = XContentType.JSON
Other potential initialization values are:
```java
this.environmentSettings = extensionsRunner.getEnvironmentSettings();
this.transportService = extensionsRunner.getExtensionTransportService();
this.transportService = extensionsRunner.getSdkTransportService().getTransportService();
this.restClient = anomalyDetectorExtension.getRestClient();
this.sdkClusterService = new SDKClusterService(extensionsRunner);
```

Many of these components are also available via Guice injection.

Optionally, change the `routes()` to `routeHandlers()`. Change `prepareRequest()` to `handleRequest()`.
### 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()`.

### Replace `BytesRestResponse` with `ExtensionRestResponse`

Expand Down
26 changes: 15 additions & 11 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ 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 @@ -187,16 +188,19 @@ dependencies {
testRuntimeOnly("org.junit.platform:junit-platform-launcher:${junitPlatform}")

configurations.all {
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}")
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}")
}
}
}

Expand Down Expand Up @@ -320,7 +324,7 @@ task closeTestExtension (type: Exec) {
tasks.named("integTest").configure { finalizedBy(closeTestExtension) }

testClusters.integTest {
extension(new ExtensionsProperties("${testExtensionYml.name}", "${testExtensionYml.uniqueId}", "${testExtensionYml.hostAddress}", "${testExtensionYml.port}", "${testExtensionYml.version}", "${testExtensionYml.opensearchVersion}", "${testExtensionYml.minimumCompatibleVersion}"))
extension(true)
testDistribution = "ARCHIVE"
// Cluster shrink exception thrown if we try to set numberOfNodes to 1, so only apply if > 1
if (_numNodes > 1) numberOfNodes = _numNodes
Expand Down
34 changes: 34 additions & 0 deletions config/certs/cert-gen.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#! /bin/bash

openssl genrsa -out root-ca-key.pem 2048
openssl req -new -x509 -sha256 -key root-ca-key.pem -subj "/C=US/ST=NEW YORK/L=BROOKLYN/O=OPENSEARCH/OU=SECURITY/CN=ROOT" -out root-ca.pem -days 730

openssl genrsa -out extension-01-key-temp.pem 2048
openssl pkcs8 -inform PEM -outform PEM -in extension-01-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out extension-01-key.pem
openssl req -new -key extension-01-key.pem -subj "/C=US/ST=NEW YORK/L=BROOKLYN/O=OPENSEARCH/OU=SECURITY/CN=extension-01" -out extension-01.csr
echo 'subjectAltName=DNS:extension-01' | tee -a extension-01.ext
echo 'subjectAltName=IP:172.20.0.11' | tee -a extension-01.ext
openssl x509 -req -in extension-01.csr -CA root-ca.pem -CAkey root-ca-key.pem -CAcreateserial -sha256 -out extension-01.pem -days 730 -extfile extension-01.ext

rm extension-01-key-temp.pem
rm extension-01.csr
rm extension-01.ext
rm root-ca.srl

openssl genrsa -out admin-key-temp.pem 2048
openssl pkcs8 -inform PEM -outform PEM -in admin-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out admin-key.pem
openssl req -new -key admin-key.pem -subj "/C=US/ST=NEW YORK/L=BROOKLYN/O=OPENSEARCH/OU=SECURITY/CN=A" -out admin.csr
openssl x509 -req -in admin.csr -CA root-ca.pem -CAkey root-ca-key.pem -CAcreateserial -sha256 -out admin.pem -days 730
openssl genrsa -out os-node-01-key-temp.pem 2048
openssl pkcs8 -inform PEM -outform PEM -in os-node-01-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out os-node-01-key.pem
openssl req -new -key os-node-01-key.pem -subj "/C=US/ST=NEW YORK/L=BROOKLYN/O=OPENSEARCH/OU=SECURITY/CN=os-node-01" -out os-node-01.csr
echo 'subjectAltName=DNS:os-node-01' | tee -a os-node-01.ext
echo 'subjectAltName=IP:172.20.0.11' | tee -a os-node-01.ext
openssl x509 -req -in os-node-01.csr -CA root-ca.pem -CAkey root-ca-key.pem -CAcreateserial -sha256 -out os-node-01.pem -days 730 -extfile os-node-01.ext

rm admin-key-temp.pem
rm admin.csr
rm os-node-01-key-temp.pem
rm os-node-01.csr
rm os-node-01.ext
rm root-ca.srl
3 changes: 1 addition & 2 deletions src/main/java/org/opensearch/sdk/ExtensionSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public class ExtensionSettings {
private String hostPort;
private String opensearchAddress;
private String opensearchPort;
private Map<String, String> securitySettings;

public static final Set<String> SECURITY_SETTINGS_KEYS = Set.of(
"path.home", // TODO Find the right place to put this setting
Expand All @@ -79,8 +80,6 @@ public class ExtensionSettings {
SSL_TRANSPORT_TRUSTSTORE_TYPE
);

private Map<String, String> securitySettings;

/**
* Jackson requires a no-arg constructor.
*/
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/opensearch/sdk/ExtensionsRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.opensearch.sdk.handlers.ExtensionsInitRequestHandler;
import org.opensearch.sdk.handlers.ExtensionsRestRequestHandler;
import org.opensearch.sdk.handlers.UpdateSettingsRequestHandler;
import org.opensearch.sdk.rest.BaseExtensionRestHandler;
import org.opensearch.sdk.rest.ExtensionRestHandler;
import org.opensearch.sdk.rest.ExtensionRestPathRegistry;
import org.opensearch.tasks.TaskManager;
Expand Down Expand Up @@ -233,6 +234,9 @@ protected ExtensionsRunner(Extension extension) throws IOException {
if (extension instanceof ActionExtension) {
// store REST handlers in the registry
for (ExtensionRestHandler extensionRestHandler : ((ActionExtension) extension).getExtensionRestHandlers()) {
if (extensionRestHandler instanceof BaseExtensionRestHandler) {
((BaseExtensionRestHandler) extensionRestHandler).setExtensionName(extensionSettings.getExtensionName());
}
extensionRestPathRegistry.registerHandler(extensionRestHandler);
}
}
Expand Down
Loading