Skip to content

Commit d2dbef5

Browse files
authored
Convert repository plugins to modules (elastic#81870)
Closes elastic#81652. Convert the `repository-azure`, `repository-gcs` and `repository-s3` plugins into modules, so that they are always included in the Elasticsearch distribution. Also change plugin installation, removal and syncing so that attempting to add or remove these plugins still succeeds but is now a no-op.
1 parent 78509f4 commit d2dbef5

File tree

286 files changed

+628
-304
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

286 files changed

+628
-304
lines changed

.ci/scripts/packaging-test.sh

-5
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,6 @@ if [ -f "/etc/os-release" ] ; then
3737
if [[ "$ID" == "debian" || "$ID_LIKE" == "debian" ]] ; then
3838
# FIXME: The base image should not have rpm installed
3939
sudo rm -Rf /usr/bin/rpm
40-
# Work around incorrect lintian version
41-
# https://github.com/elastic/elasticsearch/issues/48573
42-
if [ $VERSION_ID == 10 ] ; then
43-
sudo apt-get install -y --allow-downgrades lintian=2.15.0
44-
fi
4540
fi
4641
else
4742
cat /etc/issue || true

build-tools-internal/src/main/groovy/elasticsearch.ide.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ if (providers.systemProperty('idea.active').forUseAtConfigurationTime().getOrNul
8888
tasks.register('buildDependencyArtifacts') {
8989
group = 'ide'
9090
description = 'Builds artifacts needed as dependency for IDE modules'
91-
dependsOn ':client:rest-high-level:shadowJar', ':plugins:repository-hdfs:hadoop-client-api:shadowJar', ':plugins:repository-azure:azure-storage-blob:shadowJar'
91+
dependsOn ':client:rest-high-level:shadowJar', ':plugins:repository-hdfs:hadoop-client-api:shadowJar', ':modules:repository-azure:azure-storage-blob:shadowJar'
9292
}
9393

9494
idea {

distribution/docker/build.gradle

+3-7
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ configurations {
7070
dockerSource
7171
log4jConfig
7272
tini
73-
repositoryPlugins
74-
nonRepositoryPlugins
73+
allPlugins
7574
filebeat
7675
metricbeat
7776
cloudflareZlib
@@ -85,8 +84,7 @@ dependencies {
8584
dockerSource project(path: ":distribution:archives:linux-tar", configuration: 'default')
8685
log4jConfig project(path: ":distribution", configuration: 'log4jConfig')
8786
tini "krallin:tini:0.19.0:${tiniArch}"
88-
repositoryPlugins project(path: ':plugins', configuration: 'repositoryPlugins')
89-
nonRepositoryPlugins project(path: ':plugins', configuration: 'nonRepositoryPlugins')
87+
allPlugins project(path: ':plugins', configuration: 'allPlugins')
9088
filebeat "beats:filebeat:${VersionProperties.elasticsearch}:${beatsArch}@tar.gz"
9189
metricbeat "beats:metricbeat:${VersionProperties.elasticsearch}:${beatsArch}@tar.gz"
9290
cloudflareZlib "cloudflare:zlib:${cloudflareZlibVersion}@tar.gz"
@@ -272,8 +270,6 @@ void addBuildDockerContextTask(Architecture architecture, DockerBase base) {
272270
String buildId = providers.systemProperty('build.id').forUseAtConfigurationTime().getOrNull()
273271
boolean includeBeats = VersionProperties.isElasticsearchSnapshot() == true || buildId != null
274272

275-
from configurations.repositoryPlugins
276-
277273
if (includeBeats) {
278274
from configurations.filebeat
279275
from configurations.metricbeat
@@ -407,7 +403,7 @@ void addBuildEssDockerImageTask(Architecture architecture) {
407403
final Path projectDir = project.projectDir.toPath()
408404

409405
into("plugins") {
410-
from configurations.nonRepositoryPlugins
406+
from configurations.allPlugins
411407
}
412408

413409
from(projectDir.resolve("src/docker/Dockerfile.cloud-ess")) {

distribution/docker/src/docker/Dockerfile

-12
Original file line numberDiff line numberDiff line change
@@ -137,18 +137,6 @@ RUN sed -i -e 's/ES_DISTRIBUTION_TYPE=tar/ES_DISTRIBUTION_TYPE=docker/' bin/elas
137137
find config -type f -exec chmod 0664 {} +
138138

139139
<% if (docker_base == "cloud") { %>
140-
# Preinstall common plugins. Note that these are installed as root, meaning the `elasticsearch` user cannot delete them.
141-
COPY repository-s3-${version}.zip repository-gcs-${version}.zip repository-azure-${version}.zip /tmp/
142-
RUN bin/elasticsearch-plugin install --batch --verbose \\
143-
file:/tmp/repository-s3-${version}.zip \\
144-
file:/tmp/repository-gcs-${version}.zip \\
145-
file:/tmp/repository-azure-${version}.zip
146-
# Generate a replacement example plugins config that reflects what is actually installed
147-
RUN echo "plugins:" > config/elasticsearch-plugins.example.yml && \\
148-
echo " - id: repository-azure" >> config/elasticsearch-plugins.example.yml && \\
149-
echo " - id: repository-gcs" >> config/elasticsearch-plugins.example.yml && \\
150-
echo " - id: repository-s3" >> config/elasticsearch-plugins.example.yml
151-
152140
COPY filebeat-${version}.tar.gz metricbeat-${version}.tar.gz /tmp/
153141
RUN set -eux ; \\
154142
for beat in filebeat metricbeat ; do \\

distribution/packages/build.gradle

+4-2
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,10 @@ Closure commonDebConfig(String architecture) {
291291
return {
292292
configure(commonPackageConfig('deb', architecture))
293293

294-
// jdeb does not provide a way to set the License control attribute, and ospackage
295-
// silently ignores setting it. Instead, we set the license as "custom field"
294+
// jdeb does not provide a way to set the License control attribute, and
295+
// ospackage silently ignores setting it. This is probably because `License`
296+
// is not actually a field in the Debian control file. So instead, we set
297+
// the license as "custom field".
296298
customFields['License'] = 'Elastic-License'
297299

298300
archiveVersion = project.version.replace('-', '~')

distribution/packages/src/common/scripts/postinst

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
# $1=0 : indicates a removal
99
# $1=1 : indicates an upgrade
1010

11+
set -e
12+
1113
# source the default env file
1214
if [ -f "@path.env@" ]; then
1315
. "@path.env@"

distribution/packages/src/common/scripts/postrm

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
# $1=0 : indicates a removal
1010
# $1=1 : indicates an upgrade
1111

12+
set -e
13+
1214
# source the default env file
1315
if [ -f "@path.env@" ]; then
1416
. "@path.env@"

distribution/packages/src/common/scripts/posttrans

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
set -e
2+
13
# source the default env file
24
if [ -f "@path.env@" ]; then
35
. "@path.env@"

distribution/packages/src/common/scripts/preinst

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
# $1=1 : indicates an new install
1111
# $1=2 : indicates an upgrade
1212

13+
set -e
14+
1315
err_exit() {
1416
echo "$@" >&2
1517
exit 1

distribution/packages/src/common/scripts/prerm

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
# $1=0 : indicates a removal
1010
# $1=1 : indicates an upgrade
1111

12+
set -e
13+
1214
# source the default env file
1315
if [ -f "@path.env@" ]; then
1416
. "@path.env@"

distribution/packages/src/deb/lintian/elasticsearch

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
# we don't have a changelog, but we put our copyright file
22
# under /usr/share/doc/elasticsearch, which triggers this warning
3+
# Note that this is renamed to `no-changelog` in newer versions of
4+
# lintian, but we still support Debian 8+, so we can't change this.
35
changelog-file-missing-in-native-package
46

57
# we intentionally copy our copyright file for all deb packages
68
copyright-file-contains-full-apache-2-license
7-
copyright-should-refer-to-common-license-file-for-apache-2
9+
copyright-not-using-common-license-for-apache2
810
copyright-without-copyright-notice
911

1012
# we still put all our files under /usr/share/elasticsearch even after transition to platform dependent packages
@@ -21,7 +23,7 @@ non-standard-file-perm etc/elasticsearch/*
2123
non-standard-dir-perm var/lib/elasticsearch/ 2750 != 0755
2224
non-standard-dir-perm var/log/elasticsearch/ 2750 != 0755
2325

24-
# this lintian tag is simply wrong; contrary to the explanation, debian systemd
26+
# this lintian tag is simply wrong; contrary to the explanation, Debian systemd
2527
# does actually look at /usr/lib/systemd/system
2628
systemd-service-file-outside-lib usr/lib/systemd/system/elasticsearch.service
2729

@@ -30,7 +32,6 @@ maintainer-script-calls-systemctl
3032

3133
# bundled JDK
3234
embedded-library
33-
arch-dependent-file-in-usr-share usr/share/elasticsearch/jdk/*
3435
unstripped-binary-or-object usr/share/elasticsearch/jdk/*
3536
extra-license-file usr/share/elasticsearch/jdk/legal/*
3637
hardening-no-pie usr/share/elasticsearch/jdk/bin/*
@@ -41,3 +42,12 @@ unknown-java-class-version
4142

4243
# elastic licensed modules contain elastic license
4344
extra-license-file usr/share/elasticsearch/modules/*
45+
46+
# This dependency appears to have a packaging flaw, and includes a
47+
# generated source file alongside the compiled version
48+
jar-contains-source usr/share/elasticsearch/modules/repository-gcs/api-common*.jar *
49+
50+
# There's no `License` field in Debian control files, but earlier versions
51+
# of `lintian` were more permissive. Override this warning so that we can
52+
# run `lintian` on different releases of Debian.
53+
unknown-field elasticsearch-*.deb License

distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/cli/InstallPluginAction.java

+16
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,13 @@ public class InstallPluginAction implements Closeable {
153153
}
154154
}
155155

156+
/**
157+
* IDs of plugins that have been migrated to modules and do not require installation. This data is
158+
* maintained so that existing user workflows that install these plugins do not need to be updated
159+
* immediately.
160+
*/
161+
public static final Set<String> PLUGINS_CONVERTED_TO_MODULES = Set.of("repository-azure", "repository-gcs", "repository-s3");
162+
156163
static final Set<PosixFilePermission> BIN_DIR_PERMS;
157164
static final Set<PosixFilePermission> BIN_FILES_PERMS;
158165
static final Set<PosixFilePermission> CONFIG_DIR_PERMS;
@@ -219,6 +226,15 @@ public void execute(List<PluginDescriptor> plugins) throws Exception {
219226
handleInstallXPack(buildFlavor());
220227
}
221228

229+
if (PLUGINS_CONVERTED_TO_MODULES.contains(pluginId)) {
230+
// This deliberately does not throw an exception in order to avoid failing automation that relies on installing this
231+
// plugin during deployment.
232+
terminal.errorPrintln(
233+
"[" + pluginId + "] is no longer a plugin but instead a module packaged with this distribution of Elasticsearch"
234+
);
235+
continue;
236+
}
237+
222238
final List<Path> deleteOnFailure = new ArrayList<>();
223239
deleteOnFailures.put(pluginId, deleteOnFailure);
224240

distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/cli/PluginDescriptor.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
package org.elasticsearch.plugins.cli;
1010

11+
import org.elasticsearch.common.Strings;
12+
1113
import java.util.Objects;
1214

1315
/**
@@ -27,7 +29,7 @@ public PluginDescriptor() {}
2729
* coordinates. Can be null for official plugins.
2830
*/
2931
public PluginDescriptor(String id, String location) {
30-
this.id = Objects.requireNonNull(id, "id cannot be null");
32+
this.id = Strings.requireNonBlank(id, "plugin id cannot be null or blank");
3133
this.location = location;
3234
}
3335

@@ -40,7 +42,7 @@ public String getId() {
4042
}
4143

4244
public void setId(String id) {
43-
this.id = id;
45+
this.id = Strings.requireNonBlank(id, "plugin id cannot be null or blank");
4446
}
4547

4648
public String getLocation() {

distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/cli/PluginsConfig.java

+8-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
package org.elasticsearch.plugins.cli;
1010

11+
import org.elasticsearch.common.Strings;
1112
import org.elasticsearch.xcontent.ObjectParser;
1213
import org.elasticsearch.xcontent.ParseField;
1314
import org.elasticsearch.xcontent.XContent;
@@ -57,10 +58,12 @@ public void setProxy(String proxy) {
5758
* </ul>
5859
*
5960
* @param officialPlugins the plugins that can be installed by name only
61+
* @param migratedPlugins plugins that were once official but have since become modules. These
62+
* plugin IDs can still be specified, but do nothing.
6063
* @throws PluginSyncException if validation problems are found
6164
*/
62-
public void validate(Set<String> officialPlugins) throws PluginSyncException {
63-
if (this.plugins.stream().anyMatch(each -> each == null || each.getId() == null || each.getId().isBlank())) {
65+
public void validate(Set<String> officialPlugins, Set<String> migratedPlugins) throws PluginSyncException {
66+
if (this.plugins.stream().anyMatch(each -> each == null || Strings.isNullOrBlank(each.getId()))) {
6467
throw new RuntimeException("Cannot have null or empty IDs in [elasticsearch-plugins.yml]");
6568
}
6669

@@ -72,7 +75,9 @@ public void validate(Set<String> officialPlugins) throws PluginSyncException {
7275
}
7376

7477
for (PluginDescriptor plugin : this.plugins) {
75-
if (officialPlugins.contains(plugin.getId()) == false && plugin.getLocation() == null) {
78+
if (officialPlugins.contains(plugin.getId()) == false
79+
&& migratedPlugins.contains(plugin.getId()) == false
80+
&& plugin.getLocation() == null) {
7681
throw new PluginSyncException(
7782
"Must specify location for non-official plugin [" + plugin.getId() + "] in [elasticsearch-plugins.yml]"
7883
);

distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/cli/RemovePluginAction.java

+18-10
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@
2626
import java.util.Map;
2727
import java.util.Set;
2828
import java.util.StringJoiner;
29-
import java.util.stream.Collectors;
3029
import java.util.stream.Stream;
3130

3231
import static org.elasticsearch.cli.Terminal.Verbosity.VERBOSE;
32+
import static org.elasticsearch.plugins.cli.InstallPluginAction.PLUGINS_CONVERTED_TO_MODULES;
3333

3434
/**
3535
* An action for the plugin CLI to remove plugins from Elasticsearch.
@@ -116,6 +116,7 @@ private void ensurePluginsNotUsedByOtherPlugins(List<PluginDescriptor> plugins)
116116

117117
private void checkCanRemove(PluginDescriptor plugin) throws UserException {
118118
String pluginId = plugin.getId();
119+
119120
final Path pluginDir = env.pluginsFile().resolve(pluginId);
120121
final Path pluginConfigDir = env.configFile().resolve(pluginId);
121122
final Path removing = env.pluginsFile().resolve(".removing-" + pluginId);
@@ -127,12 +128,19 @@ private void checkCanRemove(PluginDescriptor plugin) throws UserException {
127128
*/
128129
if ((Files.exists(pluginDir) == false && Files.exists(pluginConfigDir) == false && Files.exists(removing) == false)
129130
|| (Files.exists(pluginDir) == false && Files.exists(pluginConfigDir) && this.purge == false)) {
130-
final String message = String.format(
131-
Locale.ROOT,
132-
"plugin [%s] not found; run 'elasticsearch-plugin list' to get list of installed plugins",
133-
pluginId
134-
);
135-
throw new UserException(ExitCodes.CONFIG, message);
131+
132+
if (PLUGINS_CONVERTED_TO_MODULES.contains(pluginId)) {
133+
terminal.errorPrintln(
134+
"plugin [" + pluginId + "] is no longer a plugin but instead a module packaged with this distribution of Elasticsearch"
135+
);
136+
} else {
137+
final String message = String.format(
138+
Locale.ROOT,
139+
"plugin [%s] not found; run 'elasticsearch-plugin list' to get list of installed plugins",
140+
pluginId
141+
);
142+
throw new UserException(ExitCodes.CONFIG, message);
143+
}
136144
}
137145

138146
final Path pluginBinDir = env.binFile().resolve(pluginId);
@@ -159,15 +167,15 @@ private void removePlugin(PluginDescriptor plugin) throws IOException {
159167
*/
160168
if (Files.exists(pluginDir)) {
161169
try (Stream<Path> paths = Files.list(pluginDir)) {
162-
pluginPaths.addAll(paths.collect(Collectors.toList()));
170+
pluginPaths.addAll(paths.toList());
163171
}
164172
terminal.println(VERBOSE, "removing [" + pluginDir + "]");
165173
}
166174

167175
final Path pluginBinDir = env.binFile().resolve(pluginId);
168176
if (Files.exists(pluginBinDir)) {
169177
try (Stream<Path> paths = Files.list(pluginBinDir)) {
170-
pluginPaths.addAll(paths.collect(Collectors.toList()));
178+
pluginPaths.addAll(paths.toList());
171179
}
172180
pluginPaths.add(pluginBinDir);
173181
terminal.println(VERBOSE, "removing [" + pluginBinDir + "]");
@@ -176,7 +184,7 @@ private void removePlugin(PluginDescriptor plugin) throws IOException {
176184
if (Files.exists(pluginConfigDir)) {
177185
if (this.purge) {
178186
try (Stream<Path> paths = Files.list(pluginConfigDir)) {
179-
pluginPaths.addAll(paths.collect(Collectors.toList()));
187+
pluginPaths.addAll(paths.toList());
180188
}
181189
pluginPaths.add(pluginConfigDir);
182190
terminal.println(VERBOSE, "removing [" + pluginConfigDir + "]");

0 commit comments

Comments
 (0)