Migrate some of the Docker tests from old repository ()

Backport of . Reimplement a number of the tests from
elastic/elasticsearch-docker.

There is also one Docker image fix here, which is that two of the provided
config files had different file permissions to the rest. I've fixed this
with another RUN chmod while building the image, and adjusted the
corresponding packaging test.
This commit is contained in:
Rory Hunter 2019-12-04 08:57:58 +00:00 committed by GitHub
parent 408f25e016
commit 1bc3e69fa3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 343 additions and 100 deletions
distribution/docker/src/docker
qa/os
build.gradle
src/test/java/org/elasticsearch/packaging

@ -33,6 +33,7 @@ RUN grep ES_DISTRIBUTION_TYPE=tar /usr/share/elasticsearch/bin/elasticsearch-env
RUN mkdir -p config data logs
RUN chmod 0775 config data logs
COPY config/elasticsearch.yml config/log4j2.properties config/
RUN chmod 0660 config/elasticsearch.yml config/log4j2.properties
################################################################################
# Build stage 1 (the actual elasticsearch image):

@ -85,9 +85,8 @@ declare -a es_opts
while IFS='=' read -r envvar_key envvar_value
do
# Elasticsearch settings need to have at least two dot separated lowercase
# words, e.g. `cluster.name`, except for `processors` which we handle
# specially
if [[ "$envvar_key" =~ ^[a-z0-9_]+\.[a-z0-9_]+ || "$envvar_key" == "processors" ]]; then
# words, e.g. `cluster.name`
if [[ "$envvar_key" =~ ^[a-z0-9_]+\.[a-z0-9_]+ ]]; then
if [[ ! -z $envvar_value ]]; then
es_opt="-E${envvar_key}=${envvar_value}"
es_opts+=("${es_opt}")

@ -36,6 +36,10 @@ dependencies {
compile "commons-logging:commons-logging:${versions.commonslogging}"
compile project(':libs:elasticsearch-core')
testCompile "com.fasterxml.jackson.core:jackson-annotations:${versions.jackson}"
testCompile "com.fasterxml.jackson.core:jackson-core:${versions.jackson}"
testCompile "com.fasterxml.jackson.core:jackson-databind:${versions.jackson}"
}
forbiddenApisTest {

@ -19,10 +19,12 @@
package org.elasticsearch.packaging.test;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.http.client.fluent.Request;
import org.elasticsearch.packaging.util.Distribution;
import org.elasticsearch.packaging.util.Docker.DockerShell;
import org.elasticsearch.packaging.util.Installation;
import org.elasticsearch.packaging.util.Platforms;
import org.elasticsearch.packaging.util.ServerUtils;
import org.elasticsearch.packaging.util.Shell.Result;
import org.junit.After;
@ -34,8 +36,13 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static java.nio.file.attribute.PosixFilePermissions.fromString;
import static java.util.Collections.singletonMap;
@ -43,6 +50,9 @@ import static org.elasticsearch.packaging.util.Docker.assertPermissionsAndOwners
import static org.elasticsearch.packaging.util.Docker.copyFromContainer;
import static org.elasticsearch.packaging.util.Docker.ensureImageIsLoaded;
import static org.elasticsearch.packaging.util.Docker.existsInContainer;
import static org.elasticsearch.packaging.util.Docker.getContainerLogs;
import static org.elasticsearch.packaging.util.Docker.getImageLabels;
import static org.elasticsearch.packaging.util.Docker.getJson;
import static org.elasticsearch.packaging.util.Docker.mkDirWithPrivilegeEscalation;
import static org.elasticsearch.packaging.util.Docker.removeContainer;
import static org.elasticsearch.packaging.util.Docker.rmDirWithPrivilegeEscalation;
@ -57,10 +67,16 @@ import static org.elasticsearch.packaging.util.FileUtils.append;
import static org.elasticsearch.packaging.util.FileUtils.getTempDir;
import static org.elasticsearch.packaging.util.FileUtils.rm;
import static org.elasticsearch.packaging.util.ServerUtils.makeRequest;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.arrayWithSize;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.emptyString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assume.assumeTrue;
public class DockerTests extends PackagingTestCase {
@ -95,14 +111,28 @@ public class DockerTests extends PackagingTestCase {
/**
* Checks that the Docker image can be run, and that it passes various checks.
*/
public void test10Install() {
public void test010Install() {
verifyContainerInstallation(installation, distribution());
}
/**
* Check that the /_xpack API endpoint's presence is correct for the type of distribution being tested.
*/
public void test011PresenceOfXpack() throws Exception {
waitForElasticsearch(installation);
final int statusCode = Request.Get("http://localhost:9200/_xpack").execute().returnResponse().getStatusLine().getStatusCode();
if (distribution.isOSS()) {
assertThat(statusCode, greaterThanOrEqualTo(400));
} else {
assertThat(statusCode, equalTo(200));
}
}
/**
* Checks that no plugins are initially active.
*/
public void test20PluginsListWithNoPlugins() {
public void test020PluginsListWithNoPlugins() {
final Installation.Executables bin = installation.executables();
final Result r = sh.run(bin.elasticsearchPlugin + " list");
@ -112,7 +142,7 @@ public class DockerTests extends PackagingTestCase {
/**
* Check that a keystore can be manually created using the provided CLI tool.
*/
public void test40CreateKeystoreManually() throws InterruptedException {
public void test040CreateKeystoreManually() throws InterruptedException {
final Installation.Executables bin = installation.executables();
final Path keystorePath = installation.config("elasticsearch.keystore");
@ -128,22 +158,10 @@ public class DockerTests extends PackagingTestCase {
assertThat(r.stdout, containsString("keystore.seed"));
}
/**
* Send some basic index, count and delete requests, in order to check that the installation
* is minimally functional.
*/
public void test50BasicApiTests() throws Exception {
waitForElasticsearch(installation);
assertTrue(existsInContainer(installation.logs.resolve("gc.log")));
ServerUtils.runElasticsearchTests();
}
/**
* Check that the default keystore is automatically created
*/
public void test60AutoCreateKeystore() throws Exception {
public void test041AutoCreateKeystore() throws Exception {
final Path keystorePath = installation.config("elasticsearch.keystore");
waitForPathToExist(keystorePath);
@ -155,10 +173,42 @@ public class DockerTests extends PackagingTestCase {
assertThat(result.stdout, containsString("keystore.seed"));
}
/**
* Check that the JDK's cacerts file is a symlink to the copy provided by the operating system.
*/
public void test042JavaUsesTheOsProvidedKeystore() {
final String path = sh.run("realpath jdk/lib/security/cacerts").stdout;
assertThat(path, equalTo("/etc/pki/ca-trust/extracted/java/cacerts"));
}
/**
* Checks that there are Amazon trusted certificates in the cacaerts keystore.
*/
public void test043AmazonCaCertsAreInTheKeystore() {
final boolean matches = Arrays.stream(
sh.run("jdk/bin/keytool -cacerts -storepass changeit -list | grep trustedCertEntry").stdout.split("\n")
).anyMatch(line -> line.contains("amazonrootca"));
assertTrue("Expected Amazon trusted cert in cacerts", matches);
}
/**
* Send some basic index, count and delete requests, in order to check that the installation
* is minimally functional.
*/
public void test050BasicApiTests() throws Exception {
waitForElasticsearch(installation);
assertTrue(existsInContainer(installation.logs.resolve("gc.log")));
ServerUtils.runElasticsearchTests();
}
/**
* Check that the default config can be overridden using a bind mount, and that env vars are respected
*/
public void test70BindMountCustomPathConfAndJvmOptions() throws Exception {
public void test070BindMountCustomPathConfAndJvmOptions() throws Exception {
copyFromContainer(installation.config("elasticsearch.yml"), tempDir.resolve("elasticsearch.yml"));
copyFromContainer(installation.config("log4j2.properties"), tempDir.resolve("log4j2.properties"));
@ -178,37 +228,49 @@ public class DockerTests extends PackagingTestCase {
waitForElasticsearch(installation);
final String nodesResponse = makeRequest(Request.Get("http://localhost:9200/_nodes"));
assertThat(nodesResponse, containsString("\"heap_init_in_bytes\":536870912"));
assertThat(nodesResponse, containsString("\"using_compressed_ordinary_object_pointers\":\"false\""));
final JsonNode nodes = getJson("_nodes").get("nodes");
final String nodeId = nodes.fieldNames().next();
final int heapSize = nodes.at("/" + nodeId + "/jvm/mem/heap_init_in_bytes").intValue();
final boolean usingCompressedPointers = nodes.at("/" + nodeId + "/jvm/using_compressed_ordinary_object_pointers").asBoolean();
logger.warn(nodes.at("/" + nodeId + "/jvm/mem/heap_init_in_bytes"));
assertThat("heap_init_in_bytes", heapSize, equalTo(536870912));
assertThat("using_compressed_ordinary_object_pointers", usingCompressedPointers, equalTo(false));
}
/**
* Check that the default config can be overridden using a bind mount, and that env vars are respected
* Check that the default config can be overridden using a bind mount, and that env vars are respected.
*/
public void test71BindMountCustomPathWithDifferentUID() throws Exception {
final Path tempEsDataDir = tempDir.resolve("esDataDir");
// Make the local directory and contents accessible when bind-mounted
mkDirWithPrivilegeEscalation(tempEsDataDir, 1500, 0);
public void test071BindMountCustomPathWithDifferentUID() throws Exception {
Platforms.onLinux(() -> {
final Path tempEsDataDir = tempDir.resolve("esDataDir");
// Make the local directory and contents accessible when bind-mounted
mkDirWithPrivilegeEscalation(tempEsDataDir, 1500, 0);
// Restart the container
final Map<Path, Path> volumes = singletonMap(tempEsDataDir.toAbsolutePath(), Paths.get("/usr/share/elasticsearch/data"));
// Restart the container
final Map<Path, Path> volumes = singletonMap(tempEsDataDir.toAbsolutePath(), installation.data);
runContainer(distribution(), volumes, null);
runContainer(distribution(), volumes, null);
waitForElasticsearch(installation);
waitForElasticsearch(installation);
final String nodesResponse = makeRequest(Request.Get("http://localhost:9200/_nodes"));
final JsonNode nodes = getJson("_nodes");
assertThat(nodesResponse, containsString("\"_nodes\":{\"total\":1,\"successful\":1,\"failed\":0}"));
rmDirWithPrivilegeEscalation(tempEsDataDir);
assertThat(nodes.at("/_nodes/total").intValue(), equalTo(1));
assertThat(nodes.at("/_nodes/successful").intValue(), equalTo(1));
assertThat(nodes.at("/_nodes/failed").intValue(), equalTo(0));
rmDirWithPrivilegeEscalation(tempEsDataDir);
});
}
/**
* Check that environment variables can be populated by setting variables with the suffix "_FILE",
* which point to files that hold the required values.
*/
public void test80SetEnvironmentVariablesUsingFiles() throws Exception {
public void test080SetEnvironmentVariablesUsingFiles() throws Exception {
final String optionsFilename = "esJavaOpts.txt";
// ES_JAVA_OPTS_FILE
@ -235,19 +297,18 @@ public class DockerTests extends PackagingTestCase {
/**
* Check that the elastic user's password can be configured via a file and the ELASTIC_PASSWORD_FILE environment variable.
*/
public void test81ConfigurePasswordThroughEnvironmentVariableFile() throws Exception {
public void test081ConfigurePasswordThroughEnvironmentVariableFile() throws Exception {
// Test relies on configuring security
assumeTrue(distribution.isDefault());
final String xpackPassword = "hunter2";
final String passwordFilename = "password.txt";
// ELASTIC_PASSWORD_FILE
append(tempDir.resolve(passwordFilename), xpackPassword + "\n");
// Enable security so that we can test that the password has been used
Map<String, String> envVars = new HashMap<>();
envVars.put("ELASTIC_PASSWORD_FILE", "/run/secrets/" + passwordFilename);
// Enable security so that we can test that the password has been used
envVars.put("xpack.security.enabled", "true");
// File permissions need to be secured in order for the ES wrapper to accept
@ -264,8 +325,8 @@ public class DockerTests extends PackagingTestCase {
waitForElasticsearch("green", null, installation, "elastic", "hunter2");
} catch (Exception e) {
throw new AssertionError(
"Failed to check whether Elasticsearch had started. This could be because "
+ "authentication isn't working properly. Check the container logs",
"Failed to check whether Elasticsearch had started. This could be because authentication isn't working properly. "
+ "Check the container logs",
e
);
}
@ -278,7 +339,7 @@ public class DockerTests extends PackagingTestCase {
/**
* Check that environment variables cannot be used with _FILE environment variables.
*/
public void test81CannotUseEnvVarsAndFiles() throws Exception {
public void test081CannotUseEnvVarsAndFiles() throws Exception {
final String optionsFilename = "esJavaOpts.txt";
// ES_JAVA_OPTS_FILE
@ -298,7 +359,7 @@ public class DockerTests extends PackagingTestCase {
assertThat(
dockerLogs.stderr,
containsString("ERROR: Both ES_JAVA_OPTS_FILE and ES_JAVA_OPTS are set. These are mutually exclusive.")
containsString("ERROR: Both ES_JAVA_OPTS_FILE and ES_JAVA_OPTS are set. These are mutually " + "exclusive.")
);
}
@ -306,7 +367,7 @@ public class DockerTests extends PackagingTestCase {
* Check that when populating environment variables by setting variables with the suffix "_FILE",
* the files' permissions are checked.
*/
public void test82EnvironmentVariablesUsingFilesHaveCorrectPermissions() throws Exception {
public void test082EnvironmentVariablesUsingFilesHaveCorrectPermissions() throws Exception {
final String optionsFilename = "esJavaOpts.txt";
// ES_JAVA_OPTS_FILE
@ -324,7 +385,9 @@ public class DockerTests extends PackagingTestCase {
assertThat(
dockerLogs.stderr,
containsString("ERROR: File /run/secrets/" + optionsFilename + " from ES_JAVA_OPTS_FILE must have file permissions 400 or 600")
containsString(
"ERROR: File /run/secrets/" + optionsFilename + " from ES_JAVA_OPTS_FILE must have " + "file permissions 400 or 600"
)
);
}
@ -332,7 +395,7 @@ public class DockerTests extends PackagingTestCase {
* Check whether the elasticsearch-certutil tool has been shipped correctly,
* and if present then it can execute.
*/
public void test90SecurityCliPackaging() {
public void test090SecurityCliPackaging() {
final Installation.Executables bin = installation.executables();
final Path securityCli = installation.lib.resolve("tools").resolve("security-cli");
@ -355,7 +418,7 @@ public class DockerTests extends PackagingTestCase {
/**
* Check that the elasticsearch-shard tool is shipped in the Docker image and is executable.
*/
public void test91ElasticsearchShardCliPackaging() {
public void test091ElasticsearchShardCliPackaging() {
final Installation.Executables bin = installation.executables();
final Result result = sh.run(bin.elasticsearchShard + " -h");
@ -365,10 +428,156 @@ public class DockerTests extends PackagingTestCase {
/**
* Check that the elasticsearch-node tool is shipped in the Docker image and is executable.
*/
public void test92ElasticsearchNodeCliPackaging() {
public void test092ElasticsearchNodeCliPackaging() {
final Installation.Executables bin = installation.executables();
final Result result = sh.run(bin.elasticsearchNode + " -h");
assertThat(result.stdout, containsString("A CLI tool to do unsafe cluster and index manipulations on current node"));
assertThat(
"Failed to find expected message about the elasticsearch-node CLI tool",
result.stdout,
containsString("A CLI tool to " + "do unsafe cluster and index manipulations on current node")
);
}
/**
* Check that no core dumps have been accidentally included in the Docker image.
*/
public void test100NoCoreFilesInImage() {
assertFalse("Unexpected core dump found in Docker image", existsInContainer("/core*"));
}
/**
* Check that there are no files with a GID other than 0.
*/
public void test101AllFilesAreGroupZero() {
final String findResults = sh.run("find . -not -gid 0").stdout;
assertThat("Found some files whose GID != 0", findResults, is(emptyString()));
}
/**
* Check that the Docker image has the expected "Label Schema" labels.
*
* @see <a href="http://label-schema.org/">Label Schema website</a>
*/
public void test110OrgLabelSchemaLabels() throws Exception {
final Map<String, String> labels = getImageLabels(distribution);
final Map<String, String> staticLabels = new HashMap<>();
staticLabels.put("name", "Elasticsearch");
staticLabels.put("schema-version", "1.0");
staticLabels.put("url", "https://www.elastic.co/products/elasticsearch");
staticLabels.put("usage", "https://www.elastic.co/guide/en/elasticsearch/reference/index.html");
staticLabels.put("vcs-url", "https://github.com/elastic/elasticsearch");
staticLabels.put("vendor", "Elastic");
if (distribution.isOSS()) {
staticLabels.put("license", "Apache-2.0");
} else {
staticLabels.put("license", "Elastic-License");
}
// TODO: we should check the actual version value
final Set<String> dynamicLabels = new HashSet<>();
dynamicLabels.add("build-date");
dynamicLabels.add("vcs-ref");
dynamicLabels.add("version");
final String prefix = "org.label-schema";
staticLabels.forEach((suffix, value) -> {
String key = prefix + "." + suffix;
assertThat(labels, hasKey(key));
assertThat(labels.get(key), equalTo(value));
});
dynamicLabels.forEach(label -> {
String key = prefix + "." + label;
assertThat(labels, hasKey(key));
});
}
/**
* Check that the Docker image has the expected "Open Containers Annotations" labels.
*
* @see <a href="https://github.com/opencontainers/image-spec/blob/master/annotations.md">Open Containers Annotations</a>
*/
public void test110OrgOpencontainersLabels() throws Exception {
final Map<String, String> labels = getImageLabels(distribution);
final Map<String, String> staticLabels = new HashMap<>();
staticLabels.put("title", "Elasticsearch");
staticLabels.put("url", "https://www.elastic.co/products/elasticsearch");
staticLabels.put("documentation", "https://www.elastic.co/guide/en/elasticsearch/reference/index.html");
staticLabels.put("source", "https://github.com/elastic/elasticsearch");
staticLabels.put("vendor", "Elastic");
if (distribution.isOSS()) {
staticLabels.put("licenses", "Apache-2.0");
} else {
staticLabels.put("licenses", "Elastic-License");
}
// TODO: we should check the actual version value
final Set<String> dynamicLabels = new HashSet<>();
dynamicLabels.add("created");
dynamicLabels.add("revision");
dynamicLabels.add("version");
final String prefix = "org.opencontainers.image";
staticLabels.forEach((suffix, value) -> {
String key = prefix + "." + suffix;
assertThat(labels, hasKey(key));
assertThat(labels.get(key), equalTo(value));
});
dynamicLabels.forEach(label -> {
String key = prefix + "." + label;
assertThat(labels, hasKey(key));
});
}
/**
* Check that the container logs contain the expected content for Elasticsearch itself.
*/
public void test120DockerLogsIncludeElasticsearchLogs() throws Exception {
waitForElasticsearch(installation);
final Result containerLogs = getContainerLogs();
assertThat("Container logs don't contain abbreviated class names", containerLogs.stdout, containsString("o.e.n.Node"));
assertThat("Container logs don't contain INFO level messages", containerLogs.stdout, containsString("INFO"));
}
/**
* Check that the Java process running inside the container has the expect PID, UID and username.
*/
public void test130JavaHasCorrectPidAndOwnership() {
final List<String> processes = Arrays.stream(sh.run("ps -o pid,uid,user -C java").stdout.split("\n"))
.skip(1)
.collect(Collectors.toList());
assertThat("Expected a single java process", processes, hasSize(1));
final String[] fields = processes.get(0).trim().split("\\s+");
assertThat(fields, arrayWithSize(3));
assertThat("Incorrect PID", fields[0], equalTo("1"));
assertThat("Incorrect UID", fields[1], equalTo("1000"));
assertThat("Incorrect username", fields[2], equalTo("elasticsearch"));
}
public void test140CgroupOsStatsAreAvailable() throws Exception {
waitForElasticsearch(installation);
final JsonNode nodes = getJson("_nodes/stats/os").get("nodes");
final String nodeId = nodes.fieldNames().next();
final JsonNode cgroupStats = nodes.at("/" + nodeId + "/os/cgroup");
assertFalse("Couldn't find /nodes/{nodeId}/os/cgroup in API response", cgroupStats.isMissingNode());
assertThat("Failed to find [cpu] in node OS cgroup stats", cgroupStats.get("cpu"), not(nullValue()));
assertThat("Failed to find [cpuacct] in node OS cgroup stats", cgroupStats.get("cpuacct"), not(nullValue()));
}
}

@ -19,15 +19,20 @@
package org.elasticsearch.packaging.util;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.fluent.Request;
import org.elasticsearch.common.CheckedRunnable;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -40,6 +45,7 @@ import static org.elasticsearch.packaging.util.FileMatcher.p755;
import static org.elasticsearch.packaging.util.FileMatcher.p770;
import static org.elasticsearch.packaging.util.FileMatcher.p775;
import static org.elasticsearch.packaging.util.FileUtils.getCurrentVersion;
import static org.elasticsearch.packaging.util.ServerUtils.makeRequest;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
@ -120,7 +126,7 @@ public class Docker {
waitForElasticsearchToExit();
return sh.run("docker logs " + containerId);
return getContainerLogs();
}
private static void executeDockerRun(Distribution distribution, Map<Path, Path> volumes, Map<String, String> envVars) {
@ -171,7 +177,7 @@ public class Docker {
// Give the container a chance to crash out
Thread.sleep(1000);
psOutput = dockerShell.run("ps ax").stdout;
psOutput = dockerShell.run("ps -w ax").stdout;
if (psOutput.contains("/usr/share/elasticsearch/jdk/bin/java")) {
isElasticsearchRunning = true;
@ -183,7 +189,7 @@ public class Docker {
} while (attempt++ < 5);
if (isElasticsearchRunning == false) {
final Shell.Result dockerLogs = sh.run("docker logs " + containerId);
final Shell.Result dockerLogs = getContainerLogs();
fail(
"Elasticsearch container did not start successfully.\n\nps output:\n"
+ psOutput
@ -217,7 +223,7 @@ public class Docker {
} while (attempt++ < 5);
if (isElasticsearchRunning) {
final Shell.Result dockerLogs = sh.run("docker logs " + containerId);
final Shell.Result dockerLogs = getContainerLogs();
fail("Elasticsearch container did exit.\n\nStdout:\n" + dockerLogs.stdout + "\n\nStderr:\n" + dockerLogs.stderr);
}
}
@ -278,6 +284,13 @@ public class Docker {
* Checks whether a path exists in the Docker container.
*/
public static boolean existsInContainer(Path path) {
return existsInContainer(path.toString());
}
/**
* Checks whether a path exists in the Docker container.
*/
public static boolean existsInContainer(String path) {
logger.debug("Checking whether file " + path + " exists in container");
final Shell.Result result = dockerShell.runIgnoreExitCode("test -e " + path);
@ -333,9 +346,9 @@ public class Docker {
final PosixFileAttributes dirAttributes = FileUtils.getPosixFileAttributes(localPath);
final Map<String, Integer> numericPathOwnership = FileUtils.getNumericUnixPathOwnership(localPath);
assertEquals(localPath + " has wrong uid", numericPathOwnership.get("uid").intValue(), uid);
assertEquals(localPath + " has wrong gid", numericPathOwnership.get("gid").intValue(), gid);
assertEquals(localPath + " has wrong permissions", dirAttributes.permissions(), p770);
assertThat(localPath + " has wrong uid", numericPathOwnership.get("uid"), equalTo(uid));
assertThat(localPath + " has wrong gid", numericPathOwnership.get("gid"), equalTo(gid));
assertThat(localPath + " has wrong permissions", dirAttributes.permissions(), equalTo(p770));
}
/**
@ -414,63 +427,47 @@ public class Docker {
Stream.of(es.plugins, es.modules).forEach(dir -> assertPermissionsAndOwnership(dir, p755));
// FIXME these files should all have the same permissions
Stream
.of(
"elasticsearch.keystore",
// "elasticsearch.yml",
"jvm.options"
// "log4j2.properties"
)
Stream.of("elasticsearch.keystore", "elasticsearch.yml", "jvm.options", "log4j2.properties")
.forEach(configFile -> assertPermissionsAndOwnership(es.config(configFile), p660));
Stream
.of("elasticsearch.yml", "log4j2.properties")
.forEach(configFile -> assertPermissionsAndOwnership(es.config(configFile), p644));
assertThat(dockerShell.run(es.bin("elasticsearch-keystore") + " list").stdout, containsString("keystore.seed"));
Stream.of(es.bin, es.lib).forEach(dir -> assertPermissionsAndOwnership(dir, p755));
Stream
.of(
"elasticsearch",
"elasticsearch-cli",
"elasticsearch-env",
"elasticsearch-enve",
"elasticsearch-keystore",
"elasticsearch-node",
"elasticsearch-plugin",
"elasticsearch-shard"
)
.forEach(executable -> assertPermissionsAndOwnership(es.bin(executable), p755));
Stream.of(
"elasticsearch",
"elasticsearch-cli",
"elasticsearch-env",
"elasticsearch-enve",
"elasticsearch-keystore",
"elasticsearch-node",
"elasticsearch-plugin",
"elasticsearch-shard"
).forEach(executable -> assertPermissionsAndOwnership(es.bin(executable), p755));
Stream.of("LICENSE.txt", "NOTICE.txt", "README.textile").forEach(doc -> assertPermissionsAndOwnership(es.home.resolve(doc), p644));
}
private static void verifyDefaultInstallation(Installation es) {
Stream
.of(
"elasticsearch-certgen",
"elasticsearch-certutil",
"elasticsearch-croneval",
"elasticsearch-saml-metadata",
"elasticsearch-setup-passwords",
"elasticsearch-sql-cli",
"elasticsearch-syskeygen",
"elasticsearch-users",
"x-pack-env",
"x-pack-security-env",
"x-pack-watcher-env"
)
.forEach(executable -> assertPermissionsAndOwnership(es.bin(executable), p755));
Stream.of(
"elasticsearch-certgen",
"elasticsearch-certutil",
"elasticsearch-croneval",
"elasticsearch-saml-metadata",
"elasticsearch-setup-passwords",
"elasticsearch-sql-cli",
"elasticsearch-syskeygen",
"elasticsearch-users",
"x-pack-env",
"x-pack-security-env",
"x-pack-watcher-env"
).forEach(executable -> assertPermissionsAndOwnership(es.bin(executable), p755));
// at this time we only install the current version of archive distributions, but if that changes we'll need to pass
// the version through here
assertPermissionsAndOwnership(es.bin("elasticsearch-sql-cli-" + getCurrentVersion() + ".jar"), p755);
Stream
.of("role_mapping.yml", "roles.yml", "users", "users_roles")
Stream.of("role_mapping.yml", "roles.yml", "users", "users_roles")
.forEach(configFile -> assertPermissionsAndOwnership(es.config(configFile), p660));
}
@ -483,13 +480,46 @@ public class Docker {
withLogging(() -> ServerUtils.waitForElasticsearch(status, index, installation, username, password));
}
/**
* Runs the provided closure, and captures logging information if an exception is thrown.
* @param r the closure to run
* @throws Exception any exception encountered while running the closure are propagated.
*/
private static <E extends Exception> void withLogging(CheckedRunnable<E> r) throws Exception {
try {
r.run();
} catch (Exception e) {
final Shell.Result logs = sh.run("docker logs " + containerId);
final Shell.Result logs = getContainerLogs();
logger.warn("Elasticsearch container failed to start.\n\nStdout:\n" + logs.stdout + "\n\nStderr:\n" + logs.stderr);
throw e;
}
}
public static JsonNode getJson(String path) throws IOException {
final String pluginsResponse = makeRequest(Request.Get("http://localhost:9200/" + path));
ObjectMapper mapper = new ObjectMapper();
return mapper.readTree(pluginsResponse);
}
public static Map<String, String> getImageLabels(Distribution distribution) throws Exception {
// The format below extracts the .Config.Labels value, and prints it as json. Without the json
// modifier, a stringified Go map is printed instead, which isn't helpful.
String labelsJson = sh.run("docker inspect -f '{{json .Config.Labels}}' " + distribution.flavor.name + ":test").stdout;
ObjectMapper mapper = new ObjectMapper();
final JsonNode jsonNode = mapper.readTree(labelsJson);
Map<String, String> labels = new HashMap<>();
jsonNode.fieldNames().forEachRemaining(field -> labels.put(field, jsonNode.get(field).asText()));
return labels;
}
public static Shell.Result getContainerLogs() {
return sh.run("docker logs " + containerId);
}
}