Migrate setup passwords packaging test from bats (#49337)
This commit moves the packaging tests for elasticsearch-setup-passwords to java from bats. The change also enables future tests to enable security in Elasticsearch and automatically have waitForElasticsearch work correctly, at least to the same extent it worked in bats, by waiting on the ES port instead of health check. relates #46005
This commit is contained in:
parent
9c6a5a09af
commit
7802b60a5a
|
@ -1 +0,0 @@
|
|||
bootstrap_password.bash
|
|
@ -1 +0,0 @@
|
|||
bootstrap_password.bash
|
|
@ -1 +0,0 @@
|
|||
setup_passwords.bash
|
|
@ -1 +0,0 @@
|
|||
setup_passwords.bash
|
|
@ -1,170 +0,0 @@
|
|||
#!/usr/bin/env bats
|
||||
|
||||
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
# or more contributor license agreements. Licensed under the Elastic License;
|
||||
# you may not use this file except in compliance with the Elastic License.
|
||||
|
||||
load $BATS_UTILS/utils.bash
|
||||
load $BATS_UTILS/plugins.bash
|
||||
load $BATS_UTILS/xpack.bash
|
||||
|
||||
setup() {
|
||||
if [ $BATS_TEST_NUMBER == 1 ]; then
|
||||
export PACKAGE_NAME="elasticsearch"
|
||||
clean_before_test
|
||||
install
|
||||
set_debug_logging
|
||||
|
||||
generate_trial_license
|
||||
verify_xpack_installation
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ "$BATS_TEST_FILENAME" =~ 20_tar_bootstrap_password.bats$ ]]; then
|
||||
load $BATS_UTILS/tar.bash
|
||||
GROUP='TAR BOOTSTRAP PASSWORD'
|
||||
install() {
|
||||
install_archive
|
||||
verify_archive_installation
|
||||
}
|
||||
export ESHOME=/tmp/elasticsearch
|
||||
export_elasticsearch_paths
|
||||
export ESPLUGIN_COMMAND_USER=elasticsearch
|
||||
else
|
||||
load $BATS_UTILS/packages.bash
|
||||
if is_rpm; then
|
||||
GROUP='RPM BOOTSTRAP PASSWORD'
|
||||
elif is_dpkg; then
|
||||
GROUP='DEB BOOTSTRAP PASSWORD'
|
||||
fi
|
||||
export_elasticsearch_paths
|
||||
export ESPLUGIN_COMMAND_USER=root
|
||||
install() {
|
||||
install_package
|
||||
verify_package_installation
|
||||
}
|
||||
fi
|
||||
|
||||
@test "[$GROUP] add bootstrap.password setting" {
|
||||
if [[ -f /tmp/bootstrap.password ]]; then
|
||||
sudo rm -f /tmp/bootstrap.password
|
||||
fi
|
||||
|
||||
run sudo -E -u $ESPLUGIN_COMMAND_USER bash <<"NEW_PASS"
|
||||
if [[ ! -f $ESCONFIG/elasticsearch.keystore ]]; then
|
||||
$ESHOME/bin/elasticsearch-keystore create
|
||||
fi
|
||||
cat /dev/urandom | tr -dc "[a-zA-Z0-9]" | fold -w 20 | head -n 1 > /tmp/bootstrap.password
|
||||
cat /tmp/bootstrap.password | $ESHOME/bin/elasticsearch-keystore add --stdin bootstrap.password
|
||||
NEW_PASS
|
||||
[ "$status" -eq 0 ] || {
|
||||
echo "Expected elasticsearch-keystore tool exit code to be zero but got [$status]"
|
||||
echo "$output"
|
||||
false
|
||||
}
|
||||
assert_file_exist "/tmp/bootstrap.password"
|
||||
}
|
||||
|
||||
@test "[$GROUP] test bootstrap.password is in setting list" {
|
||||
run sudo -E -u $ESPLUGIN_COMMAND_USER bash <<"NODE_SETTINGS"
|
||||
cat >> $ESCONFIG/elasticsearch.yml <<- EOF
|
||||
network.host: 127.0.0.1
|
||||
http.port: 9200
|
||||
EOF
|
||||
NODE_SETTINGS
|
||||
|
||||
run_elasticsearch_service 0
|
||||
wait_for_xpack 127.0.0.1 9200
|
||||
|
||||
sudo -E -u $ESPLUGIN_COMMAND_USER "$ESHOME/bin/elasticsearch-keystore" list | grep "bootstrap.password"
|
||||
|
||||
password=$(cat /tmp/bootstrap.password)
|
||||
clusterHealth=$(sudo curl -u "elastic:$password" -H "Content-Type: application/json" \
|
||||
-XGET "http://127.0.0.1:9200/_cluster/health?wait_for_status=green&timeout=180s")
|
||||
echo "$clusterHealth" | grep '"status":"green"' || {
|
||||
echo "Expected cluster health to be green but got:"
|
||||
echo "$clusterHealth"
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@test "[$GROUP] test auto generated passwords with modified bootstrap.password" {
|
||||
if [[ -f /tmp/setup-passwords-output-with-bootstrap ]]; then
|
||||
sudo rm -f /tmp/setup-passwords-output-with-bootstrap
|
||||
fi
|
||||
|
||||
run sudo -E -u $ESPLUGIN_COMMAND_USER bash <<"SETUP_OK"
|
||||
echo 'y' | $ESHOME/bin/elasticsearch-setup-passwords auto
|
||||
SETUP_OK
|
||||
echo "$output" > /tmp/setup-passwords-output-with-bootstrap
|
||||
[ "$status" -eq 0 ] || {
|
||||
echo "Expected x-pack elasticsearch-setup-passwords tool exit code to be zero but got [$status]"
|
||||
cat /tmp/setup-passwords-output-with-bootstrap
|
||||
debug_collect_logs
|
||||
false
|
||||
}
|
||||
|
||||
curl -s -XGET 'http://127.0.0.1:9200' | grep "missing authentication credentials for REST"
|
||||
|
||||
# Disable bash history expansion because passwords can contain "!"
|
||||
set +H
|
||||
|
||||
users=( elastic kibana logstash_system )
|
||||
for user in "${users[@]}"; do
|
||||
grep "Changed password for user $user" /tmp/setup-passwords-output-with-bootstrap || {
|
||||
echo "Expected x-pack elasticsearch-setup-passwords tool to change password for user [$user]:"
|
||||
cat /tmp/setup-passwords-output-with-bootstrap
|
||||
false
|
||||
}
|
||||
|
||||
password=$(grep "PASSWORD $user = " /tmp/setup-passwords-output-with-bootstrap | sed "s/PASSWORD $user = //")
|
||||
curl -u "$user:$password" -XGET 'http://127.0.0.1:9200' | grep "You Know, for Search"
|
||||
|
||||
basic=$(echo -n "$user:$password" | base64)
|
||||
curl -H "Authorization: Basic $basic" -XGET 'http://127.0.0.1:9200' | grep "You Know, for Search"
|
||||
done
|
||||
set -H
|
||||
}
|
||||
|
||||
@test "[$GROUP] test elasticsearch-sql-cli" {
|
||||
password=$(grep "PASSWORD elastic = " /tmp/setup-passwords-output-with-bootstrap | sed "s/PASSWORD elastic = //")
|
||||
curl -s -u "elastic:$password" -H "Content-Type: application/json" -XPUT 'localhost:9200/library/book/1?refresh&pretty' -d'{
|
||||
"name": "Ender'"'"'s Game",
|
||||
"author": "Orson Scott Card",
|
||||
"release_date": "1985-06-01",
|
||||
"page_count": 324
|
||||
}'
|
||||
|
||||
password=$(grep "PASSWORD elastic = " /tmp/setup-passwords-output-with-bootstrap | sed "s/PASSWORD elastic = //")
|
||||
|
||||
run $ESHOME/bin/elasticsearch-sql-cli --debug "http://elastic@127.0.0.1:9200" <<SQL
|
||||
$password
|
||||
SELECT * FROM library;
|
||||
SQL
|
||||
[ "$status" -eq 0 ] || {
|
||||
echo "SQL cli failed:\n$output"
|
||||
false
|
||||
}
|
||||
[[ "$output" == *"Card"* ]] || {
|
||||
echo "Failed to find author [Card] in library:$output"
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@test "[$GROUP] test elasticsearch-sql-cli when user refuses password" {
|
||||
# Run with empty stdin
|
||||
run $ESHOME/bin/elasticsearch-sql-cli --debug "http://elastic@127.0.0.1:9200" <<SQL
|
||||
SQL
|
||||
[ "$status" -eq 77 ] || { #NOPERM
|
||||
echo "SQL cli failed:\n$output"
|
||||
false
|
||||
}
|
||||
[[ "$output" == *"password required"* ]] || {
|
||||
echo "Failed to find author [password required] in error:$output"
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@test "[$GROUP] stop Elasticsearch" {
|
||||
stop_elasticsearch_service
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
|
||||
#!/usr/bin/env bats
|
||||
|
||||
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
# or more contributor license agreements. Licensed under the Elastic License;
|
||||
# you may not use this file except in compliance with the Elastic License.
|
||||
|
||||
load $BATS_UTILS/utils.bash
|
||||
load $BATS_UTILS/plugins.bash
|
||||
load $BATS_UTILS/xpack.bash
|
||||
|
||||
setup() {
|
||||
if [ $BATS_TEST_NUMBER == 1 ]; then
|
||||
export PACKAGE_NAME="elasticsearch"
|
||||
clean_before_test
|
||||
install
|
||||
set_debug_logging
|
||||
|
||||
generate_trial_license
|
||||
verify_xpack_installation
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
if [[ "$BATS_TEST_FILENAME" =~ 30_tar_setup_passwords.bats$ ]]; then
|
||||
load $BATS_UTILS/tar.bash
|
||||
GROUP='TAR SETUP PASSWORD'
|
||||
install() {
|
||||
install_archive
|
||||
verify_archive_installation
|
||||
}
|
||||
export ESHOME=/tmp/elasticsearch
|
||||
export_elasticsearch_paths
|
||||
export ESPLUGIN_COMMAND_USER=elasticsearch
|
||||
else
|
||||
load $BATS_UTILS/packages.bash
|
||||
if is_rpm; then
|
||||
GROUP='RPM SETUP PASSWORD'
|
||||
elif is_dpkg; then
|
||||
GROUP='DEB SETUP PASSWORD'
|
||||
fi
|
||||
export_elasticsearch_paths
|
||||
export ESPLUGIN_COMMAND_USER=root
|
||||
install() {
|
||||
install_package
|
||||
verify_package_installation
|
||||
}
|
||||
fi
|
||||
|
||||
@test "[$GROUP] test auto generated passwords" {
|
||||
run_elasticsearch_service 0
|
||||
wait_for_xpack
|
||||
|
||||
run sudo -E -u $ESPLUGIN_COMMAND_USER bash <<"SETUP_AUTO"
|
||||
echo 'y' | $ESHOME/bin/elasticsearch-setup-passwords auto
|
||||
SETUP_AUTO
|
||||
echo "$output" > /tmp/setup-passwords-output
|
||||
[ "$status" -eq 0 ] || {
|
||||
echo "Expected x-pack elasticsearch-setup-passwords tool exit code to be zero but got $status"
|
||||
cat /tmp/setup-passwords-output
|
||||
debug_collect_logs
|
||||
false
|
||||
}
|
||||
|
||||
curl -s -XGET localhost:9200 | grep "missing authentication credentials for REST"
|
||||
|
||||
# Disable bash history expansion because passwords can contain "!"
|
||||
set +H
|
||||
|
||||
users=( elastic kibana logstash_system )
|
||||
for user in "${users[@]}"; do
|
||||
grep "Changed password for user $user" /tmp/setup-passwords-output || {
|
||||
echo "Expected x-pack elasticsearch-setup-passwords tool to change password for user [$user]:"
|
||||
cat /tmp/setup-passwords-output
|
||||
false
|
||||
}
|
||||
|
||||
password=$(grep "PASSWORD $user = " /tmp/setup-passwords-output | sed "s/PASSWORD $user = //")
|
||||
curl -u "$user:$password" -XGET localhost:9200 | grep "You Know, for Search"
|
||||
|
||||
basic=$(echo -n "$user:$password" | base64)
|
||||
curl -H "Authorization: Basic $basic" -XGET localhost:9200 | grep "You Know, for Search"
|
||||
done
|
||||
set -H
|
||||
|
||||
stop_elasticsearch_service
|
||||
}
|
|
@ -69,7 +69,7 @@ public class ArchiveTests extends PackagingTestCase {
|
|||
|
||||
public void test20PluginsListWithNoPlugins() throws Exception {
|
||||
final Installation.Executables bin = installation.executables();
|
||||
final Result r = sh.run(bin.elasticsearchPlugin + " list");
|
||||
final Result r = bin.elasticsearchPlugin.run(sh, "list");
|
||||
|
||||
assertThat(r.stdout, isEmptyString());
|
||||
}
|
||||
|
|
|
@ -26,8 +26,12 @@ import com.carrotsearch.randomizedtesting.annotations.TestMethodProviders;
|
|||
import com.carrotsearch.randomizedtesting.annotations.Timeout;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.packaging.util.Archives;
|
||||
import org.elasticsearch.packaging.util.Distribution;
|
||||
import org.elasticsearch.packaging.util.Docker;
|
||||
import org.elasticsearch.packaging.util.FileUtils;
|
||||
import org.elasticsearch.packaging.util.Installation;
|
||||
import org.elasticsearch.packaging.util.Packages;
|
||||
import org.elasticsearch.packaging.util.Platforms;
|
||||
import org.elasticsearch.packaging.util.Shell;
|
||||
import org.junit.Assert;
|
||||
|
@ -40,6 +44,7 @@ import org.junit.rules.TestWatcher;
|
|||
import org.junit.runner.Description;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static org.elasticsearch.packaging.util.Cleanup.cleanEverything;
|
||||
|
@ -119,7 +124,78 @@ public abstract class PackagingTestCase extends Assert {
|
|||
return distribution;
|
||||
}
|
||||
|
||||
protected Shell newShell() throws Exception {
|
||||
protected static void install() throws Exception {
|
||||
switch (distribution.packaging) {
|
||||
case TAR:
|
||||
case ZIP:
|
||||
installation = Archives.installArchive(distribution);
|
||||
Archives.verifyArchiveInstallation(installation, distribution);
|
||||
break;
|
||||
case DEB:
|
||||
case RPM:
|
||||
installation = Packages.installPackage(distribution);
|
||||
Packages.verifyPackageInstallation(installation, distribution, newShell());
|
||||
break;
|
||||
case DOCKER:
|
||||
installation = Docker.runContainer(distribution);
|
||||
Docker.verifyContainerInstallation(installation, distribution);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts and stops elasticsearch, and performs assertions while it is running.
|
||||
*/
|
||||
protected void assertWhileRunning(Platforms.PlatformAction assertions) throws Exception {
|
||||
try {
|
||||
switch (distribution.packaging) {
|
||||
case TAR:
|
||||
case ZIP:
|
||||
Archives.runElasticsearch(installation, sh);
|
||||
break;
|
||||
case DEB:
|
||||
case RPM:
|
||||
Packages.startElasticsearch(sh, installation);
|
||||
break;
|
||||
case DOCKER:
|
||||
// nothing, "installing" docker image is running it
|
||||
}
|
||||
|
||||
} catch (Exception e ){
|
||||
if (Files.exists(installation.home.resolve("elasticsearch.pid"))) {
|
||||
String pid = FileUtils.slurp(installation.home.resolve("elasticsearch.pid")).trim();
|
||||
logger.info("Dumping jstack of elasticsearch processb ({}) that failed to start", pid);
|
||||
sh.runIgnoreExitCode("jstack " + pid);
|
||||
}
|
||||
if (Files.exists(installation.logs.resolve("elasticsearch.log"))) {
|
||||
logger.warn("Elasticsearch log:\n" +
|
||||
FileUtils.slurpAllLogs(installation.logs, "elasticsearch.log", "*.log.gz"));
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
try {
|
||||
assertions.run();
|
||||
} catch (Exception e) {
|
||||
logger.warn("Elasticsearch log:\n" +
|
||||
FileUtils.slurpAllLogs(installation.logs, "elasticsearch.log", "*.log.gz"));
|
||||
throw e;
|
||||
}
|
||||
|
||||
switch (distribution.packaging) {
|
||||
case TAR:
|
||||
case ZIP:
|
||||
Archives.stopElasticsearch(installation);
|
||||
break;
|
||||
case DEB:
|
||||
case RPM:
|
||||
Packages.stopElasticsearch(sh);
|
||||
break;
|
||||
case DOCKER:
|
||||
// nothing, removing container is handled externally
|
||||
}
|
||||
}
|
||||
|
||||
protected static Shell newShell() throws Exception {
|
||||
Shell sh = new Shell();
|
||||
if (distribution().hasJdk == false) {
|
||||
Platforms.onLinux(() -> {
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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.test;
|
||||
|
||||
import org.apache.http.client.fluent.Request;
|
||||
import org.elasticsearch.packaging.util.Distribution;
|
||||
import org.elasticsearch.packaging.util.FileUtils;
|
||||
import org.elasticsearch.packaging.util.ServerUtils;
|
||||
import org.elasticsearch.packaging.util.Shell;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.elasticsearch.packaging.util.FileUtils.append;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.collection.IsMapContaining.hasKey;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
public class PasswordToolsTests extends PackagingTestCase {
|
||||
|
||||
private static final Pattern USERPASS_REGEX = Pattern.compile("PASSWORD (\\w+) = ([^\\s]+)");
|
||||
private static final String BOOTSTRAP_PASSWORD = "myS3curepass";
|
||||
|
||||
@Before
|
||||
public void filterDistros() {
|
||||
assumeTrue("only default distro", distribution.flavor == Distribution.Flavor.DEFAULT);
|
||||
assumeTrue("no docker", distribution.packaging != Distribution.Packaging.DOCKER);
|
||||
}
|
||||
|
||||
public void test010Install() throws Exception {
|
||||
install();
|
||||
append(installation.config("elasticsearch.yml"),
|
||||
"xpack.license.self_generated.type: trial\n" +
|
||||
"xpack.security.enabled: true");
|
||||
}
|
||||
|
||||
public void test20GeneratePasswords() throws Exception {
|
||||
assertWhileRunning(() -> {
|
||||
Shell.Result result = installation.executables().elasticsearchSetupPasswords.run(sh, "auto --batch", null);
|
||||
Map<String, String> userpasses = parseUsersAndPasswords(result.stdout);
|
||||
for (Map.Entry<String, String> userpass : userpasses.entrySet()) {
|
||||
String response = ServerUtils.makeRequest(Request.Get("http://localhost:9200"), userpass.getKey(), userpass.getValue());
|
||||
assertThat(response, containsString("You Know, for Search"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void test30AddBootstrapPassword() throws Exception {
|
||||
|
||||
try (Stream<Path> dataFiles = Files.list(installation.data)) {
|
||||
// delete each dir under data, not data itself
|
||||
dataFiles.forEach(file -> {
|
||||
if (distribution.platform != Distribution.Platform.WINDOWS) {
|
||||
FileUtils.rm(file);
|
||||
return;
|
||||
}
|
||||
// HACK: windows asynchronously releases file locks after processes exit. Unfortunately there is no clear way to wait on
|
||||
// those locks being released. We might be able to use `openfiles /query`, but that requires modifying global settings
|
||||
// in our windows images with `openfiles /local on` (which requires a restart, thus needs to be baked into the images).
|
||||
// The following sleep allows time for windows to release the data file locks from Elasticsearch which was stopped in the
|
||||
// previous test.
|
||||
int retries = 30;
|
||||
Exception failure = null;
|
||||
while (retries-- > 0) {
|
||||
try {
|
||||
FileUtils.rm(file);
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
if (failure == null) {
|
||||
failure = e;
|
||||
} else {
|
||||
failure.addSuppressed(e);
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException interrupted) {
|
||||
Thread.currentThread().interrupt();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("failed to delete " + file, failure);
|
||||
});
|
||||
}
|
||||
|
||||
installation.executables().elasticsearchKeystore.run(sh, "add --stdin bootstrap.password", BOOTSTRAP_PASSWORD);
|
||||
|
||||
assertWhileRunning(() -> {
|
||||
String response = ServerUtils.makeRequest(
|
||||
Request.Get("http://localhost:9200/_cluster/health?wait_for_status=green&timeout=180s"),
|
||||
"elastic", BOOTSTRAP_PASSWORD);
|
||||
assertThat(response, containsString("\"status\":\"green\""));
|
||||
});
|
||||
}
|
||||
|
||||
public void test40GeneratePasswordsBootstrapAlreadySet() throws Exception {
|
||||
assertWhileRunning(() -> {
|
||||
|
||||
Shell.Result result = installation.executables().elasticsearchSetupPasswords.run(sh, "auto --batch", null);
|
||||
Map<String, String> userpasses = parseUsersAndPasswords(result.stdout);
|
||||
assertThat(userpasses, hasKey("elastic"));
|
||||
for (Map.Entry<String, String> userpass : userpasses.entrySet()) {
|
||||
String response = ServerUtils.makeRequest(Request.Get("http://localhost:9200"), userpass.getKey(), userpass.getValue());
|
||||
assertThat(response, containsString("You Know, for Search"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Map<String, String> parseUsersAndPasswords(String output) {
|
||||
Matcher matcher = USERPASS_REGEX.matcher(output);
|
||||
assertNotNull(matcher);
|
||||
Map<String, String> userpases = new HashMap<>();
|
||||
while (matcher.find()) {
|
||||
userpases.put(matcher.group(1), matcher.group(2));
|
||||
}
|
||||
return userpases;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.test;
|
||||
|
||||
import org.elasticsearch.packaging.util.Distribution;
|
||||
import org.elasticsearch.packaging.util.Shell;
|
||||
import org.junit.Before;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
public class SqlCliTests extends PackagingTestCase {
|
||||
@Before
|
||||
public void filterDistros() {
|
||||
assumeTrue("only default distro", distribution.flavor == Distribution.Flavor.DEFAULT);
|
||||
assumeTrue("no docker", distribution.packaging != Distribution.Packaging.DOCKER);
|
||||
}
|
||||
|
||||
public void test010Install() throws Exception {
|
||||
install();
|
||||
}
|
||||
|
||||
public void test020Help() throws Exception {
|
||||
Shell.Result result = installation.executables().elasticsearchSqlCli.run(sh, "--help");
|
||||
assertThat(result.stdout, containsString("Elasticsearch SQL CLI"));
|
||||
}
|
||||
}
|
|
@ -111,7 +111,7 @@ public class Archives {
|
|||
|
||||
sh.chown(fullInstallPath);
|
||||
|
||||
return Installation.ofArchive(fullInstallPath);
|
||||
return Installation.ofArchive(distribution, fullInstallPath);
|
||||
}
|
||||
|
||||
private static void setupArchiveUsersLinux(Path installPath) {
|
||||
|
|
|
@ -99,7 +99,7 @@ public class Docker {
|
|||
|
||||
waitForElasticsearchToStart();
|
||||
|
||||
return Installation.ofContainer();
|
||||
return Installation.ofContainer(distribution);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,6 +27,12 @@ import java.nio.file.Paths;
|
|||
*/
|
||||
public class Installation {
|
||||
|
||||
// in the future we'll run as a role user on Windows
|
||||
public static final String ARCHIVE_OWNER = Platforms.WINDOWS
|
||||
? System.getenv("username")
|
||||
: "elasticsearch";
|
||||
|
||||
public final Distribution distribution;
|
||||
public final Path home;
|
||||
public final Path bin; // this isn't a first-class installation feature but we include it for convenience
|
||||
public final Path lib; // same
|
||||
|
@ -39,7 +45,9 @@ public class Installation {
|
|||
public final Path pidDir;
|
||||
public final Path envFile;
|
||||
|
||||
public Installation(Path home, Path config, Path data, Path logs, Path plugins, Path modules, Path pidDir, Path envFile) {
|
||||
private Installation(Distribution distribution, Path home, Path config, Path data, Path logs,
|
||||
Path plugins, Path modules, Path pidDir, Path envFile) {
|
||||
this.distribution = distribution;
|
||||
this.home = home;
|
||||
this.bin = home.resolve("bin");
|
||||
this.lib = home.resolve("lib");
|
||||
|
@ -53,8 +61,9 @@ public class Installation {
|
|||
this.envFile = envFile;
|
||||
}
|
||||
|
||||
public static Installation ofArchive(Path home) {
|
||||
public static Installation ofArchive(Distribution distribution, Path home) {
|
||||
return new Installation(
|
||||
distribution,
|
||||
home,
|
||||
home.resolve("config"),
|
||||
home.resolve("data"),
|
||||
|
@ -66,13 +75,14 @@ public class Installation {
|
|||
);
|
||||
}
|
||||
|
||||
public static Installation ofPackage(Distribution.Packaging packaging) {
|
||||
public static Installation ofPackage(Distribution distribution) {
|
||||
|
||||
final Path envFile = (packaging == Distribution.Packaging.RPM)
|
||||
final Path envFile = (distribution.packaging == Distribution.Packaging.RPM)
|
||||
? Paths.get("/etc/sysconfig/elasticsearch")
|
||||
: Paths.get("/etc/default/elasticsearch");
|
||||
|
||||
return new Installation(
|
||||
distribution,
|
||||
Paths.get("/usr/share/elasticsearch"),
|
||||
Paths.get("/etc/elasticsearch"),
|
||||
Paths.get("/var/lib/elasticsearch"),
|
||||
|
@ -84,9 +94,10 @@ public class Installation {
|
|||
);
|
||||
}
|
||||
|
||||
public static Installation ofContainer() {
|
||||
public static Installation ofContainer(Distribution distribution) {
|
||||
String root = "/usr/share/elasticsearch";
|
||||
return new Installation(
|
||||
distribution,
|
||||
Paths.get(root),
|
||||
Paths.get(root + "/config"),
|
||||
Paths.get(root + "/data"),
|
||||
|
@ -110,23 +121,48 @@ public class Installation {
|
|||
return new Executables();
|
||||
}
|
||||
|
||||
public class Executables {
|
||||
public class Executable {
|
||||
public final Path path;
|
||||
|
||||
public final Path elasticsearch = platformExecutable("elasticsearch");
|
||||
public final Path elasticsearchPlugin = platformExecutable("elasticsearch-plugin");
|
||||
public final Path elasticsearchKeystore = platformExecutable("elasticsearch-keystore");
|
||||
public final Path elasticsearchCertutil = platformExecutable("elasticsearch-certutil");
|
||||
public final Path elasticsearchShard = platformExecutable("elasticsearch-shard");
|
||||
public final Path elasticsearchNode = platformExecutable("elasticsearch-node");
|
||||
public final Path elasticsearchSetupPasswords = platformExecutable("elasticsearch-setup-passwords");
|
||||
public final Path elasticsearchSyskeygen = platformExecutable("elasticsearch-syskeygen");
|
||||
public final Path elasticsearchUsers = platformExecutable("elasticsearch-users");
|
||||
|
||||
private Path platformExecutable(String name) {
|
||||
private Executable(String name) {
|
||||
final String platformExecutableName = Platforms.WINDOWS
|
||||
? name + ".bat"
|
||||
: name;
|
||||
return bin(platformExecutableName);
|
||||
this.path = bin(platformExecutableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return path.toString();
|
||||
}
|
||||
|
||||
public Shell.Result run(Shell sh, String args) {
|
||||
return run(sh, args, null);
|
||||
}
|
||||
|
||||
public Shell.Result run(Shell sh, String args, String input) {
|
||||
String command = path + " " + args;
|
||||
if (distribution.isArchive() && distribution.platform != Distribution.Platform.WINDOWS) {
|
||||
command = "sudo -E -u " + ARCHIVE_OWNER + " " + command;
|
||||
}
|
||||
if (input != null) {
|
||||
command = "echo \"" + input + "\" | " + command;
|
||||
}
|
||||
return sh.run(command);
|
||||
}
|
||||
}
|
||||
|
||||
public class Executables {
|
||||
|
||||
public final Executable elasticsearch = new Executable("elasticsearch");
|
||||
public final Executable elasticsearchPlugin = new Executable("elasticsearch-plugin");
|
||||
public final Executable elasticsearchKeystore = new Executable("elasticsearch-keystore");
|
||||
public final Executable elasticsearchCertutil = new Executable("elasticsearch-certutil");
|
||||
public final Executable elasticsearchShard = new Executable("elasticsearch-shard");
|
||||
public final Executable elasticsearchNode = new Executable("elasticsearch-node");
|
||||
public final Executable elasticsearchSetupPasswords = new Executable("elasticsearch-setup-passwords");
|
||||
public final Executable elasticsearchSqlCli= new Executable("elasticsearch-sql-cli");
|
||||
public final Executable elasticsearchSyskeygen = new Executable("elasticsearch-syskeygen");
|
||||
public final Executable elasticsearchUsers = new Executable("elasticsearch-users");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ public class Packages {
|
|||
throw new RuntimeException("Installing distribution " + distribution + " failed: " + result);
|
||||
}
|
||||
|
||||
Installation installation = Installation.ofPackage(distribution.packaging);
|
||||
Installation installation = Installation.ofPackage(distribution);
|
||||
|
||||
if (distribution.hasJdk == false) {
|
||||
Files.write(installation.envFile, ("JAVA_HOME=" + systemJavaHome + "\n").getBytes(StandardCharsets.UTF_8),
|
||||
|
|
|
@ -29,6 +29,11 @@ import org.apache.logging.log4j.LogManager;
|
|||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -39,13 +44,32 @@ public class ServerUtils {
|
|||
|
||||
private static final Logger logger = LogManager.getLogger(ServerUtils.class);
|
||||
|
||||
private static String SECURITY_ENABLED = "xpack.security.enabled: true";
|
||||
|
||||
// generous timeout as nested virtualization can be quite slow ...
|
||||
private static final long waitTime = TimeUnit.MINUTES.toMillis(3);
|
||||
private static final long timeoutLength = TimeUnit.SECONDS.toMillis(30);
|
||||
private static final long requestInterval = TimeUnit.SECONDS.toMillis(5);
|
||||
|
||||
public static void waitForElasticsearch(Installation installation) throws IOException {
|
||||
waitForElasticsearch("green", null, installation, null, null);
|
||||
boolean securityEnabled = false;
|
||||
|
||||
// TODO: need a way to check if docker has security enabled, the yml config is not bind mounted so can't look from here
|
||||
if (installation.distribution.packaging != Distribution.Packaging.DOCKER) {
|
||||
Path configFilePath = installation.config("elasticsearch.yml");
|
||||
// this is fragile, but currently doesn't deviate from a single line enablement and not worth the parsing effort
|
||||
String configFile = Files.readString(configFilePath, StandardCharsets.UTF_8);
|
||||
securityEnabled = configFile.contains(SECURITY_ENABLED);
|
||||
}
|
||||
|
||||
if (securityEnabled) {
|
||||
// with security enabled, we may or may not have setup a user/pass, so we use a more generic port being available check.
|
||||
// this isn't as good as a health check, but long term all this waiting should go away when node startup does not
|
||||
// make the http port available until the system is really ready to serve requests
|
||||
waitForXpack();
|
||||
} else {
|
||||
waitForElasticsearch("green", null, installation, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,6 +92,26 @@ public class ServerUtils {
|
|||
return executor.execute(request).returnResponse();
|
||||
}
|
||||
|
||||
// polls every second for Elasticsearch to be running on 9200
|
||||
private static void waitForXpack() {
|
||||
int retries = 60;
|
||||
while (retries > 0) {
|
||||
retries -= 1;
|
||||
try (Socket s = new Socket(InetAddress.getLoopbackAddress(), 9200)) {
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
// ignore, only want to establish a connection
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException interrupted) {
|
||||
Thread.currentThread().interrupt();
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Elasticsearch (with x-pack) did not start");
|
||||
}
|
||||
|
||||
public static void waitForElasticsearch(
|
||||
String status,
|
||||
String index,
|
||||
|
|
Loading…
Reference in New Issue