Skip to content

Commit b3bbf4e

Browse files
committed
Merge branch 'master' into security_api_keys
2 parents 554bf23 + 891a37a commit b3bbf4e

File tree

641 files changed

+10997
-3627
lines changed

Some content is hidden

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

641 files changed

+10997
-3627
lines changed

buildSrc/src/main/groovy/org/elasticsearch/gradle/BuildPlugin.groovy

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import org.gradle.api.tasks.compile.JavaCompile
5151
import org.gradle.api.tasks.javadoc.Javadoc
5252
import org.gradle.internal.jvm.Jvm
5353
import org.gradle.process.ExecResult
54+
import org.gradle.process.ExecSpec
5455
import org.gradle.util.GradleVersion
5556

5657
import java.nio.charset.StandardCharsets
@@ -232,6 +233,95 @@ class BuildPlugin implements Plugin<Project> {
232233
project.ext.java9Home = project.rootProject.ext.java9Home
233234
}
234235

236+
static void requireDocker(final Task task) {
237+
final Project rootProject = task.project.rootProject
238+
if (rootProject.hasProperty('requiresDocker') == false) {
239+
/*
240+
* This is our first time encountering a task that requires Docker. We will add an extension that will let us track the tasks
241+
* that register as requiring Docker. We will add a delayed execution that when the task graph is ready if any such tasks are
242+
* in the task graph, then we check two things:
243+
* - the Docker binary is available
244+
* - we can execute a Docker command that requires privileges
245+
*
246+
* If either of these fail, we fail the build.
247+
*/
248+
final boolean buildDocker
249+
final String buildDockerProperty = System.getProperty("build.docker")
250+
if (buildDockerProperty == null || buildDockerProperty == "true") {
251+
buildDocker = true
252+
} else if (buildDockerProperty == "false") {
253+
buildDocker = false
254+
} else {
255+
throw new IllegalArgumentException(
256+
"expected build.docker to be unset or one of \"true\" or \"false\" but was [" + buildDockerProperty + "]")
257+
}
258+
rootProject.rootProject.ext.buildDocker = buildDocker
259+
rootProject.rootProject.ext.requiresDocker = []
260+
rootProject.gradle.taskGraph.whenReady { TaskExecutionGraph taskGraph ->
261+
// check if the Docker binary exists and record its path
262+
final List<String> maybeDockerBinaries = ['/usr/bin/docker', '/usr/local/bin/docker']
263+
final String dockerBinary = maybeDockerBinaries.find { it -> new File(it).exists() }
264+
265+
int exitCode
266+
String dockerErrorOutput
267+
if (dockerBinary == null) {
268+
exitCode = -1
269+
dockerErrorOutput = null
270+
} else {
271+
// the Docker binary executes, check that we can execute a privileged command
272+
final ByteArrayOutputStream output = new ByteArrayOutputStream()
273+
final ExecResult result = LoggedExec.exec(rootProject, { ExecSpec it ->
274+
it.commandLine dockerBinary, "images"
275+
it.errorOutput = output
276+
it.ignoreExitValue = true
277+
})
278+
if (result.exitValue == 0) {
279+
return
280+
}
281+
exitCode = result.exitValue
282+
dockerErrorOutput = output.toString()
283+
}
284+
final List<String> tasks =
285+
((List<Task>)rootProject.requiresDocker).findAll { taskGraph.hasTask(it) }.collect { " ${it.path}".toString()}
286+
if (tasks.isEmpty() == false) {
287+
/*
288+
* There are tasks in the task graph that require Docker. Now we are failing because either the Docker binary does not
289+
* exist or because execution of a privileged Docker command failed.
290+
*/
291+
String message
292+
if (dockerBinary == null) {
293+
message = String.format(
294+
Locale.ROOT,
295+
"Docker (checked [%s]) is required to run the following task%s: \n%s",
296+
maybeDockerBinaries.join(","),
297+
tasks.size() > 1 ? "s" : "",
298+
tasks.join('\n'))
299+
} else {
300+
assert exitCode > 0 && dockerErrorOutput != null
301+
message = String.format(
302+
Locale.ROOT,
303+
"a problem occurred running Docker from [%s] yet it is required to run the following task%s: \n%s\n" +
304+
"the problem is that Docker exited with exit code [%d] with standard error output [%s]",
305+
dockerBinary,
306+
tasks.size() > 1 ? "s" : "",
307+
tasks.join('\n'),
308+
exitCode,
309+
dockerErrorOutput.trim())
310+
}
311+
throw new GradleException(
312+
message + "\nyou can address this by attending to the reported issue, "
313+
+ "removing the offending tasks from being executed, "
314+
+ "or by passing -Dbuild.docker=false")
315+
}
316+
}
317+
}
318+
if (rootProject.buildDocker) {
319+
rootProject.requiresDocker.add(task)
320+
} else {
321+
task.enabled = false
322+
}
323+
}
324+
235325
private static String findCompilerJavaHome() {
236326
String compilerJavaHome = System.getenv('JAVA_HOME')
237327
final String compilerJavaProperty = System.getProperty('compiler.java')
@@ -773,7 +863,6 @@ class BuildPlugin implements Plugin<Project> {
773863
project.tasks.withType(RandomizedTestingTask) {task ->
774864
jvm "${project.runtimeJavaHome}/bin/java"
775865
parallelism System.getProperty('tests.jvms', project.rootProject.ext.defaultParallel)
776-
ifNoTests System.getProperty('tests.ifNoTests', 'fail')
777866
onNonEmptyWorkDirectory 'wipe'
778867
leaveTemporary true
779868

@@ -785,10 +874,6 @@ class BuildPlugin implements Plugin<Project> {
785874
task.shouldRunAfter testTask
786875
}
787876
}
788-
// no loose ends: check has to depend on all test tasks
789-
project.tasks.matching {it.name == "check"}.all {
790-
dependsOn(task)
791-
}
792877

793878
// TODO: why are we not passing maxmemory to junit4?
794879
jvmArg '-Xmx' + System.getProperty('tests.heap.size', '512m')

buildSrc/src/main/groovy/org/elasticsearch/gradle/doc/RestTestsFromSnippetsTask.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public class RestTestsFromSnippetsTask extends SnippetsTask {
104104
* format of the response is incompatible i.e. it is not a JSON object.
105105
*/
106106
static shouldAddShardFailureCheck(String path) {
107-
return path.startsWith('_cat') == false && path.startsWith('_xpack/ml/datafeeds/') == false
107+
return path.startsWith('_cat') == false && path.startsWith('_ml/datafeeds/') == false
108108
}
109109

110110
/**

buildSrc/src/main/groovy/org/elasticsearch/gradle/plugin/PluginBuildPlugin.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ public class PluginBuildPlugin extends BuildPlugin {
129129
RestIntegTestTask integTest = project.tasks.create('integTest', RestIntegTestTask.class)
130130
integTest.mustRunAfter(project.precommit, project.test)
131131
project.integTestCluster.distribution = System.getProperty('tests.distribution', 'integ-test-zip')
132+
project.check.dependsOn(integTest)
132133
}
133134

134135
/**

buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterConfiguration.groovy

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,22 @@ class ClusterConfiguration {
7676
}
7777
}
7878

79+
/**
80+
* Whether the initial_master_nodes setting should be automatically derived from the nodes
81+
* in the cluster. Only takes effect if all nodes in the cluster understand this setting
82+
* and the discovery type is not explicitly set.
83+
*/
84+
@Input
85+
boolean autoSetInitialMasterNodes = true
86+
87+
/**
88+
* Whether the file-based discovery provider should be automatically setup based on
89+
* the nodes in the cluster. Only takes effect if no other hosts provider is already
90+
* configured.
91+
*/
92+
@Input
93+
boolean autoSetHostsProvider = true
94+
7995
@Input
8096
String jvmArgs = "-Xms" + System.getProperty('tests.heap.size', '512m') +
8197
" " + "-Xmx" + System.getProperty('tests.heap.size', '512m') +

buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919
package org.elasticsearch.gradle.test
2020

21+
import java.util.stream.Collectors
2122
import org.apache.tools.ant.DefaultLogger
2223
import org.apache.tools.ant.taskdefs.condition.Os
2324
import org.elasticsearch.gradle.BuildPlugin
@@ -92,7 +93,8 @@ class ClusterFormationTasks {
9293
throw new Exception("tests.distribution=integ-test-zip is not supported")
9394
}
9495
configureDistributionDependency(project, config.distribution, currentDistro, VersionProperties.elasticsearch)
95-
if (config.numBwcNodes > 0) {
96+
boolean hasBwcNodes = config.numBwcNodes > 0
97+
if (hasBwcNodes) {
9698
if (config.bwcVersion == null) {
9799
throw new IllegalArgumentException("Must specify bwcVersion when numBwcNodes > 0")
98100
}
@@ -129,11 +131,23 @@ class ClusterFormationTasks {
129131
Object dependsOn
130132
if (node.nodeVersion.onOrAfter("6.5.0")) {
131133
writeConfigSetup = { Map esConfig ->
132-
// Don't force discovery provider if one is set by the test cluster specs already
133-
if (esConfig.containsKey('discovery.zen.hosts_provider') == false) {
134-
esConfig['discovery.zen.hosts_provider'] = 'file'
134+
if (config.getAutoSetHostsProvider()) {
135+
// Don't force discovery provider if one is set by the test cluster specs already
136+
if (esConfig.containsKey('discovery.zen.hosts_provider') == false) {
137+
esConfig['discovery.zen.hosts_provider'] = 'file'
138+
}
139+
esConfig['discovery.zen.ping.unicast.hosts'] = []
140+
}
141+
boolean supportsInitialMasterNodes = hasBwcNodes == false || config.bwcVersion.onOrAfter("7.0.0")
142+
if (esConfig['discovery.type'] == null && config.getAutoSetInitialMasterNodes() && supportsInitialMasterNodes) {
143+
esConfig['cluster.initial_master_nodes'] = nodes.stream().map({ n ->
144+
if (n.config.settings['node.name'] == null) {
145+
return "node-" + n.nodeNum
146+
} else {
147+
return n.config.settings['node.name']
148+
}
149+
}).collect(Collectors.toList())
135150
}
136-
esConfig['discovery.zen.ping.unicast.hosts'] = []
137151
esConfig
138152
}
139153
dependsOn = startDependencies

buildSrc/src/main/groovy/org/elasticsearch/gradle/test/RestIntegTestTask.groovy

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,10 @@
1919
package org.elasticsearch.gradle.test
2020

2121
import com.carrotsearch.gradle.junit4.RandomizedTestingTask
22-
import org.elasticsearch.gradle.BuildPlugin
2322
import org.elasticsearch.gradle.VersionProperties
2423
import org.gradle.api.DefaultTask
25-
import org.gradle.api.Project
2624
import org.gradle.api.Task
2725
import org.gradle.api.execution.TaskExecutionAdapter
28-
import org.gradle.api.provider.Property
29-
import org.gradle.api.provider.Provider
3026
import org.gradle.api.tasks.Copy
3127
import org.gradle.api.tasks.Input
3228
import org.gradle.api.tasks.TaskState
@@ -36,7 +32,6 @@ import org.gradle.plugins.ide.idea.IdeaPlugin
3632
import java.nio.charset.StandardCharsets
3733
import java.nio.file.Files
3834
import java.util.stream.Stream
39-
4035
/**
4136
* A wrapper task around setting up a cluster and running rest tests.
4237
*/

buildSrc/src/main/java/org/elasticsearch/gradle/LoggedExec.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,18 @@ public class LoggedExec extends Exec {
2121

2222
public LoggedExec() {
2323
ByteArrayOutputStream output = new ByteArrayOutputStream();
24+
ByteArrayOutputStream error = new ByteArrayOutputStream();
2425
if (getLogger().isInfoEnabled() == false) {
2526
setStandardOutput(output);
26-
setErrorOutput(output);
27+
setErrorOutput(error);
2728
setIgnoreExitValue(true);
2829
doLast((unused) -> {
2930
if (getExecResult().getExitValue() != 0) {
3031
try {
31-
for (String line : output.toString("UTF-8").split("\\R")) {
32-
getLogger().error(line);
33-
}
32+
getLogger().error("Standard output:");
33+
getLogger().error(output.toString("UTF-8"));
34+
getLogger().error("Standard error:");
35+
getLogger().error(error.toString("UTF-8"));
3436
} catch (UnsupportedEncodingException e) {
3537
throw new GradleException("Failed to read exec output", e);
3638
}
@@ -65,17 +67,19 @@ private static <T extends BaseExecSpec> ExecResult genericExec(
6567
return function.apply(action);
6668
}
6769
ByteArrayOutputStream output = new ByteArrayOutputStream();
70+
ByteArrayOutputStream error = new ByteArrayOutputStream();
6871
try {
6972
return function.apply(spec -> {
7073
spec.setStandardOutput(output);
71-
spec.setErrorOutput(output);
74+
spec.setErrorOutput(error);
7275
action.execute(spec);
7376
});
7477
} catch (Exception e) {
7578
try {
76-
for (String line : output.toString("UTF-8").split("\\R")) {
77-
project.getLogger().error(line);
78-
}
79+
project.getLogger().error("Standard output:");
80+
project.getLogger().error(output.toString("UTF-8"));
81+
project.getLogger().error("Standard error:");
82+
project.getLogger().error(error.toString("UTF-8"));
7983
} catch (UnsupportedEncodingException ue) {
8084
throw new GradleException("Failed to read exec output", ue);
8185
}

buildSrc/src/main/java/org/elasticsearch/gradle/precommit/TestingConventionsTasks.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import org.gradle.api.file.FileTree;
2626
import org.gradle.api.tasks.Input;
2727
import org.gradle.api.tasks.OutputFile;
28-
import org.gradle.api.tasks.SkipWhenEmpty;
2928
import org.gradle.api.tasks.TaskAction;
3029
import org.gradle.api.tasks.testing.Test;
3130
import org.gradle.api.tasks.util.PatternFilterable;
@@ -103,6 +102,22 @@ public void doCheck() throws IOException {
103102
final Map<String, Set<File>> classFilesPerRandomizedTestingTask = classFilesPerRandomizedTestingTask(allTestClassFiles);
104103
final Map<String, Set<File>> classFilesPerGradleTestTask = classFilesPerGradleTestTask();
105104

105+
Map<String, Set<Class<?>>> testClassesPerTask =
106+
Stream.concat(
107+
classFilesPerGradleTestTask.entrySet().stream(),
108+
classFilesPerRandomizedTestingTask.entrySet().stream()
109+
)
110+
.collect(
111+
Collectors.toMap(
112+
Map.Entry::getKey,
113+
entry -> entry.getValue().stream()
114+
.map(classes::get)
115+
.filter(implementsNamingConvention)
116+
.collect(Collectors.toSet())
117+
)
118+
);
119+
120+
106121
problems = collectProblems(
107122
checkNoneExists(
108123
"Test classes implemented by inner classes will not run",
@@ -118,6 +133,16 @@ public void doCheck() throws IOException {
118133
.filter(this::seemsLikeATest)
119134
.filter(implementsNamingConvention.negate())
120135
),
136+
collectProblems(
137+
testClassesPerTask.entrySet().stream()
138+
.map( entry ->
139+
checkAtLeastOneExists(
140+
"test class in " + entry.getKey(),
141+
entry.getValue().stream()
142+
)
143+
)
144+
.collect(Collectors.joining())
145+
),
121146
checkNoneExists(
122147
"Test classes are not included in any enabled task (" +
123148
Stream.concat(
@@ -215,7 +240,6 @@ private Class<? extends Task> getRandomizedTestingTask() {
215240
}
216241

217242
@Input
218-
@SkipWhenEmpty
219243
public Map<String, File> getTestClassNames() {
220244
if (testClassNames == null) {
221245
testClassNames = Boilerplate.getJavaSourceSets(getProject()).getByName("test").getOutput().getClassesDirs()
@@ -243,6 +267,14 @@ private String checkNoneExists(String message, Stream<? extends Class<?>> stream
243267
}
244268
}
245269

270+
private String checkAtLeastOneExists(String message, Stream<? extends Class<?>> stream) {
271+
if (stream.findAny().isPresent()) {
272+
return "";
273+
} else {
274+
return "Expected at least one " + message + ", but found none.\n";
275+
}
276+
}
277+
246278
private boolean seemsLikeATest(Class<?> clazz) {
247279
try {
248280
ClassLoader classLoader = clazz.getClassLoader();

0 commit comments

Comments
 (0)