Add Vagrant Gradle plugin (#21348)

This commit changes the current :elactisearch:qa:vagrant build file and transforms it into a Gradle plugin in order to reuse it in other projects.

Most of the code from the build.gradle file has been moved into the VagrantTestPlugin class. To avoid duplicated VMs when running vagrant tests, the Gradle plugin sets the following environment variables before running vagrant commands:
VAGRANT_CWD: absolute path to the folder that contains the Vagrantfile
VAGRANT_PROJECT_DIR: absolute path to the Gradle project that use the VagrantTestPlugin

The VAGRANT_PROJECT_DIR is used to share project folders and files with the vagrant VM. These folders and files are exported when running the task `gradle vagrantSetUp` which:
- collects all project archives dependencies and copies them into `${project.buildDir}/bats/archives`
- copy all project bats testing files from 'src/test/resources/packaging/tests' into `${project.buildDir}/bats/tests`
- copy all project bats utils files from 'src/test/resources/packaging/utils' into `${project.buildDir}/bats/utils`

It is also possible to inherit and grab the archives/tests/utils files from project dependencies using the plugin configuration:

apply plugin: 'elasticsearch.vagrant'
esvagrant {
    inheritTestUtils true|false
    inheritTestArchives true|false
    inheritTests true|false
}
dependencies {
    // Inherit Bats test utils from :qa:vagrant project
    bats project(path: ':qa:vagrant', configuration: 'bats')
}

The folders `${project.buildDir}/bats/archives`, `${project.buildDir}/bats/tests` and `${project.buildDir}/bats/utils` are then exported to the vagrant VMs and mapped to the BATS_ARCHIVES, BATS_TESTS and BATS_UTILS environnement variables.

The following Gradle tasks have also be renamed:

* gradle vagrantSetUp
This task copies all the necessary files to the project build directory (was `prepareTestRoot`)

* gradle vagrantSmokeTest
This task starts the VMs and echoes a "Hello world" within each VM (was: `smokeTest`)
This commit is contained in:
Tanguy Leroux 2016-11-14 13:57:52 +01:00 committed by GitHub
commit b8f50b0219
25 changed files with 589 additions and 316 deletions

View File

@ -325,7 +325,7 @@ vagrant plugin install vagrant-cachier
. Validate your installed dependencies: . Validate your installed dependencies:
------------------------------------- -------------------------------------
gradle :qa:vagrant:checkVagrantVersion gradle :qa:vagrant:vagrantCheckVersion
------------------------------------- -------------------------------------
. Download and smoke test the VMs with `gradle vagrantSmokeTest` or . Download and smoke test the VMs with `gradle vagrantSmokeTest` or
@ -417,17 +417,26 @@ and in another window:
---------------------------------------------------- ----------------------------------------------------
vagrant up centos-7 --provider virtualbox && vagrant ssh centos-7 vagrant up centos-7 --provider virtualbox && vagrant ssh centos-7
cd $TESTROOT cd $BATS_ARCHIVES
sudo bats $BATS/*rpm*.bats sudo -E bats $BATS_TESTS/*rpm*.bats
---------------------------------------------------- ----------------------------------------------------
If you wanted to retest all the release artifacts on a single VM you could: If you wanted to retest all the release artifacts on a single VM you could:
------------------------------------------------- -------------------------------------------------
gradle prepareTestRoot gradle vagrantSetUp
vagrant up ubuntu-1404 --provider virtualbox && vagrant ssh ubuntu-1404 vagrant up ubuntu-1404 --provider virtualbox && vagrant ssh ubuntu-1404
cd $TESTROOT cd $BATS_ARCHIVES
sudo bats $BATS/*.bats sudo -E bats $BATS_TESTS/*.bats
-------------------------------------------------
Note: Starting vagrant VM outside of the elasticsearch folder requires to
indicates the folder that contains the Vagrantfile using the VAGRANT_CWD
environment variable:
-------------------------------------------------
gradle vagrantSetUp
VAGRANT_CWD=/path/to/elasticsearch vagrant up centos-7 --provider virtualbox
------------------------------------------------- -------------------------------------------------
== Coverage analysis == Coverage analysis

9
Vagrantfile vendored
View File

@ -77,6 +77,9 @@ Vagrant.configure(2) do |config|
# the elasticsearch project called vagrant.... # the elasticsearch project called vagrant....
config.vm.synced_folder ".", "/vagrant", disabled: true config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.synced_folder ".", "/elasticsearch" config.vm.synced_folder ".", "/elasticsearch"
# Expose project directory
PROJECT_DIR = ENV['VAGRANT_PROJECT_DIR'] || Dir.pwd
config.vm.synced_folder PROJECT_DIR, "/project"
config.vm.provider "virtualbox" do |v| config.vm.provider "virtualbox" do |v|
# Give the boxes 3GB because Elasticsearch defaults to using 2GB # Give the boxes 3GB because Elasticsearch defaults to using 2GB
v.memory = 3072 v.memory = 3072
@ -272,8 +275,10 @@ export ZIP=/elasticsearch/distribution/zip/build/distributions
export TAR=/elasticsearch/distribution/tar/build/distributions export TAR=/elasticsearch/distribution/tar/build/distributions
export RPM=/elasticsearch/distribution/rpm/build/distributions export RPM=/elasticsearch/distribution/rpm/build/distributions
export DEB=/elasticsearch/distribution/deb/build/distributions export DEB=/elasticsearch/distribution/deb/build/distributions
export TESTROOT=/elasticsearch/qa/vagrant/build/testroot export BATS=/project/build/bats
export BATS=/elasticsearch/qa/vagrant/src/test/resources/packaging/scripts export BATS_UTILS=/project/build/bats/utils
export BATS_TESTS=/project/build/bats/tests
export BATS_ARCHIVES=/project/build/bats/archives
VARS VARS
SHELL SHELL
end end

View File

@ -18,14 +18,7 @@
*/ */
package org.elasticsearch.gradle.vagrant package org.elasticsearch.gradle.vagrant
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Input import org.gradle.api.tasks.Input
import org.gradle.api.tasks.TaskAction
import org.gradle.logging.ProgressLoggerFactory
import org.gradle.process.internal.ExecAction
import org.gradle.process.internal.ExecActionFactory
import javax.inject.Inject
/** /**
* Runs bats over vagrant. Pretty much like running it using Exec but with a * Runs bats over vagrant. Pretty much like running it using Exec but with a

View File

@ -34,11 +34,18 @@ public class VagrantCommandTask extends LoggedExec {
@Input @Input
String boxName String boxName
@Input
Map<String, String> environmentVars
public VagrantCommandTask() { public VagrantCommandTask() {
executable = 'vagrant' executable = 'vagrant'
project.afterEvaluate { project.afterEvaluate {
// It'd be nice if --machine-readable were, well, nice // It'd be nice if --machine-readable were, well, nice
standardOutput = new TeeOutputStream(standardOutput, createLoggerOutputStream()) standardOutput = new TeeOutputStream(standardOutput, createLoggerOutputStream())
if (environmentVars != null) {
environment environmentVars
}
} }
} }

View File

@ -0,0 +1,76 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.gradle.vagrant
import org.gradle.api.tasks.Input
class VagrantPropertiesExtension {
@Input
List<String> boxes
@Input
Long testSeed
@Input
String formattedTestSeed
@Input
String upgradeFromVersion
@Input
List<String> upgradeFromVersions
@Input
String batsDir
@Input
Boolean inheritTests
@Input
Boolean inheritTestArchives
@Input
Boolean inheritTestUtils
VagrantPropertiesExtension(List<String> availableBoxes) {
this.boxes = availableBoxes
this.batsDir = 'src/test/resources/packaging'
}
void boxes(String... boxes) {
this.boxes = Arrays.asList(boxes)
}
void setBatsDir(String batsDir) {
this.batsDir = batsDir
}
void setInheritTests(Boolean inheritTests) {
this.inheritTests = inheritTests
}
void setInheritTestArchives(Boolean inheritTestArchives) {
this.inheritTestArchives = inheritTestArchives
}
void setInheritTestUtils(Boolean inheritTestUtils) {
this.inheritTestUtils = inheritTestUtils
}
}

View File

@ -0,0 +1,457 @@
package org.elasticsearch.gradle.vagrant
import org.elasticsearch.gradle.FileContentsTask
import org.gradle.BuildAdapter
import org.gradle.BuildResult
import org.gradle.api.*
import org.gradle.api.artifacts.dsl.RepositoryHandler
import org.gradle.api.internal.artifacts.dependencies.DefaultProjectDependency
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.Delete
import org.gradle.api.tasks.Exec
class VagrantTestPlugin implements Plugin<Project> {
/** All available boxes **/
static List<String> BOXES = [
'centos-6',
'centos-7',
'debian-8',
'fedora-24',
'oel-6',
'oel-7',
'opensuse-13',
'sles-12',
'ubuntu-1204',
'ubuntu-1404',
'ubuntu-1604'
]
/** Boxes used when sampling the tests **/
static List<String> SAMPLE = [
'centos-7',
'ubuntu-1404',
]
/** All onboarded archives by default, available for Bats tests even if not used **/
static List<String> DISTRIBUTION_ARCHIVES = ['tar', 'rpm', 'deb']
/** Packages onboarded for upgrade tests **/
static List<String> UPGRADE_FROM_ARCHIVES = ['rpm', 'deb']
private static final BATS = 'bats'
private static final String BATS_TEST_COMMAND ="cd \$BATS_ARCHIVES && sudo -E bats --tap \$BATS_TESTS/*.$BATS"
@Override
void apply(Project project) {
// Creates the Vagrant extension for the project
project.extensions.create('esvagrant', VagrantPropertiesExtension, listVagrantBoxes(project))
// Add required repositories for Bats tests
configureBatsRepositories(project)
// Creates custom configurations for Bats testing files (and associated scripts and archives)
createBatsConfiguration(project)
// Creates all the main Vagrant tasks
createVagrantTasks(project)
if (project.extensions.esvagrant.boxes == null || project.extensions.esvagrant.boxes.size() == 0) {
throw new InvalidUserDataException('Vagrant boxes cannot be null or empty for esvagrant')
}
for (String box : project.extensions.esvagrant.boxes) {
if (BOXES.contains(box) == false) {
throw new InvalidUserDataException("Vagrant box [${box}] not found, available virtual machines are ${BOXES}")
}
}
// Creates all tasks related to the Vagrant boxes
createVagrantBoxesTasks(project)
}
private List<String> listVagrantBoxes(Project project) {
String vagrantBoxes = project.getProperties().get('vagrant.boxes', 'sample')
if (vagrantBoxes == 'sample') {
return SAMPLE
} else if (vagrantBoxes == 'all') {
return BOXES
} else {
return vagrantBoxes.split(',')
}
}
private static Set<String> listVersions(Project project) {
Node xml
new URL('https://repo1.maven.org/maven2/org/elasticsearch/elasticsearch/maven-metadata.xml').openStream().withStream { s ->
xml = new XmlParser().parse(s)
}
Set<String> versions = new TreeSet<>(xml.versioning.versions.version.collect { it.text() }.findAll { it ==~ /[5]\.\d\.\d/ })
if (versions.isEmpty() == false) {
return versions;
}
// If no version is found, we run the tests with the current version
return Collections.singleton(project.version);
}
private static File getVersionsFile(Project project) {
File versions = new File(project.projectDir, 'versions');
if (versions.exists() == false) {
// Use the elasticsearch's versions file from project :qa:vagrant
versions = project.project(":qa:vagrant").file('versions')
}
return versions
}
private static void configureBatsRepositories(Project project) {
RepositoryHandler repos = project.repositories
// Try maven central first, it'll have releases before 5.0.0
repos.mavenCentral()
/* Setup a repository that tries to download from
https://artifacts.elastic.co/downloads/elasticsearch/[module]-[revision].[ext]
which should work for 5.0.0+. This isn't a real ivy repository but gradle
is fine with that */
repos.ivy {
artifactPattern "https://artifacts.elastic.co/downloads/elasticsearch/[module]-[revision].[ext]"
}
}
private static void createBatsConfiguration(Project project) {
project.configurations.create(BATS)
Long seed
String formattedSeed = null
String[] upgradeFromVersions
String maybeTestsSeed = System.getProperty("tests.seed", null);
if (maybeTestsSeed != null) {
List<String> seeds = maybeTestsSeed.tokenize(':')
if (seeds.size() != 0) {
String masterSeed = seeds.get(0)
seed = new BigInteger(masterSeed, 16).longValue()
formattedSeed = maybeTestsSeed
}
}
if (formattedSeed == null) {
seed = new Random().nextLong()
formattedSeed = String.format("%016X", seed)
}
String maybeUpdradeFromVersions = System.getProperty("tests.packaging.upgrade.from.versions", null)
if (maybeUpdradeFromVersions != null) {
upgradeFromVersions = maybeUpdradeFromVersions.split(",")
} else {
upgradeFromVersions = getVersionsFile(project)
}
String upgradeFromVersion = upgradeFromVersions[new Random(seed).nextInt(upgradeFromVersions.length)]
DISTRIBUTION_ARCHIVES.each {
// Adds a dependency for the current version
project.dependencies.add(BATS, project.dependencies.project(path: ":distribution:${it}", configuration: 'archives'))
}
UPGRADE_FROM_ARCHIVES.each {
// The version of elasticsearch that we upgrade *from*
project.dependencies.add(BATS, "org.elasticsearch.distribution.${it}:elasticsearch:${upgradeFromVersion}@${it}")
}
project.extensions.esvagrant.testSeed = seed
project.extensions.esvagrant.formattedTestSeed = formattedSeed
project.extensions.esvagrant.upgradeFromVersion = upgradeFromVersion
project.extensions.esvagrant.upgradeFromVersions = upgradeFromVersions
}
private static void createCleanTask(Project project) {
project.tasks.create('clean', Delete.class) {
description 'Clean the project build directory'
group 'Build'
delete project.buildDir
}
}
private static void createStopTask(Project project) {
project.tasks.create('stop') {
description 'Stop any tasks from tests that still may be running'
group 'Verification'
}
}
private static void createSmokeTestTask(Project project) {
project.tasks.create('vagrantSmokeTest') {
description 'Smoke test the specified vagrant boxes'
group 'Verification'
}
}
private static void createPrepareVagrantTestEnvTask(Project project) {
File batsDir = new File("${project.buildDir}/${BATS}")
Task createBatsDirsTask = project.tasks.create('createBatsDirs')
createBatsDirsTask.outputs.dir batsDir
createBatsDirsTask.dependsOn project.tasks.vagrantVerifyVersions
createBatsDirsTask.doLast {
batsDir.mkdirs()
}
Copy copyBatsArchives = project.tasks.create('copyBatsArchives', Copy) {
dependsOn createBatsDirsTask
into "${batsDir}/archives"
from project.configurations[BATS]
}
Copy copyBatsTests = project.tasks.create('copyBatsTests', Copy) {
dependsOn createBatsDirsTask
into "${batsDir}/tests"
from {
"${project.extensions.esvagrant.batsDir}/tests"
}
}
Copy copyBatsUtils = project.tasks.create('copyBatsUtils', Copy) {
dependsOn createBatsDirsTask
into "${batsDir}/utils"
from {
"${project.extensions.esvagrant.batsDir}/utils"
}
}
// Now we iterate over dependencies of the bats configuration. When a project dependency is found,
// we bring back its own archives, test files or test utils.
project.afterEvaluate {
project.configurations.bats.dependencies.findAll {it.configuration == BATS }.each { d ->
if (d instanceof DefaultProjectDependency) {
DefaultProjectDependency externalBatsDependency = (DefaultProjectDependency) d
Project externalBatsProject = externalBatsDependency.dependencyProject
String externalBatsDir = externalBatsProject.extensions.esvagrant.batsDir
if (project.extensions.esvagrant.inheritTests) {
copyBatsTests.from(externalBatsProject.files("${externalBatsDir}/tests"))
}
if (project.extensions.esvagrant.inheritTestArchives) {
copyBatsArchives.from(externalBatsDependency.projectConfiguration.files)
}
if (project.extensions.esvagrant.inheritTestUtils) {
copyBatsUtils.from(externalBatsProject.files("${externalBatsDir}/utils"))
}
}
}
}
Task createVersionFile = project.tasks.create('createVersionFile', FileContentsTask) {
dependsOn createBatsDirsTask
file "${batsDir}/archives/version"
contents project.version
}
Task createUpgradeFromFile = project.tasks.create('createUpgradeFromFile', FileContentsTask) {
dependsOn createBatsDirsTask
file "${batsDir}/archives/upgrade_from_version"
contents project.extensions.esvagrant.upgradeFromVersion
}
Task vagrantSetUpTask = project.tasks.create('vagrantSetUp')
vagrantSetUpTask.dependsOn 'vagrantCheckVersion'
vagrantSetUpTask.dependsOn copyBatsTests, copyBatsUtils, copyBatsArchives, createVersionFile, createUpgradeFromFile
vagrantSetUpTask.doFirst {
project.gradle.addBuildListener new BuildAdapter() {
@Override
void buildFinished(BuildResult result) {
if (result.failure) {
println "Reproduce with: gradle packagingTest "
+"-Pvagrant.boxes=${project.extensions.esvagrant.boxes} "
+ "-Dtests.seed=${project.extensions.esvagrant.formattedSeed} "
+ "-Dtests.packaging.upgrade.from.versions=${project.extensions.esvagrant.upgradeFromVersions.join(",")}"
}
}
}
}
}
private static void createUpdateVersionsTask(Project project) {
project.tasks.create('vagrantUpdateVersions') {
description 'Update file containing options for the\n "starting" version in the "upgrade from" packaging tests.'
group 'Verification'
doLast {
File versions = getVersionsFile(project)
versions.text = listVersions(project).join('\n') + '\n'
}
}
}
private static void createVerifyVersionsTask(Project project) {
project.tasks.create('vagrantVerifyVersions') {
description 'Update file containing options for the\n "starting" version in the "upgrade from" packaging tests.'
group 'Verification'
doLast {
String maybeUpdateFromVersions = System.getProperty("tests.packaging.upgrade.from.versions", null)
if (maybeUpdateFromVersions == null) {
Set<String> versions = listVersions(project)
Set<String> actualVersions = new TreeSet<>(project.extensions.esvagrant.upgradeFromVersions)
if (!versions.equals(actualVersions)) {
throw new GradleException("out-of-date versions " + actualVersions +
", expected " + versions + "; run gradle vagrantUpdateVersions")
}
}
}
}
}
private static void createCheckVagrantVersionTask(Project project) {
project.tasks.create('vagrantCheckVersion', Exec) {
description 'Check the Vagrant version'
group 'Verification'
commandLine 'vagrant', '--version'
standardOutput = new ByteArrayOutputStream()
doLast {
String version = standardOutput.toString().trim()
if ((version ==~ /Vagrant 1\.(8\.[6-9]|9\.[0-9])+/) == false) {
throw new InvalidUserDataException("Illegal version of vagrant [${version}]. Need [Vagrant 1.8.6+]")
}
}
}
}
private static void createCheckVirtualBoxVersionTask(Project project) {
project.tasks.create('virtualboxCheckVersion', Exec) {
description 'Check the Virtualbox version'
group 'Verification'
commandLine 'vboxmanage', '--version'
standardOutput = new ByteArrayOutputStream()
doLast {
String version = standardOutput.toString().trim()
try {
String[] versions = version.split('\\.')
int major = Integer.parseInt(versions[0])
int minor = Integer.parseInt(versions[1])
if ((major < 5) || (major == 5 && minor < 1)) {
throw new InvalidUserDataException("Illegal version of virtualbox [${version}]. Need [5.1+]")
}
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
throw new InvalidUserDataException("Unable to parse version of virtualbox [${version}]. Required [5.1+]", e)
}
}
}
}
private static void createPackagingTestTask(Project project) {
project.tasks.create('packagingTest') {
group 'Verification'
description "Tests yum/apt packages using vagrant and bats.\n" +
" Specify the vagrant boxes to test using the gradle property 'vagrant.boxes'.\n" +
" 'sample' can be used to test a single yum and apt box. 'all' can be used to\n" +
" test all available boxes. The available boxes are: \n" +
" ${BOXES}"
dependsOn 'vagrantCheckVersion'
}
}
private static void createVagrantTasks(Project project) {
createCleanTask(project)
createStopTask(project)
createSmokeTestTask(project)
createUpdateVersionsTask(project)
createVerifyVersionsTask(project)
createCheckVagrantVersionTask(project)
createCheckVirtualBoxVersionTask(project)
createPrepareVagrantTestEnvTask(project)
createPackagingTestTask(project)
}
private static void createVagrantBoxesTasks(Project project) {
assert project.extensions.esvagrant.boxes != null
assert project.tasks.stop != null
Task stop = project.tasks.stop
assert project.tasks.vagrantSmokeTest != null
Task vagrantSmokeTest = project.tasks.vagrantSmokeTest
assert project.tasks.vagrantCheckVersion != null
Task vagrantCheckVersion = project.tasks.vagrantCheckVersion
assert project.tasks.virtualboxCheckVersion != null
Task virtualboxCheckVersion = project.tasks.virtualboxCheckVersion
assert project.tasks.vagrantSetUp != null
Task vagrantSetUp = project.tasks.vagrantSetUp
assert project.tasks.packagingTest != null
Task packagingTest = project.tasks.packagingTest
/*
* We always use the main project.rootDir as Vagrant's current working directory (VAGRANT_CWD)
* so that boxes are not duplicated for every Gradle project that use this VagrantTestPlugin.
*/
def vagrantEnvVars = [
'VAGRANT_CWD' : "${project.rootDir.absolutePath}",
'VAGRANT_VAGRANTFILE' : 'Vagrantfile',
'VAGRANT_PROJECT_DIR' : "${project.projectDir.absolutePath}"
]
// Each box gets it own set of tasks
for (String box : BOXES) {
String boxTask = box.capitalize().replace('-', '')
// always add a halt task for all boxes, so clean makes sure they are all shutdown
Task halt = project.tasks.create("vagrant${boxTask}#halt", VagrantCommandTask) {
boxName box
environmentVars vagrantEnvVars
args 'halt', box
}
stop.dependsOn(halt)
if (project.extensions.esvagrant.boxes.contains(box) == false) {
// we only need a halt task if this box was not specified
continue;
}
Task update = project.tasks.create("vagrant${boxTask}#update", VagrantCommandTask) {
boxName box
environmentVars vagrantEnvVars
args 'box', 'update', box
dependsOn vagrantCheckVersion, virtualboxCheckVersion, vagrantSetUp
}
Task up = project.tasks.create("vagrant${boxTask}#up", VagrantCommandTask) {
boxName box
environmentVars vagrantEnvVars
/* Its important that we try to reprovision the box even if it already
exists. That way updates to the vagrant configuration take automatically.
That isn't to say that the updates will always be compatible. Its ok to
just destroy the boxes if they get busted but that is a manual step
because its slow-ish. */
/* We lock the provider to virtualbox because the Vagrantfile specifies
lots of boxes that only work properly in virtualbox. Virtualbox is
vagrant's default but its possible to change that default and folks do.
But the boxes that we use are unlikely to work properly with other
virtualization providers. Thus the lock. */
args 'up', box, '--provision', '--provider', 'virtualbox'
/* It'd be possible to check if the box is already up here and output
SKIPPED but that would require running vagrant status which is slow! */
dependsOn update
}
Task smoke = project.tasks.create("vagrant${boxTask}#smoketest", Exec) {
environment vagrantEnvVars
dependsOn up
finalizedBy halt
commandLine 'vagrant', 'ssh', box, '--command',
"set -o pipefail && echo 'Hello from ${project.path}' | sed -ue 's/^/ ${box}: /'"
}
vagrantSmokeTest.dependsOn(smoke)
Task packaging = project.tasks.create("vagrant${boxTask}#packagingtest", BatsOverVagrantTask) {
boxName box
environmentVars vagrantEnvVars
dependsOn up
finalizedBy halt
command BATS_TEST_COMMAND
}
packagingTest.dependsOn(packaging)
}
}
}

View File

@ -0,0 +1 @@
implementation-class=org.elasticsearch.gradle.vagrant.VagrantTestPlugin

View File

@ -17,288 +17,13 @@
* under the License. * under the License.
*/ */
import org.elasticsearch.gradle.FileContentsTask apply plugin: 'elasticsearch.vagrant'
import org.elasticsearch.gradle.vagrant.BatsOverVagrantTask
import org.elasticsearch.gradle.vagrant.VagrantCommandTask
String testScripts = '*.bats'
String testCommand = "cd \$TESTROOT && sudo bats --tap \$BATS/$testScripts"
String smokeTestCommand = 'echo I work'
// the images we allow testing with
List<String> availableBoxes = [
'centos-6',
'centos-7',
'debian-8',
'fedora-24',
'oel-6',
'oel-7',
'opensuse-13',
'sles-12',
'ubuntu-1204',
'ubuntu-1404',
'ubuntu-1604'
]
String vagrantBoxes = getProperties().get('vagrant.boxes', 'sample')
List<String> boxes = []
for (String box : vagrantBoxes.split(',')) {
if (box == 'sample') {
boxes.add('centos-7')
boxes.add('ubuntu-1404')
} else if (box == 'all') {
boxes = availableBoxes
break
} else {
if (availableBoxes.contains(box) == false) {
throw new IllegalArgumentException("Unknown vagrant box '${box}'")
}
boxes.add(box)
}
}
long seed
String formattedSeed = null
String[] upgradeFromVersions
String upgradeFromVersion
String maybeTestsSeed = System.getProperty("tests.seed", null);
if (maybeTestsSeed != null) {
List<String> seeds = maybeTestsSeed.tokenize(':')
if (seeds.size() != 0) {
String masterSeed = seeds.get(0)
seed = new BigInteger(masterSeed, 16).longValue()
formattedSeed = maybeTestsSeed
}
}
if (formattedSeed == null) {
seed = new Random().nextLong()
formattedSeed = String.format("%016X", seed)
}
String maybeUpdradeFromVersions = System.getProperty("tests.packaging.upgrade.from.versions", null)
if (maybeUpdradeFromVersions != null) {
upgradeFromVersions = maybeUpdradeFromVersions.split(",")
} else {
upgradeFromVersions = new File(project.projectDir, 'versions')
}
upgradeFromVersion = upgradeFromVersions[new Random(seed).nextInt(upgradeFromVersions.length)]
configurations {
test
}
repositories {
mavenCentral() // Try maven central first, it'll have releases before 5.0.0
/* Setup a repository that tries to download from
https://artifacts.elastic.co/downloads/elasticsearch/[module]-[revision].[ext]
which should work for 5.0.0+. This isn't a real ivy repository but gradle
is fine with that */
ivy {
artifactPattern "https://artifacts.elastic.co/downloads/elasticsearch/[module]-[revision].[ext]"
}
}
dependencies { dependencies {
test project(path: ':distribution:tar', configuration: 'archives')
test project(path: ':distribution:rpm', configuration: 'archives')
test project(path: ':distribution:deb', configuration: 'archives')
// Collect all the plugins // Collect all the plugins
for (Project subproj : project.rootProject.subprojects) { for (Project subproj : project.rootProject.subprojects) {
if (subproj.path.startsWith(':plugins:')) { if (subproj.path.startsWith(':plugins:')) {
test project(path: "${subproj.path}", configuration: 'zip') bats project(path: "${subproj.path}", configuration: 'zip')
}
}
// The version of elasticsearch that we upgrade *from*
test "org.elasticsearch.distribution.deb:elasticsearch:$upgradeFromVersion@deb"
test "org.elasticsearch.distribution.rpm:elasticsearch:$upgradeFromVersion@rpm"
}
task clean(type: Delete) {
group 'Build'
delete buildDir
}
task stop {
group 'Verification'
description 'Stop any tasks from tests that still may be running'
}
Set<String> getVersions() {
Node xml
new URL('https://repo1.maven.org/maven2/org/elasticsearch/elasticsearch/maven-metadata.xml').openStream().withStream { s ->
xml = new XmlParser().parse(s)
}
Set<String> versions = new TreeSet<>(xml.versioning.versions.version.collect { it.text() }.findAll { it ==~ /[5]\.\d\.\d/ })
if (versions.isEmpty() == false) {
return versions;
}
// If no version is found, we run the tests with the current version
return Collections.singleton(project.version);
}
task updatePackagingTestUpgradeFromVersions {
group 'Verification'
description 'Update file containing options for the\n "starting" version in the "upgrade from" packaging tests.'
doLast {
Set<String> versions = getVersions()
new File(project.projectDir, 'versions').text = versions.join('\n') + '\n'
}
}
task verifyPackagingTestUpgradeFromVersions {
doLast {
String maybeUpdateFromVersions = System.getProperty("tests.packaging.upgrade.from.versions", null)
if (maybeUpdateFromVersions == null) {
Set<String> versions = getVersions()
Set<String> actualVersions = new TreeSet<>(Arrays.asList(upgradeFromVersions))
if (!versions.equals(actualVersions)) {
throw new GradleException("out-of-date versions " + actualVersions +
", expected " + versions + "; run gradle updatePackagingTestUpgradeFromVersions")
}
}
}
}
File testRoot = new File("$buildDir/testroot")
task createTestRoot {
dependsOn verifyPackagingTestUpgradeFromVersions
outputs.dir testRoot
doLast {
testRoot.mkdirs()
}
}
task createVersionFile(type: FileContentsTask) {
dependsOn createTestRoot
file "${testRoot}/version"
contents = version
}
task createUpgradeFromFile(type: FileContentsTask) {
dependsOn createTestRoot
file "${testRoot}/upgrade_from_version"
contents = upgradeFromVersion
}
task prepareTestRoot(type: Copy) {
description 'Dump bats test dependencies into the $TESTROOT'
into testRoot
from configurations.test
dependsOn createVersionFile, createUpgradeFromFile
doFirst {
gradle.addBuildListener new BuildAdapter() {
@Override
void buildFinished(BuildResult result) {
if (result.failure) {
println "Reproduce with: gradle packagingTest -Pvagrant.boxes=${vagrantBoxes} -Dtests.seed=${formattedSeed} -Dtests.packaging.upgrade.from.versions=${upgradeFromVersions.join(",")}"
}
}
} }
} }
} }
task checkVagrantVersion(type: Exec) {
commandLine 'vagrant', '--version'
standardOutput = new ByteArrayOutputStream()
doLast {
String version = standardOutput.toString().trim()
if ((version ==~ /Vagrant 1\.(8\.[6-9]|9\.[0-9])+/) == false) {
throw new InvalidUserDataException("Illegal version of vagrant [${version}]. Need [Vagrant 1.8.6+]")
}
}
}
task checkVirtualBoxVersion(type: Exec) {
commandLine 'vboxmanage', '--version'
standardOutput = new ByteArrayOutputStream()
doLast {
String version = standardOutput.toString().trim()
try {
String[] versions = version.split('\\.')
int major = Integer.parseInt(versions[0])
int minor = Integer.parseInt(versions[1])
if ((major < 5) || (major == 5 && minor < 1)) {
throw new InvalidUserDataException("Illegal version of virtualbox [${version}]. Need [5.1+]")
}
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
throw new InvalidUserDataException("Unable to parse version of virtualbox [${version}]. Required [5.1+]", e)
}
}
}
task vagrantSmokeTest {
group 'Verification'
description 'Smoke test the specified vagrant boxes'
}
task packagingTest {
group 'Verification'
description "Tests yum/apt packages using vagrant and bats.\n" +
" Specify the vagrant boxes to test using the gradle property 'vagrant.boxes'.\n" +
" 'sample' can be used to test a single yum and apt box. 'all' can be used to\n" +
" test all available boxes. The available boxes are: \n" +
" ${availableBoxes}"
}
// Each box gets it own set of tasks
for (String box : availableBoxes) {
String boxTask = box.capitalize().replace('-', '')
// always add a halt task for all boxes, so clean makes sure they are all shutdown
Task halt = tasks.create("vagrant${boxTask}#halt", VagrantCommandTask) {
boxName box
args 'halt', box
}
stop.dependsOn(halt)
if (boxes.contains(box) == false) {
// we only need a halt task if this box was not specified
continue;
}
Task update = tasks.create("vagrant${boxTask}#update", VagrantCommandTask) {
boxName box
args 'box', 'update', box
dependsOn checkVagrantVersion, checkVirtualBoxVersion
}
Task up = tasks.create("vagrant${boxTask}#up", VagrantCommandTask) {
boxName box
/* It's important that we try to reprovision the box even if it already
exists. That way updates to the vagrant configuration take automatically.
That isn't to say that the updates will always be compatible. Its ok to
just destroy the boxes if they get busted but that is a manual step
because its slow-ish. */
/* We lock the provider to virtualbox because the Vagrantfile specifies
lots of boxes that only work properly in virtualbox. Virtualbox is
vagrant's default but its possible to change that default and folks do.
But the boxes that we use are unlikely to work properly with other
virtualization providers. Thus the lock. */
args 'up', box, '--provision', '--provider', 'virtualbox'
/* It'd be possible to check if the box is already up here and output
SKIPPED but that would require running vagrant status which is slow! */
dependsOn update
}
Task smoke = tasks.create("vagrant${boxTask}#smoketest", Exec) {
dependsOn up
finalizedBy halt
commandLine 'vagrant', 'ssh', box, '--command',
"set -o pipefail && ${smokeTestCommand} | sed -ue 's/^/ ${box}: /'"
}
vagrantSmokeTest.dependsOn(smoke)
Task packaging = tasks.create("packagingTest${boxTask}", BatsOverVagrantTask) {
dependsOn up
finalizedBy halt
boxName box
command testCommand
dependsOn prepareTestRoot
}
packagingTest.dependsOn(packaging)
}

View File

@ -29,9 +29,9 @@
# under the License. # under the License.
# Load test utilities # Load test utilities
load packaging_test_utils load $BATS_UTILS/utils.bash
load tar load $BATS_UTILS/tar.bash
load plugins load $BATS_UTILS/plugins.bash
setup() { setup() {
skip_not_tar_gz skip_not_tar_gz

View File

@ -30,9 +30,9 @@
# under the License. # under the License.
# Load test utilities # Load test utilities
load packaging_test_utils load $BATS_UTILS/utils.bash
load os_package load $BATS_UTILS/packages.bash
load plugins load $BATS_UTILS/plugins.bash
# Cleans everything for the 1st execution # Cleans everything for the 1st execution
setup() { setup() {

View File

@ -29,9 +29,9 @@
# under the License. # under the License.
# Load test utilities # Load test utilities
load packaging_test_utils load $BATS_UTILS/utils.bash
load os_package load $BATS_UTILS/packages.bash
load plugins load $BATS_UTILS/plugins.bash
# Cleans everything for the 1st execution # Cleans everything for the 1st execution
setup() { setup() {

View File

@ -29,9 +29,9 @@
# under the License. # under the License.
# Load test utilities # Load test utilities
load packaging_test_utils load $BATS_UTILS/utils.bash
load os_package load $BATS_UTILS/packages.bash
load plugins load $BATS_UTILS/plugins.bash
# Cleans everything for the 1st execution # Cleans everything for the 1st execution
setup() { setup() {

View File

@ -29,9 +29,9 @@
# under the License. # under the License.
# Load test utilities # Load test utilities
load packaging_test_utils load $BATS_UTILS/utils.bash
load os_package load $BATS_UTILS/packages.bash
load plugins load $BATS_UTILS/plugins.bash
# Cleans everything for the 1st execution # Cleans everything for the 1st execution
setup() { setup() {

View File

@ -31,8 +31,8 @@
# under the License. # under the License.
# Load test utilities # Load test utilities
load packaging_test_utils load $BATS_UTILS/utils.bash
load os_package load $BATS_UTILS/packages.bash
# Cleans everything for the 1st execution # Cleans everything for the 1st execution
setup() { setup() {

View File

@ -31,8 +31,8 @@
# under the License. # under the License.
# Load test utilities # Load test utilities
load packaging_test_utils load $BATS_UTILS/utils.bash
load os_package load $BATS_UTILS/packages.bash
# Cleans everything for the 1st execution # Cleans everything for the 1st execution
setup() { setup() {

View File

@ -39,9 +39,9 @@
# system uses. # system uses.
# Load test utilities # Load test utilities
load packaging_test_utils load $BATS_UTILS/utils.bash
load modules load $BATS_UTILS/modules.bash
load plugins load $BATS_UTILS/plugins.bash
setup() { setup() {
# The rules on when we should clean an reinstall are complex - all the # The rules on when we should clean an reinstall are complex - all the
@ -60,7 +60,7 @@ setup() {
} }
if [[ "$BATS_TEST_FILENAME" =~ 25_tar_plugins.bats$ ]]; then if [[ "$BATS_TEST_FILENAME" =~ 25_tar_plugins.bats$ ]]; then
load tar load $BATS_UTILS/tar.bash
GROUP='TAR PLUGINS' GROUP='TAR PLUGINS'
install() { install() {
install_archive install_archive
@ -70,7 +70,7 @@ if [[ "$BATS_TEST_FILENAME" =~ 25_tar_plugins.bats$ ]]; then
export_elasticsearch_paths export_elasticsearch_paths
export ESPLUGIN_COMMAND_USER=elasticsearch export ESPLUGIN_COMMAND_USER=elasticsearch
else else
load os_package load $BATS_UTILS/packages.bash
if is_rpm; then if is_rpm; then
GROUP='RPM PLUGINS' GROUP='RPM PLUGINS'
elif is_dpkg; then elif is_dpkg; then