Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1b865d8
Dynamically enable / disable plugins in correspondence to stateless m…
mosche Feb 9, 2026
052328a
nit
mosche Feb 9, 2026
112c178
nit
mosche Feb 9, 2026
d99317e
Merge branch 'main' into statelessOnPrem/distributionMode
mosche Feb 9, 2026
d9ca9d0
fix tests
mosche Feb 9, 2026
282d42d
Merge branch 'main' into statelessOnPrem/distributionMode
mosche Feb 10, 2026
5e5825c
Rename to DeploymentTarget
mosche Feb 10, 2026
ef2a9f3
Rename to DeploymentTarget
mosche Feb 10, 2026
f86e361
Merge remote-tracking branch 'origin/main' into statelessOnPrem/distr…
mosche Feb 10, 2026
1ea1ad3
mark more plugins as STATEFUL_ONLY
mosche Feb 10, 2026
74eaa7e
Merge remote-tracking branch 'origin/main' into statelessOnPrem/distr…
mosche Feb 10, 2026
12a3570
make watcher stateful only
mosche Feb 10, 2026
b6b89d8
Merge remote-tracking branch 'origin/main' into statelessOnPrem/distr…
mosche Mar 5, 2026
40a2b51
Merge remote-tracking branch 'origin/main' into statelessOnPrem/distr…
mosche Mar 5, 2026
1e4e2d0
review
mosche Mar 5, 2026
5dea363
[CI] Auto commit changes from spotless
Mar 5, 2026
73abe4a
review
mosche Mar 5, 2026
6d71fe4
Merge remote-tracking branch 'origin/main' into statelessOnPrem/distr…
mosche Mar 9, 2026
3996474
fix test
mosche Mar 9, 2026
4496e0e
Merge remote-tracking branch 'origin/main' into statelessOnPrem/distr…
mosche Mar 9, 2026
d7cfc5d
Merge branch 'main' into statelessOnPrem/distributionMode
mosche Mar 9, 2026
0e788ca
Merge branch 'main' into statelessOnPrem/distributionMode
mosche Mar 9, 2026
b08e39d
Merge branch 'main' into statelessOnPrem/distributionMode
mosche Mar 10, 2026
a01b8cf
Merge remote-tracking branch 'origin/main' into statelessOnPrem/distr…
mosche Mar 10, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class PluginBuildPluginFuncTest extends AbstractGradleFuncTest {
props.get("has.native.controller") == null
props.get("extended.plugins") == null
props.get("modulename") == null
props.size() == 6
props.size() == 7
}

def "module name is inferred by plugin properties"() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class StablePluginBuildPluginFuncTest extends AbstractGradleFuncTest {
props.get("modulename") == null
props.get("extended.plugins") == null
props.get("has.native.controller") == null
props.size() == 5
props.size() == 6

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ private TaskProvider<Zip> createBundleTasks(final Project project, PluginPropert
task.getHasNativeController().set(providerFactory.provider(extension::isHasNativeController));
task.getRequiresKeystore().set(providerFactory.provider(extension::isRequiresKeystore));
task.getIsLicensed().set(providerFactory.provider(extension::isLicensed));
task.getDeploymentTarget().set(providerFactory.provider(extension::getDeploymentTarget));

var mainSourceSet = project.getExtensions().getByType(SourceSetContainer.class).getByName(SourceSet.MAIN_SOURCE_SET_NAME);
FileCollection moduleInfoFile = mainSourceSet.getOutput()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.inject.Inject;

Expand All @@ -49,6 +50,8 @@ public abstract class GeneratePluginPropertiesTask extends DefaultTask {
public static final String STABLE_PROPERTIES_FILENAME = "stable-plugin-descriptor.properties";
private static final String DESCRIPTION = "Generates Elasticsearch Plugin descriptor file";

private static final Set<String> DEPLOYMENT_TARGETS = Set.of("ALL", "STATELESS_ONLY", "STATEFUL_ONLY");

@Inject
public GeneratePluginPropertiesTask(ProjectLayout projectLayout) {
setDescription(DESCRIPTION);
Expand Down Expand Up @@ -95,6 +98,10 @@ public GeneratePluginPropertiesTask(ProjectLayout projectLayout) {
@Input
public abstract Property<Boolean> getIsStable();

@Input
@Optional
public abstract Property<String> getDeploymentTarget();

@TaskAction
public void generatePropertiesFile() throws IOException {
String classname = getClassname().getOrElse("");
Expand All @@ -119,6 +126,14 @@ public void generatePropertiesFile() throws IOException {
props.put("licensed", getIsLicensed().get());
props.put("modulename", findModuleName());

String deploymentTarget = getDeploymentTarget().getOrElse("ALL");
if (DEPLOYMENT_TARGETS.contains(deploymentTarget) == false) {
throw new InvalidUserDataException(
"invalid deploymentTarget '" + deploymentTarget + "', expected one of " + DEPLOYMENT_TARGETS
);
}
props.put("deploymentTarget", deploymentTarget);

SimpleTemplateEngine engine = new SimpleTemplateEngine();
Path outputFile = getOutputFile().get().getAsFile().toPath();
Files.createDirectories(outputFile.getParent());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ public class PluginPropertiesExtension {
/** True if the plugin requires the elasticsearch keystore to exist, false otherwise. */
private boolean requiresKeystore;

/** The optional deployment target of this plugin. */
private String deploymentTarget;

/** A license file that should be included in the built plugin zip. */
private File licenseFile;

Expand Down Expand Up @@ -117,6 +120,14 @@ public boolean isRequiresKeystore() {
return requiresKeystore;
}

public String getDeploymentTarget() {
return deploymentTarget;
}

public void setDeploymentTarget(String deploymentTarget) {
this.deploymentTarget = deploymentTarget;
}

public void setRequiresKeystore(boolean requiresKeystore) {
this.requiresKeystore = requiresKeystore;
}
Expand Down
3 changes: 3 additions & 0 deletions build-tools/src/main/resources/plugin-descriptor.properties
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,6 @@ has.native.controller=${hasNativeController}
# This plugin requires that a license agreement be accepted before installation
licensed=${licensed}
<% } %>

# The deployment target describing when to include this plugin
deployment.target=${deploymentTarget}
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ public void testPluginWithVerbose() throws Exception {
"Native Controller: false",
"Licensed: false",
"Extended Plugins: []",
" * Classname: org.fake"
" * Classname: org.fake",
"Deployment Target: ALL"
),
terminal.getOutput()
);
Expand All @@ -145,7 +146,8 @@ public void testPluginWithNativeController() throws Exception {
"Native Controller: true",
"Licensed: false",
"Extended Plugins: []",
" * Classname: org.fake"
" * Classname: org.fake",
"Deployment Target: ALL"
),
terminal.getOutput()
);
Expand All @@ -169,6 +171,7 @@ public void testPluginWithVerboseMultiplePlugins() throws Exception {
"Licensed: false",
"Extended Plugins: []",
" * Classname: org.fake",
"Deployment Target: ALL",
"fake_plugin2",
"- Plugin information:",
"Name: fake_plugin2",
Expand All @@ -179,7 +182,8 @@ public void testPluginWithVerboseMultiplePlugins() throws Exception {
"Native Controller: false",
"Licensed: false",
"Extended Plugins: []",
" * Classname: org.fake2"
" * Classname: org.fake2",
"Deployment Target: ALL"
),
terminal.getOutput()
);
Expand Down
1 change: 1 addition & 0 deletions modules/health-shards-availability/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ apply plugin: 'elasticsearch.internal-cluster-test'
esplugin {
description = 'Health report API extension providing the shards_availability output'
classname = 'org.elasticsearch.health.plugin.ShardsAvailabilityPlugin'
deploymentTarget = 'STATEFUL_ONLY'
}

restResources {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.elasticsearch.ReleaseVersions;
import org.elasticsearch.action.support.SubscribableListener;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.common.ReferenceDocs;
import org.elasticsearch.common.io.stream.InputStreamStreamInput;
import org.elasticsearch.common.logging.LogConfigurator;
Expand Down Expand Up @@ -223,8 +224,9 @@ private static void initPhase2(Bootstrap bootstrap) throws IOException {
);

// load the plugin Java modules and layers now for use in entitlements
var modulesBundles = PluginsLoader.loadModulesBundles(nodeEnv.modulesDir());
var pluginsBundles = PluginsLoader.loadPluginsBundles(nodeEnv.pluginsDir());
boolean isStatelessMode = DiscoveryNode.isStateless(nodeEnv.settings());
var modulesBundles = PluginsLoader.loadModulesBundles(nodeEnv.modulesDir(), isStatelessMode);
var pluginsBundles = PluginsLoader.loadPluginsBundles(nodeEnv.pluginsDir(), isStatelessMode);

final PluginsLoader pluginsLoader;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
Expand All @@ -43,6 +44,18 @@ public class PluginDescriptor implements Writeable, ToXContentObject {
public static final String STABLE_DESCRIPTOR_FILENAME = "stable-plugin-descriptor.properties";
public static final String NAMED_COMPONENTS_FILENAME = "named_components.json";

/**
* Deployment target describing when to load a plugin (stateful, stateless, or both).
*/
public enum DeploymentTarget {
/** Only load plugin on stateful deployments (stateless mode disabled) */
STATEFUL_ONLY,
/** Only load plugin on stateless deployments (stateless mode enabled) */
STATELESS_ONLY,
/** All deployment targets (default) */
ALL
}

private final String name;
private final String description;
private final String version;
Expand All @@ -55,6 +68,7 @@ public class PluginDescriptor implements Writeable, ToXContentObject {
private final boolean isLicensed;
private final boolean isModular;
private final boolean isStable;
private final DeploymentTarget deploymentTarget;

/**
* Construct plugin info.
Expand All @@ -71,6 +85,7 @@ public class PluginDescriptor implements Writeable, ToXContentObject {
* @param isLicensed whether is this a licensed plugin
* @param isModular whether this plugin should be loaded in a module layer
* @param isStable whether this plugin is implemented using the stable plugin API
* @param deploymentTarget when to load this plugin
*/
public PluginDescriptor(
String name,
Expand All @@ -84,7 +99,8 @@ public PluginDescriptor(
boolean hasNativeController,
boolean isLicensed,
boolean isModular,
boolean isStable
boolean isStable,
DeploymentTarget deploymentTarget
) {
this.name = name;
this.description = description;
Expand All @@ -98,6 +114,7 @@ public PluginDescriptor(
this.isLicensed = isLicensed;
this.isModular = isModular;
this.isStable = isStable;
this.deploymentTarget = deploymentTarget;

ensureCorrectArgumentsForPluginType();
}
Expand All @@ -123,6 +140,7 @@ public PluginDescriptor(final StreamInput in) throws IOException {

isModular = in.readBoolean();
isStable = in.readBoolean();
deploymentTarget = DeploymentTarget.ALL; // only read from descriptor property files, not serialized

ensureCorrectArgumentsForPluginType();
}
Expand Down Expand Up @@ -253,8 +271,42 @@ private static PluginDescriptor readerInternalDescriptor(Map<String, String> pro

boolean isLicensed = readBoolean(propsMap, name, "licensed");
boolean modular = module != null;

return new PluginDescriptor(name, desc, ver, esVer, javaVer, classname, module, extended, nativeCont, isLicensed, modular, false);
DeploymentTarget deploymentTarget = readDeploymentTarget(propsMap, name);

return new PluginDescriptor(
name,
desc,
ver,
esVer,
javaVer,
classname,
module,
extended,
nativeCont,
isLicensed,
modular,
false,
deploymentTarget
);
}

private static DeploymentTarget readDeploymentTarget(Map<String, String> propsMap, String pluginId) {
String rawValue = propsMap.remove("deployment.target");
if (rawValue == null) {
return DeploymentTarget.ALL;
}
try {
return DeploymentTarget.valueOf(rawValue.trim());
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(
Strings.format(
"Descriptor of plugin [%s] contains invalid deployment.target [%s], expected one of %s",
pluginId,
rawValue,
Arrays.toString(DeploymentTarget.values())
)
);
}
}

private static PluginDescriptor readerStableDescriptor(Map<String, String> propsMap, String filename) {
Expand All @@ -264,8 +316,23 @@ private static PluginDescriptor readerStableDescriptor(Map<String, String> props
String esVer = readElasticsearchVersion(propsMap, name);
String javaVer = readJavaVersion(propsMap, name);
boolean isModular = readBoolean(propsMap, name, "modular");

return new PluginDescriptor(name, desc, ver, esVer, javaVer, null, null, List.of(), false, false, isModular, true);
DeploymentTarget deploymentTarget = readDeploymentTarget(propsMap, name);

return new PluginDescriptor(
name,
desc,
ver,
esVer,
javaVer,
null,
null,
List.of(),
false,
false,
isModular,
true,
deploymentTarget
);
}

private static String readNonEmptyString(Map<String, String> propsMap, String pluginId, String name) {
Expand Down Expand Up @@ -415,6 +482,13 @@ public boolean isStable() {
return isStable;
}

/**
* The deployment target of this plugin, specifically if to include the plugin in stateful and/or stateless mode.
*/
public DeploymentTarget getDeploymentTarget() {
return deploymentTarget;
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
Expand All @@ -433,7 +507,6 @@ public XContentBuilder toXContentFragment(XContentBuilder builder, Params params
builder.field("extended_plugins", extendedPlugins);
builder.field("has_native_controller", hasNativeController);
builder.field("licensed", isLicensed);

return builder;
}

Expand Down Expand Up @@ -470,6 +543,7 @@ public String toString(String prefix) {
appendLine(lines, prefix, "Licensed: ", isLicensed);
appendLine(lines, prefix, "Extended Plugins: ", extendedPlugins.toString());
appendLine(lines, prefix, " * Classname: ", classname);
appendLine(lines, prefix, "Deployment Target: ", deploymentTarget);

return String.join(System.lineSeparator(), lines);
}
Expand Down
Loading