Skip to content

Commit

Permalink
Introduce packaging tests for Docker (elastic#46599)
Browse files Browse the repository at this point in the history
Closes elastic#37617. Add packaging tests for our Docker images, similar to what
we have for RPMs or Debian packages. This works by running a container and
probing it e.g. via `docker exec`. Test can also be run in Vagrant, by
exporting the Docker images to disk and loading them again in VMs. Docker
is installed via `Vagrantfile` in a selection of boxes.
  • Loading branch information
pugnascotia authored Oct 5, 2019
1 parent 3d4a7d0 commit da59dfe
Show file tree
Hide file tree
Showing 16 changed files with 817 additions and 30 deletions.
105 changes: 103 additions & 2 deletions Vagrantfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# vim: ft=ruby ts=2 sw=2 sts=2 et:

# This Vagrantfile exists to test packaging. Read more about its use in the
# vagrant section in TESTING.asciidoc.
Expand Down Expand Up @@ -63,6 +63,7 @@ Vagrant.configure(2) do |config|
# Install Jayatana so we can work around it being present.
[ -f /usr/share/java/jayatanaag.jar ] || install jayatana
SHELL
ubuntu_docker config
end
end
'ubuntu-1804'.tap do |box|
Expand All @@ -72,6 +73,7 @@ Vagrant.configure(2) do |config|
# Install Jayatana so we can work around it being present.
[ -f /usr/share/java/jayatanaag.jar ] || install jayatana
SHELL
ubuntu_docker config
end
end
'debian-8'.tap do |box|
Expand All @@ -87,6 +89,7 @@ Vagrant.configure(2) do |config|
config.vm.define box, define_opts do |config|
config.vm.box = 'elastic/debian-9-x86_64'
deb_common config, box
deb_docker config
end
end
'centos-6'.tap do |box|
Expand All @@ -99,6 +102,7 @@ Vagrant.configure(2) do |config|
config.vm.define box, define_opts do |config|
config.vm.box = 'elastic/centos-7-x86_64'
rpm_common config, box
rpm_docker config
end
end
'oel-6'.tap do |box|
Expand All @@ -117,12 +121,14 @@ Vagrant.configure(2) do |config|
config.vm.define box, define_opts do |config|
config.vm.box = 'elastic/fedora-28-x86_64'
dnf_common config, box
dnf_docker config
end
end
'fedora-29'.tap do |box|
config.vm.define box, define_opts do |config|
config.vm.box = 'elastic/fedora-28-x86_64'
dnf_common config, box
dnf_docker config
end
end
'opensuse-42'.tap do |box|
Expand Down Expand Up @@ -185,6 +191,63 @@ def deb_common(config, name, extra: '')
)
end

def ubuntu_docker(config)
config.vm.provision 'install Docker using apt', type: 'shell', inline: <<-SHELL
# Install packages to allow apt to use a repository over HTTPS
apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg2 \
software-properties-common
# Add Docker’s official GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
# Set up the stable Docker repository
add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
# Install Docker. Unlike Fedora and CentOS, this also start the daemon.
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io
# Add vagrant to the Docker group, so that it can run commands
usermod -aG docker vagrant
SHELL
end


def deb_docker(config)
config.vm.provision 'install Docker using apt', type: 'shell', inline: <<-SHELL
# Install packages to allow apt to use a repository over HTTPS
apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg2 \
software-properties-common
# Add Docker’s official GPG key
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
# Set up the stable Docker repository
add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/debian \
$(lsb_release -cs) \
stable"
# Install Docker. Unlike Fedora and CentOS, this also start the daemon.
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io
# Add vagrant to the Docker group, so that it can run commands
usermod -aG docker vagrant
SHELL
end

def rpm_common(config, name)
linux_common(
config,
Expand All @@ -195,6 +258,25 @@ def rpm_common(config, name)
)
end

def rpm_docker(config)
config.vm.provision 'install Docker using yum', type: 'shell', inline: <<-SHELL
# Install prerequisites
yum install -y yum-utils device-mapper-persistent-data lvm2
# Add repository
yum-config-manager -y --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# Install Docker
yum install -y docker-ce docker-ce-cli containerd.io
# Start Docker
systemctl enable --now docker
# Add vagrant to the Docker group, so that it can run commands
usermod -aG docker vagrant
SHELL
end

def dnf_common(config, name)
# Autodetect doesn't work....
if Vagrant.has_plugin?('vagrant-cachier')
Expand All @@ -211,6 +293,25 @@ def dnf_common(config, name)
)
end

def dnf_docker(config)
config.vm.provision 'install Docker using dnf', type: 'shell', inline: <<-SHELL
# Install prerequisites
dnf -y install dnf-plugins-core
# Add repository
dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
# Install Docker
dnf install -y docker-ce docker-ce-cli containerd.io
# Start Docker
systemctl enable --now docker
# Add vagrant to the Docker group, so that it can run commands
usermod -aG docker vagrant
SHELL
end

def suse_common(config, name, extra: '')
linux_common(
config,
Expand Down Expand Up @@ -268,7 +369,7 @@ def linux_common(config,

# This prevents leftovers from previous tests using the
# same VM from messing up the current test
config.vm.provision 'clean es installs in tmp', run: 'always', type: 'shell', inline: <<-SHELL
config.vm.provision 'clean es installs in tmp', type: 'shell', inline: <<-SHELL
rm -rf /tmp/elasticsearch*
SHELL

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,10 +319,14 @@ private List<ElasticsearchDistribution> configureDistributions(Project project,
List<ElasticsearchDistribution> currentDistros = new ArrayList<>();
List<ElasticsearchDistribution> upgradeDistros = new ArrayList<>();

for (Type type : Arrays.asList(Type.DEB, Type.RPM)) {
for (Type type : Arrays.asList(Type.DEB, Type.RPM, Type.DOCKER)) {
for (Flavor flavor : Flavor.values()) {
for (boolean bundledJdk : Arrays.asList(true, false)) {
addDistro(distributions, type, null, flavor, bundledJdk, VersionProperties.getElasticsearch(), currentDistros);
// We should never add a Docker distro with bundledJdk == false
boolean skip = type == Type.DOCKER && bundledJdk == false;
if (skip == false) {
addDistro(distributions, type, null, flavor, bundledJdk, VersionProperties.getElasticsearch(), currentDistros);
}
}
}
// upgrade version is always bundled jdk
Expand Down Expand Up @@ -386,6 +390,11 @@ private static String distroId(Type type, Platform platform, Flavor flavor, bool
}

private static String destructiveDistroTestTaskName(ElasticsearchDistribution distro) {
return "destructiveDistroTest." + distroId(distro.getType(), distro.getPlatform(), distro.getFlavor(), distro.getBundledJdk());
Type type = distro.getType();
return "destructiveDistroTest." + distroId(
type,
distro.getPlatform(),
distro.getFlavor(),
distro.getBundledJdk());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ void setupDistributions(Project project) {
// for the distribution as a file, just depend on the artifact directly
dependencies.add(distribution.configuration.getName(), dependencyNotation(project, distribution));

// no extraction allowed for rpm or deb
if (distribution.getType() != Type.RPM && distribution.getType() != Type.DEB) {
// no extraction allowed for rpm, deb or docker
if (distribution.getType().shouldExtract()) {
// for the distribution extracted, add a root level task that does the extraction, and depend on that
// extracted configuration as an artifact consisting of the extracted distribution directory
dependencies.add(distribution.getExtracted().configuration.getName(),
Expand Down Expand Up @@ -221,7 +221,6 @@ private Object dependencyNotation(Project project, ElasticsearchDistribution dis
}

private static Dependency projectDependency(Project project, String projectPath, String projectConfig) {

if (project.findProject(projectPath) == null) {
throw new GradleException("no project [" + projectPath + "], project names: " + project.getRootProject().getAllprojects());
}
Expand All @@ -233,11 +232,20 @@ private static Dependency projectDependency(Project project, String projectPath,

private static String distributionProjectPath(ElasticsearchDistribution distribution) {
String projectPath = ":distribution";
if (distribution.getType() == Type.INTEG_TEST_ZIP) {
projectPath += ":archives:integ-test-zip";
} else {
projectPath += distribution.getType() == Type.ARCHIVE ? ":archives:" : ":packages:";
projectPath += distributionProjectName(distribution);
switch (distribution.getType()) {
case INTEG_TEST_ZIP:
projectPath += ":archives:integ-test-zip";
break;

case DOCKER:
projectPath += ":docker:";
projectPath += distributionProjectName(distribution);
break;

default:
projectPath += distribution.getType() == Type.ARCHIVE ? ":archives:" : ":packages:";
projectPath += distributionProjectName(distribution);
break;
}
return projectPath;
}
Expand All @@ -250,9 +258,12 @@ private static String distributionProjectName(ElasticsearchDistribution distribu
if (distribution.getBundledJdk() == false) {
projectName += "no-jdk-";
}

if (distribution.getType() == Type.ARCHIVE) {
Platform platform = distribution.getPlatform();
projectName += platform.toString() + (platform == Platform.WINDOWS ? "-zip" : "-tar");
} else if (distribution.getType() == Type.DOCKER) {
projectName += "docker-export";
} else {
projectName += distribution.getType();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,25 @@ public enum Type {
INTEG_TEST_ZIP,
ARCHIVE,
RPM,
DEB;
DEB,
DOCKER;

@Override
public String toString() {
return super.toString().toLowerCase(Locale.ROOT);
}

public boolean shouldExtract() {
switch (this) {
case DEB:
case DOCKER:
case RPM:
return false;

default:
return true;
}
}
}

public enum Flavor {
Expand Down Expand Up @@ -171,11 +184,16 @@ public String toString() {
}

public Extracted getExtracted() {
if (getType() == Type.RPM || getType() == Type.DEB) {
throw new UnsupportedOperationException("distribution type [" + getType() + "] for " +
"elasticsearch distribution [" + name + "] cannot be extracted");
switch (getType()) {
case DEB:
case DOCKER:
case RPM:
throw new UnsupportedOperationException("distribution type [" + getType() + "] for " +
"elasticsearch distribution [" + name + "] cannot be extracted");

default:
return extracted;
}
return extracted;
}

@Override
Expand Down Expand Up @@ -217,7 +235,7 @@ void finalizeValues() {
if (platform.isPresent() == false) {
platform.set(CURRENT_PLATFORM);
}
} else { // rpm or deb
} else { // rpm, deb or docker
if (platform.isPresent()) {
throw new IllegalArgumentException("platform not allowed for elasticsearch distribution ["
+ name + "] of type [" + getType() + "]");
Expand Down
34 changes: 34 additions & 0 deletions distribution/docker/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,37 @@ assemble.dependsOn "buildDockerImage"
if (tasks.findByName("composePull")) {
tasks.composePull.enabled = false
}

/*
* The export subprojects write out the generated Docker images to disk, so
* that they can be easily reloaded, for example into a VM.
*/
subprojects { Project subProject ->
if (subProject.name.contains('docker-export')) {
apply plugin: 'distribution'

final boolean oss = subProject.name.startsWith('oss')

def exportTaskName = taskName("export", oss, "DockerImage")
def buildTaskName = taskName("build", oss, "DockerImage")
def tarFile = "${parent.projectDir}/build/elasticsearch${oss ? '-oss' : ''}_test.${VersionProperties.elasticsearch}.docker.tar"

final Task exportDockerImageTask = task(exportTaskName, type: LoggedExec) {
executable 'docker'
args "save",
"-o",
tarFile,
"elasticsearch${oss ? '-oss' : ''}:test"
}

exportDockerImageTask.dependsOn(parent.tasks.getByName(buildTaskName))

artifacts.add('default', file(tarFile)) {
type 'tar'
name "elasticsearch${oss ? '-oss' : ''}"
builtBy exportTaskName
}

assemble.dependsOn exportTaskName
}
}
2 changes: 2 additions & 0 deletions distribution/docker/docker-export/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// This file is intentionally blank. All configuration of the
// export is done in the parent project.
2 changes: 2 additions & 0 deletions distribution/docker/oss-docker-export/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// This file is intentionally blank. All configuration of the
// export is done in the parent project.
Loading

0 comments on commit da59dfe

Please sign in to comment.