28
28
import org .elasticsearch .gradle .ElasticsearchDistribution .Type ;
29
29
import org .elasticsearch .gradle .Jdk ;
30
30
import org .elasticsearch .gradle .JdkDownloadPlugin ;
31
+ import org .elasticsearch .gradle .OS ;
31
32
import org .elasticsearch .gradle .Version ;
32
33
import org .elasticsearch .gradle .VersionProperties ;
33
34
import org .elasticsearch .gradle .info .BuildParams ;
34
35
import org .elasticsearch .gradle .vagrant .BatsProgressLogger ;
35
36
import org .elasticsearch .gradle .vagrant .VagrantBasePlugin ;
36
37
import org .elasticsearch .gradle .vagrant .VagrantExtension ;
38
+ import org .gradle .api .GradleException ;
37
39
import org .gradle .api .NamedDomainObjectContainer ;
38
40
import org .gradle .api .Plugin ;
39
41
import org .gradle .api .Project ;
40
42
import org .gradle .api .Task ;
41
43
import org .gradle .api .artifacts .Configuration ;
42
44
import org .gradle .api .file .Directory ;
45
+ import org .gradle .api .logging .Logger ;
46
+ import org .gradle .api .logging .Logging ;
43
47
import org .gradle .api .plugins .ExtraPropertiesExtension ;
44
48
import org .gradle .api .plugins .JavaBasePlugin ;
45
49
import org .gradle .api .provider .Provider ;
52
56
import java .io .UncheckedIOException ;
53
57
import java .nio .file .Files ;
54
58
import java .nio .file .Path ;
59
+ import java .nio .file .Paths ;
55
60
import java .util .ArrayList ;
56
61
import java .util .Arrays ;
57
62
import java .util .HashMap ;
66
71
import static org .elasticsearch .gradle .vagrant .VagrantMachine .convertWindowsPath ;
67
72
68
73
public class DistroTestPlugin implements Plugin <Project > {
74
+ private static final Logger logger = Logging .getLogger (DistroTestPlugin .class );
69
75
70
76
private static final String SYSTEM_JDK_VERSION = "11.0.2+9" ;
71
77
private static final String SYSTEM_JDK_VENDOR = "openjdk" ;
@@ -84,6 +90,8 @@ public class DistroTestPlugin implements Plugin<Project> {
84
90
85
91
@ Override
86
92
public void apply (Project project ) {
93
+ final boolean runDockerTests = shouldRunDockerTests (project );
94
+
87
95
project .getPluginManager ().apply (DistributionDownloadPlugin .class );
88
96
project .getPluginManager ().apply (BuildPlugin .class );
89
97
@@ -95,15 +103,17 @@ public void apply(Project project) {
95
103
Provider <Directory > upgradeDir = project .getLayout ().getBuildDirectory ().dir ("packaging/upgrade" );
96
104
Provider <Directory > pluginsDir = project .getLayout ().getBuildDirectory ().dir ("packaging/plugins" );
97
105
98
- List <ElasticsearchDistribution > distributions = configureDistributions (project , upgradeVersion );
106
+ List <ElasticsearchDistribution > distributions = configureDistributions (project , upgradeVersion , runDockerTests );
99
107
TaskProvider <Copy > copyDistributionsTask = configureCopyDistributionsTask (project , distributionsDir );
100
108
TaskProvider <Copy > copyUpgradeTask = configureCopyUpgradeTask (project , upgradeVersion , upgradeDir );
101
109
TaskProvider <Copy > copyPluginsTask = configureCopyPluginsTask (project , pluginsDir );
102
110
103
111
TaskProvider <Task > destructiveDistroTest = project .getTasks ().register ("destructiveDistroTest" );
104
112
for (ElasticsearchDistribution distribution : distributions ) {
105
- TaskProvider <?> destructiveTask = configureDistroTest (project , distribution );
106
- destructiveDistroTest .configure (t -> t .dependsOn (destructiveTask ));
113
+ if (distribution .getType () != Type .DOCKER || runDockerTests == true ) {
114
+ TaskProvider <?> destructiveTask = configureDistroTest (project , distribution );
115
+ destructiveDistroTest .configure (t -> t .dependsOn (destructiveTask ));
116
+ }
107
117
}
108
118
Map <String , TaskProvider <?>> batsTests = new HashMap <>();
109
119
batsTests .put ("bats oss" , configureBatsTest (project , "oss" , distributionsDir , copyDistributionsTask ));
@@ -129,7 +139,23 @@ public void apply(Project project) {
129
139
TaskProvider <GradleDistroTestTask > vmTask =
130
140
configureVMWrapperTask (vmProject , distribution .getName () + " distribution" , destructiveTaskName , vmDependencies );
131
141
vmTask .configure (t -> t .dependsOn (distribution ));
132
- distroTest .configure (t -> t .dependsOn (vmTask ));
142
+
143
+ distroTest .configure (t -> {
144
+ // Only VM sub-projects that are specifically opted-in to testing Docker should
145
+ // have the Docker task added as a dependency. Although we control whether Docker
146
+ // is installed in the VM via `Vagrantfile` and we could auto-detect its presence
147
+ // in the VM, the test tasks e.g. `destructiveDistroTest.default-docker` are defined
148
+ // on the host during Gradle's configuration phase and not in the VM, so
149
+ // auto-detection doesn't work.
150
+ //
151
+ // The shouldTestDocker property could be null, hence we use Boolean.TRUE.equals()
152
+ boolean shouldExecute = distribution .getType () != Type .DOCKER
153
+ || Boolean .TRUE .equals (vmProject .findProperty ("shouldTestDocker" )) == true ;
154
+
155
+ if (shouldExecute ) {
156
+ t .dependsOn (vmTask );
157
+ }
158
+ });
133
159
}
134
160
}
135
161
@@ -321,17 +347,17 @@ private static TaskProvider<BatsTestTask> configureBatsTest(Project project, Str
321
347
});
322
348
}
323
349
324
- private List <ElasticsearchDistribution > configureDistributions (Project project , Version upgradeVersion ) {
350
+ private List <ElasticsearchDistribution > configureDistributions (Project project , Version upgradeVersion , boolean runDockerTests ) {
325
351
NamedDomainObjectContainer <ElasticsearchDistribution > distributions = DistributionDownloadPlugin .getContainer (project );
326
352
List <ElasticsearchDistribution > currentDistros = new ArrayList <>();
327
353
List <ElasticsearchDistribution > upgradeDistros = new ArrayList <>();
328
354
329
- // Docker disabled for https://github.com/elastic/elasticsearch/issues/47639
330
- for (Type type : Arrays .asList (Type .DEB , Type .RPM /*,Type.DOCKER*/ )) {
355
+ for (Type type : List .of (Type .DEB , Type .RPM , Type .DOCKER )) {
331
356
for (Flavor flavor : Flavor .values ()) {
332
357
for (boolean bundledJdk : Arrays .asList (true , false )) {
333
- // We should never add a Docker distro with bundledJdk == false
334
- boolean skip = type == Type .DOCKER && bundledJdk == false ;
358
+ // All our Docker images include a bundled JDK so it doesn't make sense to test without one
359
+ boolean skip = type == Type .DOCKER && (runDockerTests == false || bundledJdk == false );
360
+
335
361
if (skip == false ) {
336
362
addDistro (distributions , type , null , flavor , bundledJdk , VersionProperties .getElasticsearch (), currentDistros );
337
363
}
@@ -345,6 +371,7 @@ private List<ElasticsearchDistribution> configureDistributions(Project project,
345
371
addDistro (distributions , type , null , Flavor .OSS , true , upgradeVersion .toString (), upgradeDistros );
346
372
}
347
373
}
374
+
348
375
for (Platform platform : Arrays .asList (Platform .LINUX , Platform .WINDOWS )) {
349
376
for (Flavor flavor : Flavor .values ()) {
350
377
for (boolean bundledJdk : Arrays .asList (true , false )) {
@@ -405,4 +432,92 @@ private static String destructiveDistroTestTaskName(ElasticsearchDistribution di
405
432
distro .getFlavor (),
406
433
distro .getBundledJdk ());
407
434
}
435
+
436
+ static Map <String , String > parseOsRelease (final List <String > osReleaseLines ) {
437
+ final Map <String , String > values = new HashMap <>();
438
+
439
+ osReleaseLines .stream ().map (String ::trim ).filter (line -> (line .isEmpty () || line .startsWith ("#" )) == false ).forEach (line -> {
440
+ final String [] parts = line .split ("=" , 2 );
441
+ final String key = parts [0 ];
442
+ // remove optional leading and trailing quotes and whitespace
443
+ final String value = parts [1 ].replaceAll ("^['\" ]?\\ s*" , "" ).replaceAll ("\\ s*['\" ]?$" , "" );
444
+
445
+ values .put (key , value );
446
+ });
447
+
448
+ return values ;
449
+ }
450
+
451
+ static String deriveId (final Map <String , String > osRelease ) {
452
+ return osRelease .get ("ID" ) + "-" + osRelease .get ("VERSION_ID" );
453
+ }
454
+
455
+ private static List <String > getLinuxExclusionList (Project project ) {
456
+ final String exclusionsFilename = "dockerOnLinuxExclusions" ;
457
+ final Path exclusionsPath = project .getRootDir ().toPath ().resolve (Path .of (".ci" , exclusionsFilename ));
458
+
459
+ try {
460
+ return Files .readAllLines (exclusionsPath )
461
+ .stream ()
462
+ .map (String ::trim )
463
+ .filter (line -> (line .isEmpty () || line .startsWith ("#" )) == false )
464
+ .collect (Collectors .toList ());
465
+ } catch (IOException e ) {
466
+ throw new GradleException ("Failed to read .ci/" + exclusionsFilename , e );
467
+ }
468
+ }
469
+
470
+ /**
471
+ * The {@link DistroTestPlugin} generates a number of test tasks, some
472
+ * of which are Docker packaging tests. When running on the host OS or in CI
473
+ * i.e. not in a Vagrant VM, only certain operating systems are supported. This
474
+ * method determines whether the Docker tests should be run on the host
475
+ * OS. Essentially, unless an OS and version is specifically excluded, we expect
476
+ * to be able to run Docker and test the Docker images.
477
+ * @param project
478
+ */
479
+ private static boolean shouldRunDockerTests (Project project ) {
480
+ switch (OS .current ()) {
481
+ case WINDOWS :
482
+ // Not yet supported.
483
+ return false ;
484
+
485
+ case MAC :
486
+ // Assume that Docker for Mac is installed, since Docker is part of the dev workflow.
487
+ return true ;
488
+
489
+ case LINUX :
490
+ // Only some hosts in CI are configured with Docker. We attempt to work out the OS
491
+ // and version, so that we know whether to expect to find Docker. We don't attempt
492
+ // to probe for whether Docker is available, because that doesn't tell us whether
493
+ // Docker is unavailable when it should be.
494
+ final Path osRelease = Paths .get ("/etc/os-release" );
495
+
496
+ if (Files .exists (osRelease )) {
497
+ Map <String , String > values ;
498
+
499
+ try {
500
+ final List <String > osReleaseLines = Files .readAllLines (osRelease );
501
+ values = parseOsRelease (osReleaseLines );
502
+ } catch (IOException e ) {
503
+ throw new GradleException ("Failed to read /etc/os-release" , e );
504
+ }
505
+
506
+ final String id = deriveId (values );
507
+
508
+ final boolean shouldExclude = getLinuxExclusionList (project ).contains (id );
509
+
510
+ logger .warn ("Linux OS id [" + id + "] is " + (shouldExclude ? "" : "not " ) + "present in the Docker exclude list" );
511
+
512
+ return shouldExclude == false ;
513
+ }
514
+
515
+ logger .warn ("/etc/os-release does not exist!" );
516
+ return false ;
517
+
518
+ default :
519
+ logger .warn ("Unknown OS [" + OS .current () + "], answering false to shouldRunDockerTests()" );
520
+ return false ;
521
+ }
522
+ }
408
523
}
0 commit comments