|
@@ -30,12 +30,11 @@ import java.util.stream.Stream;
|
|
|
|
|
|
import static java.nio.file.attribute.PosixFilePermissions.fromString;
|
|
|
import static org.elasticsearch.packaging.util.DockerRun.getImageName;
|
|
|
+import static org.elasticsearch.packaging.util.FileMatcher.p444;
|
|
|
import static org.elasticsearch.packaging.util.FileMatcher.p555;
|
|
|
-import static org.elasticsearch.packaging.util.FileMatcher.p644;
|
|
|
import static org.elasticsearch.packaging.util.FileMatcher.p664;
|
|
|
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.MatcherAssert.assertThat;
|
|
|
import static org.hamcrest.Matchers.containsString;
|
|
@@ -214,7 +213,7 @@ public class Docker {
|
|
|
|
|
|
// I'm not sure why we're already removing this container, but that's OK.
|
|
|
if (isErrorAcceptable == false) {
|
|
|
- throw new RuntimeException("Command was not successful: [" + command + "] result: " + result.toString());
|
|
|
+ throw new RuntimeException("Command was not successful: [" + command + "] result: " + result);
|
|
|
}
|
|
|
}
|
|
|
} finally {
|
|
@@ -248,8 +247,6 @@ public class Docker {
|
|
|
List<String> cmd = new ArrayList<>();
|
|
|
cmd.add("docker");
|
|
|
cmd.add("exec");
|
|
|
- cmd.add("--user");
|
|
|
- cmd.add("elasticsearch:root");
|
|
|
cmd.add("--tty");
|
|
|
|
|
|
env.forEach((key, value) -> cmd.add("--env " + key + "=\"" + value + "\""));
|
|
@@ -402,25 +399,45 @@ public class Docker {
|
|
|
|
|
|
/**
|
|
|
* Checks that the specified path's permissions and ownership match those specified.
|
|
|
- * @param path the path to check
|
|
|
+ * <p>
|
|
|
+ * The implementation supports multiple files being matched by the path, via bash expansion, although
|
|
|
+ * it is expected that only the final part of the path will contain expansions.
|
|
|
+ *
|
|
|
+ * @param path the path to check, possibly with e.g. a wildcard (<code>*</code>)
|
|
|
+ * @param expectedUser the file's expected user
|
|
|
+ * @param expectedGroup the file's expected group
|
|
|
* @param expectedPermissions the unix permissions that the path ought to have
|
|
|
*/
|
|
|
- public static void assertPermissionsAndOwnership(Path path, Set<PosixFilePermission> expectedPermissions) {
|
|
|
+ public static void assertPermissionsAndOwnership(
|
|
|
+ Path path,
|
|
|
+ String expectedUser,
|
|
|
+ String expectedGroup,
|
|
|
+ Set<PosixFilePermission> expectedPermissions
|
|
|
+ ) {
|
|
|
logger.debug("Checking permissions and ownership of [" + path + "]");
|
|
|
|
|
|
- final String[] components = dockerShell.run("stat -c \"%U %G %A\" " + path).stdout.split("\\s+");
|
|
|
+ final Shell.Result result = dockerShell.run("bash -c 'stat -c \"%n %U %G %A\" " + path + "'");
|
|
|
+
|
|
|
+ final Path parent = path.getParent();
|
|
|
+
|
|
|
+ result.stdout.lines().forEach(line -> {
|
|
|
+ final String[] components = line.split("\\s+");
|
|
|
+
|
|
|
+ final String filename = components[0];
|
|
|
+ final String username = components[1];
|
|
|
+ final String group = components[2];
|
|
|
+ final String permissions = components[3];
|
|
|
|
|
|
- final String username = components[0];
|
|
|
- final String group = components[1];
|
|
|
- final String permissions = components[2];
|
|
|
+ // The final substring() is because we don't check the directory bit, and we
|
|
|
+ // also don't want any SELinux security context indicator.
|
|
|
+ Set<PosixFilePermission> actualPermissions = fromString(permissions.substring(1, 10));
|
|
|
|
|
|
- // The final substring() is because we don't check the directory bit, and we
|
|
|
- // also don't want any SELinux security context indicator.
|
|
|
- Set<PosixFilePermission> actualPermissions = fromString(permissions.substring(1, 10));
|
|
|
+ String fullPath = filename.startsWith("/") ? filename : parent + "/" + filename;
|
|
|
|
|
|
- assertEquals("Permissions of " + path + " are wrong", expectedPermissions, actualPermissions);
|
|
|
- assertThat("File owner of " + path + " is wrong", username, equalTo("elasticsearch"));
|
|
|
- assertThat("File group of " + path + " is wrong", group, equalTo("root"));
|
|
|
+ assertEquals("Permissions of " + fullPath + " are wrong", expectedPermissions, actualPermissions);
|
|
|
+ assertThat("File owner of " + fullPath + " is wrong", username, equalTo(expectedUser));
|
|
|
+ assertThat("File group of " + fullPath + " is wrong", group, equalTo(expectedGroup));
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -442,42 +459,39 @@ public class Docker {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Perform a variety of checks on an installation. If the current distribution is not OSS, additional checks are carried out.
|
|
|
- * @param installation the installation to verify
|
|
|
+ * Perform a variety of checks on an installation.
|
|
|
+ * @param es the installation to verify
|
|
|
*/
|
|
|
- public static void verifyContainerInstallation(Installation installation) {
|
|
|
- verifyOssInstallation(installation);
|
|
|
- verifyDefaultInstallation(installation);
|
|
|
- }
|
|
|
-
|
|
|
- private static void verifyOssInstallation(Installation es) {
|
|
|
+ public static void verifyContainerInstallation(Installation es) {
|
|
|
+ // Ensure the `elasticsearch` user and group exist.
|
|
|
+ // These lines will both throw an exception if the command fails
|
|
|
dockerShell.run("id elasticsearch");
|
|
|
dockerShell.run("getent group elasticsearch");
|
|
|
|
|
|
final Shell.Result passwdResult = dockerShell.run("getent passwd elasticsearch");
|
|
|
final String homeDir = passwdResult.stdout.trim().split(":")[5];
|
|
|
- assertThat(homeDir, equalTo("/usr/share/elasticsearch"));
|
|
|
+ assertThat("elasticsearch user's home directory is incorrect", homeDir, equalTo("/usr/share/elasticsearch"));
|
|
|
|
|
|
- Stream.of(es.home, es.data, es.logs, es.config, es.plugins).forEach(dir -> assertPermissionsAndOwnership(dir, p775));
|
|
|
+ assertPermissionsAndOwnership(es.home, "root", "root", p775);
|
|
|
|
|
|
- Stream.of(es.bin, es.bundledJdk, es.lib, es.modules).forEach(dir -> assertPermissionsAndOwnership(dir, p555));
|
|
|
+ Stream.of(es.bundledJdk, es.lib, es.modules).forEach(dir -> assertPermissionsAndOwnership(dir, "root", "root", p555));
|
|
|
|
|
|
- Stream.of("elasticsearch.yml", "jvm.options", "log4j2.properties")
|
|
|
- .forEach(configFile -> assertPermissionsAndOwnership(es.config(configFile), p664));
|
|
|
+ // You can't install plugins that include configuration when running as `elasticsearch` and the `config`
|
|
|
+ // dir is owned by `root`, because the installed tries to manipulate the permissions on the plugin's
|
|
|
+ // config directory.
|
|
|
+ Stream.of(es.bin, es.config, es.logs, es.config.resolve("jvm.options.d"), es.data, es.plugins)
|
|
|
+ .forEach(dir -> assertPermissionsAndOwnership(dir, "elasticsearch", "root", p775));
|
|
|
|
|
|
- assertThat(dockerShell.run(es.bin("elasticsearch-keystore") + " list").stdout, containsString("keystore.seed"));
|
|
|
+ Stream.of(es.bin, es.bundledJdk.resolve("bin"), es.modules.resolve("x-pack-ml/platform/linux-*/bin"))
|
|
|
+ .forEach(binariesPath -> assertPermissionsAndOwnership(binariesPath.resolve("*"), "root", "root", p555));
|
|
|
|
|
|
- Stream.of(
|
|
|
- "elasticsearch",
|
|
|
- "elasticsearch-cli",
|
|
|
- "elasticsearch-env",
|
|
|
- "elasticsearch-keystore",
|
|
|
- "elasticsearch-node",
|
|
|
- "elasticsearch-plugin",
|
|
|
- "elasticsearch-shard"
|
|
|
- ).forEach(executable -> assertPermissionsAndOwnership(es.bin(executable), p555));
|
|
|
+ Stream.of("elasticsearch.yml", "jvm.options", "log4j2.properties", "role_mapping.yml", "roles.yml", "users", "users_roles")
|
|
|
+ .forEach(configFile -> assertPermissionsAndOwnership(es.config(configFile), "root", "root", p664));
|
|
|
|
|
|
- Stream.of("LICENSE.txt", "NOTICE.txt", "README.asciidoc").forEach(doc -> assertPermissionsAndOwnership(es.home.resolve(doc), p644));
|
|
|
+ Stream.of("LICENSE.txt", "NOTICE.txt", "README.asciidoc")
|
|
|
+ .forEach(doc -> assertPermissionsAndOwnership(es.home.resolve(doc), "root", "root", p444));
|
|
|
+
|
|
|
+ assertThat(dockerShell.run(es.bin("elasticsearch-keystore") + " list").stdout, containsString("keystore.seed"));
|
|
|
|
|
|
// nc is useful for checking network issues
|
|
|
// zip/unzip are installed to help users who are working with certificates.
|
|
@@ -490,38 +504,6 @@ public class Docker {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- private static void verifyDefaultInstallation(Installation es) {
|
|
|
- Stream.of(
|
|
|
- "elasticsearch-certgen",
|
|
|
- "elasticsearch-certutil",
|
|
|
- "elasticsearch-croneval",
|
|
|
- "elasticsearch-saml-metadata",
|
|
|
- "elasticsearch-security-config",
|
|
|
- "elasticsearch-setup-passwords",
|
|
|
- "elasticsearch-sql-cli",
|
|
|
- "elasticsearch-syskeygen",
|
|
|
- "elasticsearch-users",
|
|
|
- "elasticsearch-service-tokens",
|
|
|
- "x-pack-env",
|
|
|
- "x-pack-security-env",
|
|
|
- "x-pack-watcher-env"
|
|
|
- ).forEach(executable -> assertPermissionsAndOwnership(es.bin(executable), p555));
|
|
|
-
|
|
|
- // 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"), p555);
|
|
|
-
|
|
|
- final String architecture = getArchitecture();
|
|
|
- Stream.of("autodetect", "categorize", "controller", "data_frame_analyzer", "normalize", "pytorch_inference")
|
|
|
- .forEach(executableName -> {
|
|
|
- final Path executablePath = es.modules.resolve("x-pack-ml/platform/linux-" + architecture + "/bin/" + executableName);
|
|
|
- assertPermissionsAndOwnership(executablePath, p555);
|
|
|
- });
|
|
|
-
|
|
|
- Stream.of("role_mapping.yml", "roles.yml", "users", "users_roles")
|
|
|
- .forEach(configFile -> assertPermissionsAndOwnership(es.config(configFile), p664));
|
|
|
- }
|
|
|
-
|
|
|
public static void waitForElasticsearch(Installation installation) throws Exception {
|
|
|
withLogging(() -> ServerUtils.waitForElasticsearch(installation));
|
|
|
}
|
|
@@ -625,12 +607,4 @@ public class Docker {
|
|
|
public static void restartContainer() {
|
|
|
sh.run("docker restart " + containerId);
|
|
|
}
|
|
|
-
|
|
|
- private static String getArchitecture() {
|
|
|
- String architecture = System.getProperty("os.arch", "x86_64");
|
|
|
- if (architecture.equals("amd64")) {
|
|
|
- architecture = "x86_64";
|
|
|
- }
|
|
|
- return architecture;
|
|
|
- }
|
|
|
}
|