Skip to content

Commit e05137a

Browse files
Run keystore management tests on docker distros (elastic#50610)
* Add Docker handling to PackagingTestCase Keystore tests need to be able to run in the Docker case. We can do this by using a DockerShell instead of a plain Shell when Docker is running. * Improve ES startup check for docker Previously we were checking truncated output for the packaged JDK as an indication that Elasticsearch had started. With new preliminary password checks, we might get a false positive from ES keystore commands, so we have to check specifically that the Elasticsearch class from the Bootstrap package is what's running.
1 parent 3e06d4a commit e05137a

File tree

6 files changed

+88
-75
lines changed

6 files changed

+88
-75
lines changed

qa/os/src/test/java/org/elasticsearch/packaging/test/DockerTests.java

Lines changed: 5 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,13 @@
2121

2222
import com.fasterxml.jackson.databind.JsonNode;
2323
import org.apache.http.client.fluent.Request;
24-
import org.elasticsearch.packaging.util.Distribution;
25-
import org.elasticsearch.packaging.util.Docker.DockerShell;
2624
import org.elasticsearch.packaging.util.Installation;
2725
import org.elasticsearch.packaging.util.Platforms;
2826
import org.elasticsearch.packaging.util.ServerUtils;
2927
import org.elasticsearch.packaging.util.Shell.Result;
3028
import org.junit.After;
31-
import org.junit.AfterClass;
3229
import org.junit.Before;
3330
import org.junit.BeforeClass;
34-
import org.junit.Ignore;
3531

3632
import java.io.IOException;
3733
import java.nio.file.Files;
@@ -44,21 +40,17 @@
4440

4541
import static java.nio.file.attribute.PosixFilePermissions.fromString;
4642
import static java.util.Collections.singletonMap;
47-
import static org.elasticsearch.packaging.util.Docker.assertPermissionsAndOwnership;
4843
import static org.elasticsearch.packaging.util.Docker.copyFromContainer;
49-
import static org.elasticsearch.packaging.util.Docker.ensureImageIsLoaded;
5044
import static org.elasticsearch.packaging.util.Docker.existsInContainer;
5145
import static org.elasticsearch.packaging.util.Docker.getContainerLogs;
5246
import static org.elasticsearch.packaging.util.Docker.getImageLabels;
5347
import static org.elasticsearch.packaging.util.Docker.getJson;
5448
import static org.elasticsearch.packaging.util.Docker.mkDirWithPrivilegeEscalation;
55-
import static org.elasticsearch.packaging.util.Docker.removeContainer;
5649
import static org.elasticsearch.packaging.util.Docker.rmDirWithPrivilegeEscalation;
5750
import static org.elasticsearch.packaging.util.Docker.runContainer;
5851
import static org.elasticsearch.packaging.util.Docker.runContainerExpectingFailure;
5952
import static org.elasticsearch.packaging.util.Docker.verifyContainerInstallation;
6053
import static org.elasticsearch.packaging.util.Docker.waitForElasticsearch;
61-
import static org.elasticsearch.packaging.util.Docker.waitForPathToExist;
6254
import static org.elasticsearch.packaging.util.FileMatcher.p600;
6355
import static org.elasticsearch.packaging.util.FileMatcher.p660;
6456
import static org.elasticsearch.packaging.util.FileUtils.append;
@@ -105,25 +97,15 @@
10597
import com.fasterxml.jackson.databind.JsonNode;
10698

10799
public class DockerTests extends PackagingTestCase {
108-
protected DockerShell sh;
109100
private Path tempDir;
110101

111102
@BeforeClass
112103
public static void filterDistros() {
113-
assumeTrue("only Docker", distribution.packaging == Distribution.Packaging.DOCKER);
114-
115-
ensureImageIsLoaded(distribution);
116-
}
117-
118-
@AfterClass
119-
public static void cleanup() {
120-
// runContainer also calls this, so we don't need this method to be annotated as `@After`
121-
removeContainer();
104+
assumeTrue("only Docker", distribution().isDocker());
122105
}
123106

124107
@Before
125108
public void setupTest() throws IOException {
126-
sh = new DockerShell();
127109
installation = runContainer(distribution());
128110
tempDir = Files.createTempDirectory(getTempDir(), DockerTests.class.getSimpleName());
129111
}
@@ -164,44 +146,10 @@ public void test020PluginsListWithNoPlugins() {
164146
assertThat("Expected no plugins to be listed", r.stdout, emptyString());
165147
}
166148

167-
/**
168-
* Check that a keystore can be manually created using the provided CLI tool.
169-
*/
170-
public void test040CreateKeystoreManually() throws InterruptedException {
171-
final Installation.Executables bin = installation.executables();
172-
173-
final Path keystorePath = installation.config("elasticsearch.keystore");
174-
175-
waitForPathToExist(keystorePath);
176-
177-
// Move the auto-created one out of the way, or else the CLI prompts asks us to confirm
178-
sh.run("mv " + keystorePath + " " + keystorePath + ".bak");
179-
180-
sh.run(bin.keystoreTool + " create");
181-
182-
final Result r = sh.run(bin.keystoreTool + " list");
183-
assertThat(r.stdout, containsString("keystore.seed"));
184-
}
185-
186-
/**
187-
* Check that the default keystore is automatically created
188-
*/
189-
public void test041AutoCreateKeystore() throws Exception {
190-
final Path keystorePath = installation.config("elasticsearch.keystore");
191-
192-
waitForPathToExist(keystorePath);
193-
194-
assertPermissionsAndOwnership(keystorePath, p660);
195-
196-
final Installation.Executables bin = installation.executables();
197-
final Result result = sh.run(bin.keystoreTool + " list");
198-
assertThat(result.stdout, containsString("keystore.seed"));
199-
}
200-
201149
/**
202150
* Check that the JDK's cacerts file is a symlink to the copy provided by the operating system.
203151
*/
204-
public void test042JavaUsesTheOsProvidedKeystore() {
152+
public void test040JavaUsesTheOsProvidedKeystore() {
205153
final String path = sh.run("realpath jdk/lib/security/cacerts").stdout;
206154

207155
assertThat(path, equalTo("/etc/pki/ca-trust/extracted/java/cacerts"));
@@ -364,7 +312,7 @@ public void test081ConfigurePasswordThroughEnvironmentVariableFile() throws Exce
364312
/**
365313
* Check that environment variables cannot be used with _FILE environment variables.
366314
*/
367-
public void test081CannotUseEnvVarsAndFiles() throws Exception {
315+
public void test082CannotUseEnvVarsAndFiles() throws Exception {
368316
final String optionsFilename = "esJavaOpts.txt";
369317

370318
// ES_JAVA_OPTS_FILE
@@ -392,7 +340,7 @@ public void test081CannotUseEnvVarsAndFiles() throws Exception {
392340
* Check that when populating environment variables by setting variables with the suffix "_FILE",
393341
* the files' permissions are checked.
394342
*/
395-
public void test082EnvironmentVariablesUsingFilesHaveCorrectPermissions() throws Exception {
343+
public void test083EnvironmentVariablesUsingFilesHaveCorrectPermissions() throws Exception {
396344
final String optionsFilename = "esJavaOpts.txt";
397345

398346
// ES_JAVA_OPTS_FILE
@@ -420,7 +368,7 @@ public void test082EnvironmentVariablesUsingFilesHaveCorrectPermissions() throws
420368
* Check that environment variables are translated to -E options even for commands invoked under
421369
* `docker exec`, where the Docker image's entrypoint is not executed.
422370
*/
423-
public void test83EnvironmentVariablesAreRespectedUnderDockerExec() {
371+
public void test084EnvironmentVariablesAreRespectedUnderDockerExec() {
424372
// This test relies on a CLI tool attempting to connect to Elasticsearch, and the
425373
// tool in question is only in the default distribution.
426374
assumeTrue(distribution.isDefault());
@@ -598,7 +546,6 @@ public void test120DockerLogsIncludeElasticsearchLogs() throws Exception {
598546
/**
599547
* Check that the Java process running inside the container has the expect PID, UID and username.
600548
*/
601-
@Ignore /* Ignored for feature branch, awaits fix: https://github.com/elastic/elasticsearch/issues/49469 */
602549
public void test130JavaHasCorrectPidAndOwnership() {
603550
final List<String> processes = Arrays.stream(sh.run("ps -o pid,uid,user -C java").stdout.split("\n"))
604551
.skip(1)

qa/os/src/test/java/org/elasticsearch/packaging/test/KeystoreManagementTests.java

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.elasticsearch.packaging.test;
2121

2222
import org.elasticsearch.packaging.util.Distribution;
23+
import org.elasticsearch.packaging.util.Docker;
2324
import org.elasticsearch.packaging.util.FileUtils;
2425
import org.elasticsearch.packaging.util.Installation;
2526
import org.elasticsearch.packaging.util.Platforms;
@@ -35,6 +36,8 @@
3536
import static org.elasticsearch.packaging.util.Archives.ARCHIVE_OWNER;
3637
import static org.elasticsearch.packaging.util.Archives.installArchive;
3738
import static org.elasticsearch.packaging.util.Archives.verifyArchiveInstallation;
39+
import static org.elasticsearch.packaging.util.Docker.assertPermissionsAndOwnership;
40+
import static org.elasticsearch.packaging.util.Docker.waitForPathToExist;
3841
import static org.elasticsearch.packaging.util.FileMatcher.Fileness.File;
3942
import static org.elasticsearch.packaging.util.FileMatcher.file;
4043
import static org.elasticsearch.packaging.util.FileMatcher.p660;
@@ -45,7 +48,6 @@
4548
import static org.elasticsearch.packaging.util.Packages.verifyPackageInstallation;
4649
import static org.hamcrest.CoreMatchers.containsString;
4750
import static org.hamcrest.CoreMatchers.is;
48-
import static org.hamcrest.CoreMatchers.not;
4951
import static org.hamcrest.CoreMatchers.notNullValue;
5052
import static org.junit.Assume.assumeThat;
5153
import static org.junit.Assume.assumeTrue;
@@ -54,7 +56,7 @@ public class KeystoreManagementTests extends PackagingTestCase {
5456

5557
private static final String PASSWORD_ERROR_MESSAGE = "Provided keystore password was incorrect";
5658

57-
/** We need an initially installed package */
59+
/** Test initial archive state */
5860
public void test10InstallArchiveDistribution() throws Exception {
5961
assumeTrue(distribution().isArchive());
6062

@@ -63,11 +65,12 @@ public void test10InstallArchiveDistribution() throws Exception {
6365

6466
final Installation.Executables bin = installation.executables();
6567
Shell.Result r = sh.runIgnoreExitCode(bin.keystoreTool.toString() + " has-passwd");
66-
assertThat("has-passwd should fail", r.exitCode, not(is(0)));
67-
assertThat("has-passwd should fail", r.stderr, containsString("ERROR: Elasticsearch keystore not found"));
68+
assertFalse("has-passwd should fail", r.isSuccess());
69+
assertThat("has-passwd should indicate missing keystore",
70+
r.stderr, containsString("ERROR: Elasticsearch keystore not found"));
6871
}
6972

70-
/** We need an initially installed package */
73+
/** Test initial package state */
7174
public void test11InstallPackageDistribution() throws Exception {
7275
assumeTrue(distribution().isPackage());
7376

@@ -78,11 +81,34 @@ public void test11InstallPackageDistribution() throws Exception {
7881

7982
final Installation.Executables bin = installation.executables();
8083
Shell.Result r = sh.runIgnoreExitCode(bin.keystoreTool.toString() + " has-passwd");
81-
assertThat("has-passwd should fail", r.exitCode, not(is(0)));
82-
assertThat("has-passwd should fail", r.stderr, containsString("ERROR: Keystore is not password-protected"));
84+
assertFalse("has-passwd should fail", r.isSuccess());
85+
assertThat("has-passwd should indicate unprotected keystore",
86+
r.stderr, containsString("ERROR: Keystore is not password-protected"));
87+
Shell.Result r2 = bin.keystoreTool.run("list");
88+
assertThat(r2.stdout, containsString("keystore.seed"));
89+
}
90+
91+
/** Test initial Docker state */
92+
public void test12InstallDockerDistribution() throws Exception {
93+
assumeTrue(distribution().isDocker());
94+
95+
installation = Docker.runContainer(distribution());
96+
97+
try {
98+
waitForPathToExist(installation.config("elasticsearch.keystore"));
99+
} catch (InterruptedException e) {
100+
throw new RuntimeException(e);
101+
}
102+
103+
final Installation.Executables bin = installation.executables();
104+
Shell.Result r = sh.runIgnoreExitCode(bin.keystoreTool.toString() + " has-passwd");
105+
assertFalse("has-passwd should fail", r.isSuccess());
106+
assertThat("has-passwd should indicate unprotected keystore",
107+
r.stdout, containsString("ERROR: Keystore is not password-protected"));
108+
Shell.Result r2 = bin.keystoreTool.run("list");
109+
assertThat(r2.stdout, containsString("keystore.seed"));
83110
}
84111

85-
@Ignore /* Ignored for feature branch, awaits fix: https://github.com/elastic/elasticsearch/issues/49469 */
86112
public void test20CreateKeystoreManually() throws Exception {
87113
rmKeystoreIfExists();
88114
createKeystore();
@@ -95,7 +121,7 @@ public void test20CreateKeystoreManually() throws Exception {
95121
}
96122

97123
public void test30AutoCreateKeystore() throws Exception {
98-
assumeTrue("RPMs and Debs install a keystore file", distribution.isArchive());
124+
assumeTrue("Packages and docker are installed with a keystore file", distribution.isArchive());
99125
rmKeystoreIfExists();
100126

101127
startElasticsearch();
@@ -239,12 +265,31 @@ private void createKeystore() throws Exception {
239265
Platforms.onWindows(() -> {
240266
sh.chown(keystore);
241267
});
268+
269+
if (distribution().isDocker()) {
270+
try {
271+
waitForPathToExist(keystore);
272+
} catch (InterruptedException e) {
273+
throw new RuntimeException(e);
274+
}
275+
}
242276
}
243277

244278
private void rmKeystoreIfExists() {
245279
Path keystore = installation.config("elasticsearch.keystore");
246-
if (Files.exists(keystore)) {
247-
FileUtils.rm(keystore);
280+
if (distribution().isDocker()) {
281+
try {
282+
waitForPathToExist(keystore);
283+
} catch (InterruptedException e) {
284+
throw new RuntimeException(e);
285+
}
286+
287+
// Move the auto-created one out of the way, or else the CLI prompts asks us to confirm
288+
sh.run("rm " + keystore);
289+
} else {
290+
if (Files.exists(keystore)) {
291+
FileUtils.rm(keystore);
292+
}
248293
}
249294
}
250295

@@ -267,7 +312,7 @@ private void assertPasswordProtectedKeystore() {
267312
assertThat("keystore should be password protected", r.exitCode, is(0));
268313
}
269314

270-
private void verifyKeystorePermissions() throws Exception {
315+
private void verifyKeystorePermissions() {
271316
Path keystore = installation.config("elasticsearch.keystore");
272317
switch (distribution.packaging) {
273318
case TAR:
@@ -279,7 +324,7 @@ private void verifyKeystorePermissions() throws Exception {
279324
assertThat(keystore, file(File, "root", "elasticsearch", p660));
280325
break;
281326
case DOCKER:
282-
// TODO #49469
327+
assertPermissionsAndOwnership(keystore, p660);
283328
break;
284329
default:
285330
throw new IllegalStateException("Unknown Elasticsearch packaging type.");

qa/os/src/test/java/org/elasticsearch/packaging/test/PackagingTestCase.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.elasticsearch.packaging.util.Platforms;
3636
import org.elasticsearch.packaging.util.Shell;
3737
import org.junit.After;
38+
import org.junit.AfterClass;
3839
import org.junit.Assert;
3940
import org.junit.Before;
4041
import org.junit.BeforeClass;
@@ -49,6 +50,8 @@
4950
import java.nio.file.Paths;
5051

5152
import static org.elasticsearch.packaging.util.Cleanup.cleanEverything;
53+
import static org.elasticsearch.packaging.util.Docker.ensureImageIsLoaded;
54+
import static org.elasticsearch.packaging.util.Docker.removeContainer;
5255
import static org.hamcrest.CoreMatchers.containsString;
5356
import static org.hamcrest.CoreMatchers.equalTo;
5457
import static org.junit.Assume.assumeFalse;
@@ -117,9 +120,23 @@ public static void cleanup() throws Exception {
117120

118121
@BeforeClass
119122
public static void createShell() throws Exception {
120-
sh = new Shell();
123+
if (distribution().isDocker()) {
124+
ensureImageIsLoaded(distribution);
125+
sh = new Docker.DockerShell();
126+
} else {
127+
sh = new Shell();
128+
}
129+
}
130+
131+
@AfterClass
132+
public static void cleanupDocker() {
133+
if (distribution().isDocker()) {
134+
// runContainer also calls this, so we don't need this method to be annotated as `@After`
135+
removeContainer();
136+
}
121137
}
122138

139+
123140
@Before
124141
public void setup() throws Exception {
125142
assumeFalse(failed); // skip rest of tests once one fails

qa/os/src/test/java/org/elasticsearch/packaging/util/Cleanup.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public class Cleanup {
3737

3838
private static final List<String> ELASTICSEARCH_FILES_LINUX = Arrays.asList(
3939
"/usr/share/elasticsearch",
40-
"/etc/elasticsearch/elasticsearch-keystore",
40+
"/etc/elasticsearch/elasticsearch.keystore",
4141
"/etc/elasticsearch",
4242
"/var/lib/elasticsearch",
4343
"/var/log/elasticsearch",

qa/os/src/test/java/org/elasticsearch/packaging/util/Distribution.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ public boolean isPackage() {
6464
return packaging == Packaging.RPM || packaging == Packaging.DEB;
6565
}
6666

67+
public boolean isDocker() {
68+
return packaging == Packaging.DOCKER;
69+
}
70+
6771
public enum Packaging {
6872

6973
TAR(".tar.gz", Platforms.LINUX || Platforms.DARWIN),

qa/os/src/test/java/org/elasticsearch/packaging/util/Docker.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,9 @@ public static void waitForElasticsearchToStart() {
177177
// Give the container a chance to crash out
178178
Thread.sleep(1000);
179179

180-
psOutput = dockerShell.run("ps -w ax").stdout;
180+
psOutput = dockerShell.run("ps -ww ax").stdout;
181181

182-
if (psOutput.contains("/usr/share/elasticsearch/jdk/bin/java")) {
182+
if (psOutput.contains("org.elasticsearch.bootstrap.Elasticsearch")) {
183183
isElasticsearchRunning = true;
184184
break;
185185
}

0 commit comments

Comments
 (0)