|
@@ -0,0 +1,259 @@
|
|
|
|
+/*
|
|
|
|
+ * 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.packaging.util;
|
|
|
|
+
|
|
|
|
+import org.elasticsearch.packaging.util.Shell.Result;
|
|
|
|
+
|
|
|
|
+import java.io.IOException;
|
|
|
|
+import java.nio.file.Files;
|
|
|
|
+import java.nio.file.Path;
|
|
|
|
+import java.nio.file.Paths;
|
|
|
|
+import java.util.regex.Pattern;
|
|
|
|
+import java.util.stream.Stream;
|
|
|
|
+
|
|
|
|
+import static org.elasticsearch.packaging.util.FileMatcher.Fileness.Directory;
|
|
|
|
+import static org.elasticsearch.packaging.util.FileMatcher.Fileness.File;
|
|
|
|
+import static org.elasticsearch.packaging.util.FileMatcher.file;
|
|
|
|
+import static org.elasticsearch.packaging.util.FileMatcher.p644;
|
|
|
|
+import static org.elasticsearch.packaging.util.FileMatcher.p660;
|
|
|
|
+import static org.elasticsearch.packaging.util.FileMatcher.p750;
|
|
|
|
+import static org.elasticsearch.packaging.util.FileMatcher.p755;
|
|
|
|
+import static org.elasticsearch.packaging.util.FileUtils.getCurrentVersion;
|
|
|
|
+import static org.elasticsearch.packaging.util.FileUtils.getDistributionFile;
|
|
|
|
+import static org.elasticsearch.packaging.util.Platforms.isSysVInit;
|
|
|
|
+import static org.elasticsearch.packaging.util.Platforms.isSystemd;
|
|
|
|
+import static org.elasticsearch.packaging.util.ServerUtils.waitForElasticsearch;
|
|
|
|
+import static org.hamcrest.CoreMatchers.anyOf;
|
|
|
|
+import static org.hamcrest.CoreMatchers.containsString;
|
|
|
|
+import static org.hamcrest.CoreMatchers.is;
|
|
|
|
+import static org.hamcrest.MatcherAssert.assertThat;
|
|
|
|
+import static org.junit.Assert.assertFalse;
|
|
|
|
+import static org.junit.Assert.assertTrue;
|
|
|
|
+
|
|
|
|
+public class Packages {
|
|
|
|
+
|
|
|
|
+ public static final Path SYSVINIT_SCRIPT = Paths.get("/etc/init.d/elasticsearch");
|
|
|
|
+ public static final Path SYSTEMD_SERVICE = Paths.get("/usr/lib/systemd/system/elasticsearch.service");
|
|
|
|
+
|
|
|
|
+ public static void assertInstalled(Distribution distribution) {
|
|
|
|
+ final Result status = packageStatus(distribution);
|
|
|
|
+ assertThat(status.exitCode, is(0));
|
|
|
|
+
|
|
|
|
+ Platforms.onDPKG(() -> assertFalse(Pattern.compile("(?m)^Status:.+deinstall ok").matcher(status.stdout).find()));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void assertRemoved(Distribution distribution) {
|
|
|
|
+ final Result status = packageStatus(distribution);
|
|
|
|
+
|
|
|
|
+ Platforms.onRPM(() -> assertThat(status.exitCode, is(1)));
|
|
|
|
+
|
|
|
|
+ Platforms.onDPKG(() -> {
|
|
|
|
+ assertThat(status.exitCode, anyOf(is(0), is(1)));
|
|
|
|
+ if (status.exitCode == 0) {
|
|
|
|
+ assertTrue(Pattern.compile("(?m)^Status:.+deinstall ok").matcher(status.stdout).find());
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static Result packageStatus(Distribution distribution) {
|
|
|
|
+ final Shell sh = new Shell();
|
|
|
|
+ final Result result;
|
|
|
|
+
|
|
|
|
+ if (distribution.packaging == Distribution.Packaging.RPM) {
|
|
|
|
+ result = sh.runIgnoreExitCode("rpm -qe " + distribution.flavor.name);
|
|
|
|
+ } else {
|
|
|
|
+ result = sh.runIgnoreExitCode("dpkg -s " + distribution.flavor.name);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static Installation install(Distribution distribution) {
|
|
|
|
+ return install(distribution, getCurrentVersion());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static Installation install(Distribution distribution, String version) {
|
|
|
|
+ final Shell sh = new Shell();
|
|
|
|
+ final Path distributionFile = getDistributionFile(distribution, version);
|
|
|
|
+
|
|
|
|
+ Platforms.onRPM(() -> sh.run("rpm -i " + distributionFile));
|
|
|
|
+ Platforms.onDPKG(() -> sh.run("dpkg -i " + distributionFile));
|
|
|
|
+
|
|
|
|
+ return Installation.ofPackage(distribution.packaging);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void remove(Distribution distribution) {
|
|
|
|
+ final Shell sh = new Shell();
|
|
|
|
+
|
|
|
|
+ Platforms.onRPM(() -> {
|
|
|
|
+ sh.run("rpm -e " + distribution.flavor.name);
|
|
|
|
+ final Result status = packageStatus(distribution);
|
|
|
|
+ assertThat(status.exitCode, is(1));
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ Platforms.onDPKG(() -> {
|
|
|
|
+ sh.run("dpkg -r " + distribution.flavor.name);
|
|
|
|
+ final Result status = packageStatus(distribution);
|
|
|
|
+ assertThat(status.exitCode, is(0));
|
|
|
|
+ assertTrue(Pattern.compile("(?m)^Status:.+deinstall ok").matcher(status.stdout).find());
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void verifyPackageInstallation(Installation installation, Distribution distribution) {
|
|
|
|
+ verifyOssInstallation(installation, distribution);
|
|
|
|
+ if (distribution.flavor == Distribution.Flavor.DEFAULT) {
|
|
|
|
+ verifyDefaultInstallation(installation);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ private static void verifyOssInstallation(Installation es, Distribution distribution) {
|
|
|
|
+ final Shell sh = new Shell();
|
|
|
|
+
|
|
|
|
+ sh.run("id elasticsearch");
|
|
|
|
+ sh.run("getent group elasticsearch");
|
|
|
|
+
|
|
|
|
+ final Result passwdResult = sh.run("getent passwd elasticsearch");
|
|
|
|
+ final Path homeDir = Paths.get(passwdResult.stdout.trim().split(":")[5]);
|
|
|
|
+ assertFalse("elasticsearch user home directory must not exist", Files.exists(homeDir));
|
|
|
|
+
|
|
|
|
+ Stream.of(
|
|
|
|
+ es.home,
|
|
|
|
+ es.plugins,
|
|
|
|
+ es.modules
|
|
|
|
+ ).forEach(dir -> assertThat(dir, file(Directory, "root", "root", p755)));
|
|
|
|
+
|
|
|
|
+ assertThat(es.pidDir, file(Directory, "elasticsearch", "elasticsearch", p755));
|
|
|
|
+
|
|
|
|
+ Stream.of(
|
|
|
|
+ es.data,
|
|
|
|
+ es.logs
|
|
|
|
+ ).forEach(dir -> assertThat(dir, file(Directory, "elasticsearch", "elasticsearch", p750)));
|
|
|
|
+
|
|
|
|
+ // we shell out here because java's posix file permission view doesn't support special modes
|
|
|
|
+ assertThat(es.config, file(Directory, "root", "elasticsearch", p750));
|
|
|
|
+ assertThat(sh.run("find \"" + es.config + "\" -maxdepth 0 -printf \"%m\"").stdout, containsString("2750"));
|
|
|
|
+
|
|
|
|
+ Stream.of(
|
|
|
|
+ "elasticsearch.keystore",
|
|
|
|
+ "elasticsearch.yml",
|
|
|
|
+ "jvm.options",
|
|
|
|
+ "log4j2.properties"
|
|
|
|
+ ).forEach(configFile -> assertThat(es.config(configFile), file(File, "root", "elasticsearch", p660)));
|
|
|
|
+ assertThat(es.config(".elasticsearch.keystore.initial_md5sum"), file(File, "root", "elasticsearch", p644));
|
|
|
|
+
|
|
|
|
+ assertThat(sh.run("sudo -u elasticsearch " + es.bin("elasticsearch-keystore") + " list").stdout, containsString("keystore.seed"));
|
|
|
|
+
|
|
|
|
+ Stream.of(
|
|
|
|
+ es.bin,
|
|
|
|
+ es.lib
|
|
|
|
+ ).forEach(dir -> assertThat(dir, file(Directory, "root", "root", p755)));
|
|
|
|
+
|
|
|
|
+ Stream.of(
|
|
|
|
+ "elasticsearch",
|
|
|
|
+ "elasticsearch-plugin",
|
|
|
|
+ "elasticsearch-keystore",
|
|
|
|
+ "elasticsearch-translog"
|
|
|
|
+ ).forEach(executable -> assertThat(es.bin(executable), file(File, "root", "root", p755)));
|
|
|
|
+
|
|
|
|
+ Stream.of(
|
|
|
|
+ "NOTICE.txt",
|
|
|
|
+ "README.textile"
|
|
|
|
+ ).forEach(doc -> assertThat(es.home.resolve(doc), file(File, "root", "root", p644)));
|
|
|
|
+
|
|
|
|
+ assertThat(es.envFile, file(File, "root", "elasticsearch", p660));
|
|
|
|
+
|
|
|
|
+ if (distribution.packaging == Distribution.Packaging.RPM) {
|
|
|
|
+ assertThat(es.home.resolve("LICENSE.txt"), file(File, "root", "root", p644));
|
|
|
|
+ } else {
|
|
|
|
+ Path copyrightDir = Paths.get(sh.run("readlink -f /usr/share/doc/" + distribution.flavor.name).stdout.trim());
|
|
|
|
+ assertThat(copyrightDir, file(Directory, "root", "root", p755));
|
|
|
|
+ assertThat(copyrightDir.resolve("copyright"), file(File, "root", "root", p644));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (isSystemd()) {
|
|
|
|
+ Stream.of(
|
|
|
|
+ SYSTEMD_SERVICE,
|
|
|
|
+ Paths.get("/usr/lib/tmpfiles.d/elasticsearch.conf"),
|
|
|
|
+ Paths.get("/usr/lib/sysctl.d/elasticsearch.conf")
|
|
|
|
+ ).forEach(confFile -> assertThat(confFile, file(File, "root", "root", p644)));
|
|
|
|
+
|
|
|
|
+ final String sysctlExecutable = (distribution.packaging == Distribution.Packaging.RPM)
|
|
|
|
+ ? "/usr/sbin/sysctl"
|
|
|
|
+ : "/sbin/sysctl";
|
|
|
|
+ assertThat(sh.run(sysctlExecutable + " vm.max_map_count").stdout, containsString("vm.max_map_count = 262144"));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (isSysVInit()) {
|
|
|
|
+ assertThat(SYSVINIT_SCRIPT, file(File, "root", "root", p750));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static void verifyDefaultInstallation(Installation es) {
|
|
|
|
+
|
|
|
|
+ Stream.of(
|
|
|
|
+ "elasticsearch-certgen",
|
|
|
|
+ "elasticsearch-certutil",
|
|
|
|
+ "elasticsearch-croneval",
|
|
|
|
+ "elasticsearch-migrate",
|
|
|
|
+ "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 -> assertThat(es.bin(executable), file(File, "root", "root", 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
|
|
|
|
+ assertThat(es.bin("elasticsearch-sql-cli-" + getCurrentVersion() + ".jar"), file(File, "root", "root", p755));
|
|
|
|
+
|
|
|
|
+ Stream.of(
|
|
|
|
+ "users",
|
|
|
|
+ "users_roles",
|
|
|
|
+ "roles.yml",
|
|
|
|
+ "role_mapping.yml",
|
|
|
|
+ "log4j2.properties"
|
|
|
|
+ ).forEach(configFile -> assertThat(es.config(configFile), file(File, "root", "elasticsearch", p660)));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void startElasticsearch() throws IOException {
|
|
|
|
+ final Shell sh = new Shell();
|
|
|
|
+ if (isSystemd()) {
|
|
|
|
+ sh.run("systemctl daemon-reload");
|
|
|
|
+ sh.run("systemctl enable elasticsearch.service");
|
|
|
|
+ sh.run("systemctl is-enabled elasticsearch.service");
|
|
|
|
+ sh.run("systemctl start elasticsearch.service");
|
|
|
|
+ } else {
|
|
|
|
+ sh.run("service elasticsearch start");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ waitForElasticsearch();
|
|
|
|
+
|
|
|
|
+ if (isSystemd()) {
|
|
|
|
+ sh.run("systemctl is-active elasticsearch.service");
|
|
|
|
+ sh.run("systemctl status elasticsearch.service");
|
|
|
|
+ } else {
|
|
|
|
+ sh.run("service elasticsearch status");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|