Output all failing bootstrap checks

This commit modifies the boostrap checks to output all failing checks
instead of early-failing on the first check and then possibly failing
again after the user resolves the first failing check.

Closes #17474
This commit is contained in:
Jason Tedor 2016-04-07 09:50:43 -04:00
parent cfc23a9d67
commit fc7442739c
2 changed files with 57 additions and 8 deletions

View File

@ -34,6 +34,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
/**
* We enforce limits once any network host is configured. In this case we assume the node is running in production
@ -72,14 +73,22 @@ final class BootstrapCheck {
static void check(final boolean enforceLimits, final List<Check> checks, final String nodeName) {
final ESLogger logger = Loggers.getLogger(BootstrapCheck.class, nodeName);
for (final Check check : checks) {
final boolean fail = check.check();
if (fail) {
if (enforceLimits) {
throw new RuntimeException(check.errorMessage());
} else {
logger.warn(check.errorMessage());
}
final List<String> errors =
checks.stream()
.filter(BootstrapCheck.Check::check)
.map(BootstrapCheck.Check::errorMessage)
.collect(Collectors.toList());
if (!errors.isEmpty()) {
final List<String> messages = new ArrayList<>(1 + errors.size());
messages.add("bootstrap checks failed");
messages.addAll(errors);
if (enforceLimits) {
final RuntimeException re = new RuntimeException(String.join("\n", messages));
errors.stream().map(IllegalStateException::new).forEach(re::addSuppressed);
throw re;
} else {
messages.forEach(message -> logger.warn(message));
}
}
}

View File

@ -26,12 +26,16 @@ import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.test.ESTestCase;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.Matchers.hasToString;
import static org.hamcrest.Matchers.not;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -97,6 +101,42 @@ public class BootstrapCheckTests extends ESTestCase {
assertTrue(BootstrapCheck.enforceLimits(boundTransportAddress));
}
public void testExceptionAggregation() {
final List<BootstrapCheck.Check> checks = Arrays.asList(
new BootstrapCheck.Check() {
@Override
public boolean check() {
return true;
}
@Override
public String errorMessage() {
return "first";
}
},
new BootstrapCheck.Check() {
@Override
public boolean check() {
return true;
}
@Override
public String errorMessage() {
return "second";
}
}
);
final RuntimeException e =
expectThrows(RuntimeException.class, () -> BootstrapCheck.check(true, checks, "testExceptionAggregation"));
assertThat(e, hasToString(allOf(containsString("bootstrap checks failed"), containsString("first"), containsString("second"))));
final Throwable[] suppressed = e.getSuppressed();
assertThat(suppressed.length, equalTo(2));
assertThat(suppressed[0], instanceOf(IllegalStateException.class));
assertThat(suppressed[0], hasToString(containsString("first")));
assertThat(suppressed[1], instanceOf(IllegalStateException.class));
assertThat(suppressed[1], hasToString(containsString("second")));
}
public void testFileDescriptorLimits() {
final boolean osX = randomBoolean(); // simulates OS X versus non-OS X
final int limit = osX ? 10240 : 1 << 16;