Skip to content

Commit f015e6a

Browse files
authored
[Extensions] REST API to initialize an extension and dynamically load it (#8029)
* Implemented REST API for initializing extension Signed-off-by: Owais Kazi <[email protected]> * Cleanup extensions.yml design Signed-off-by: Owais Kazi <[email protected]> * Added tests for RestInitializeExtensionAction Signed-off-by: Owais Kazi <[email protected]> * Pulled extensions REST request in extensions directory Signed-off-by: Owais Kazi <[email protected]> * Removed forbidden APIs from rest action and modified tests Signed-off-by: Owais Kazi <[email protected]> * Added entry in changelog Signed-off-by: Owais Kazi <[email protected]> * Added test for parse Signed-off-by: Owais Kazi <[email protected]> * Addressed PR comments Signed-off-by: Owais Kazi <[email protected]> * Addressed PR comments Signed-off-by: Owais Kazi <[email protected]> * Spotless Fixed Signed-off-by: Owais Kazi <[email protected]> * Handled exceptions Signed-off-by: Owais Kazi <[email protected]> * Handled test failure Signed-off-by: Owais Kazi <[email protected]> --------- Signed-off-by: Owais Kazi <[email protected]>
1 parent 9c5c6eb commit f015e6a

17 files changed

+535
-363
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
8282
- Add descending order search optimization through reverse segment read. ([#7967](https://github.com/opensearch-project/OpenSearch/pull/7967))
8383
- Update components of segrep backpressure to support remote store. ([#8020](https://github.com/opensearch-project/OpenSearch/pull/8020))
8484
- Make remote cluster connection setup in async ([#8038](https://github.com/opensearch-project/OpenSearch/pull/8038))
85+
- Add API to initialize extensions ([#8029]()https://github.com/opensearch-project/OpenSearch/pull/8029)
8586

8687
### Dependencies
8788
- Bump `com.azure:azure-storage-common` from 12.21.0 to 12.21.1 (#7566, #7814)

server/src/main/java/org/opensearch/action/ActionModule.java

+12-2
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,10 @@
294294
import org.opensearch.common.settings.Settings;
295295
import org.opensearch.common.settings.SettingsFilter;
296296
import org.opensearch.common.util.FeatureFlags;
297+
import org.opensearch.extensions.ExtensionsManager;
297298
import org.opensearch.extensions.action.ExtensionProxyAction;
298299
import org.opensearch.extensions.action.ExtensionProxyTransportAction;
300+
import org.opensearch.extensions.rest.RestInitializeExtensionAction;
299301
import org.opensearch.index.seqno.RetentionLeaseActions;
300302
import org.opensearch.identity.IdentityService;
301303
import org.opensearch.indices.SystemIndices;
@@ -453,7 +455,7 @@
453455
import org.opensearch.rest.action.search.RestPutSearchPipelineAction;
454456
import org.opensearch.rest.action.search.RestSearchAction;
455457
import org.opensearch.rest.action.search.RestSearchScrollAction;
456-
import org.opensearch.rest.extensions.RestSendToExtensionAction;
458+
import org.opensearch.extensions.rest.RestSendToExtensionAction;
457459
import org.opensearch.tasks.Task;
458460
import org.opensearch.threadpool.ThreadPool;
459461
import org.opensearch.usage.UsageService;
@@ -508,6 +510,7 @@ public class ActionModule extends AbstractModule {
508510
private final RequestValidators<PutMappingRequest> mappingRequestValidators;
509511
private final RequestValidators<IndicesAliasesRequest> indicesAliasesRequestRequestValidators;
510512
private final ThreadPool threadPool;
513+
private final ExtensionsManager extensionsManager;
511514

512515
public ActionModule(
513516
Settings settings,
@@ -521,7 +524,8 @@ public ActionModule(
521524
CircuitBreakerService circuitBreakerService,
522525
UsageService usageService,
523526
SystemIndices systemIndices,
524-
IdentityService identityService
527+
IdentityService identityService,
528+
ExtensionsManager extensionsManager
525529
) {
526530
this.settings = settings;
527531
this.indexNameExpressionResolver = indexNameExpressionResolver;
@@ -530,6 +534,7 @@ public ActionModule(
530534
this.settingsFilter = settingsFilter;
531535
this.actionPlugins = actionPlugins;
532536
this.threadPool = threadPool;
537+
this.extensionsManager = extensionsManager;
533538
actions = setupActions(actionPlugins);
534539
actionFilters = setupActionFilters(actionPlugins);
535540
dynamicActionRegistry = new DynamicActionRegistry();
@@ -947,6 +952,11 @@ public void initRestHandlers(Supplier<DiscoveryNodes> nodesInCluster) {
947952
registerHandler.accept(new RestDeleteSearchPipelineAction());
948953
}
949954

955+
// Extensions API
956+
if (FeatureFlags.isEnabled(FeatureFlags.EXTENSIONS)) {
957+
registerHandler.accept(new RestInitializeExtensionAction(extensionsManager));
958+
}
959+
950960
for (ActionPlugin plugin : actionPlugins) {
951961
for (RestHandler handler : plugin.getRestHandlers(
952962
settings,

server/src/main/java/org/opensearch/bootstrap/Security.java

-1
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,6 @@ static void addFilePermissions(Permissions policy, Environment environment) thro
316316
addDirectoryPath(policy, Environment.PATH_HOME_SETTING.getKey(), environment.libDir(), "read,readlink", false);
317317
addDirectoryPath(policy, Environment.PATH_HOME_SETTING.getKey(), environment.modulesDir(), "read,readlink", false);
318318
addDirectoryPath(policy, Environment.PATH_HOME_SETTING.getKey(), environment.pluginsDir(), "read,readlink", false);
319-
addDirectoryPath(policy, Environment.PATH_HOME_SETTING.getKey(), environment.extensionDir(), "read,readlink", false);
320319
addDirectoryPath(policy, "path.conf'", environment.configDir(), "read,readlink", false);
321320
// read-write dirs
322321
addDirectoryPath(policy, "java.io.tmpdir", environment.tmpDir(), "read,readlink,write,delete", false);

server/src/main/java/org/opensearch/env/Environment.java

-4
Original file line numberDiff line numberDiff line change
@@ -311,10 +311,6 @@ public Path pluginsDir() {
311311
return pluginsDir;
312312
}
313313

314-
public Path extensionDir() {
315-
return extensionsDir;
316-
}
317-
318314
public Path binDir() {
319315
return binDir;
320316
}

server/src/main/java/org/opensearch/extensions/ExtensionDependency.java

+39
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
import org.opensearch.common.io.stream.StreamInput;
1717
import org.opensearch.common.io.stream.StreamOutput;
1818
import org.opensearch.common.io.stream.Writeable;
19+
import org.opensearch.core.common.Strings;
20+
import org.opensearch.core.xcontent.XContentParser;
21+
22+
import static org.opensearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
1923

2024
/**
2125
* This class handles the dependent extensions information
@@ -25,6 +29,8 @@
2529
public class ExtensionDependency implements Writeable {
2630
private String uniqueId;
2731
private Version version;
32+
private static final String UNIQUE_ID = "uniqueId";
33+
private static final String VERSION = "version";
2834

2935
public ExtensionDependency(String uniqueId, Version version) {
3036
this.uniqueId = uniqueId;
@@ -54,6 +60,39 @@ public void writeTo(StreamOutput out) throws IOException {
5460
out.writeVersion(version);
5561
}
5662

63+
public static ExtensionDependency parse(XContentParser parser) throws IOException {
64+
String uniqueId = null;
65+
Version version = null;
66+
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser);
67+
while (parser.nextToken() != XContentParser.Token.END_OBJECT) {
68+
String fieldName = parser.currentName();
69+
parser.nextToken();
70+
71+
switch (fieldName) {
72+
case UNIQUE_ID:
73+
uniqueId = parser.text();
74+
break;
75+
case VERSION:
76+
try {
77+
version = Version.fromString(parser.text());
78+
} catch (IllegalArgumentException e) {
79+
throw e;
80+
}
81+
break;
82+
default:
83+
parser.skipChildren();
84+
break;
85+
}
86+
}
87+
if (Strings.isNullOrEmpty(uniqueId)) {
88+
throw new IOException("Required field [uniqueId] is missing in the request for the dependent extension");
89+
} else if (version == null) {
90+
throw new IOException("Required field [version] is missing in the request for the dependent extension");
91+
}
92+
return new ExtensionDependency(uniqueId, version);
93+
94+
}
95+
5796
/**
5897
* The uniqueId of the dependency extension
5998
*

0 commit comments

Comments
 (0)