*/
package org.sonar.application.process;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.net.ConnectException;
import org.elasticsearch.ElasticsearchException;
-import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.cluster.health.ClusterHealthStatus;
-import org.elasticsearch.rest.RestStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.application.es.EsConnector;
public class EsManagedProcess extends AbstractManagedProcess {
private static final Logger LOG = LoggerFactory.getLogger(EsManagedProcess.class);
private static final int WAIT_FOR_UP_DELAY_IN_MILLIS = 100;
- private static final Set<String> SUPPRESSED_ERROR_MESSAGES = Set.of("Connection refused", "Timeout connecting");
private volatile boolean nodeOperational = false;
private final int waitForUpTimeout;
- private final AtomicBoolean firstMasterNotDiscoveredLog = new AtomicBoolean(true);
private final EsConnector esConnector;
public EsManagedProcess(Process process, ProcessId processId, EsConnector esConnector) {
return esConnector.getClusterHealthStatus()
.map(EsManagedProcess::convert)
.orElse(CONNECTION_REFUSED);
- } catch (ElasticsearchStatusException e) {
- if (e.status() == RestStatus.SERVICE_UNAVAILABLE && e.getMessage().contains("type=master_not_discovered_exception")) {
- if (firstMasterNotDiscoveredLog.getAndSet(false)) {
- LOG.info("Elasticsearch is waiting for a master to be elected. Did you start all the search nodes ?");
- }
- }
- return KO;
} catch (ElasticsearchException e) {
- if (e.status() == RestStatus.INTERNAL_SERVER_ERROR && (SUPPRESSED_ERROR_MESSAGES.stream().anyMatch(s -> e.getMessage().contains(s)))) {
+ if (e.getRootCause() instanceof ConnectException) {
return CONNECTION_REFUSED;
- } else {
- LOG.error("Failed to check status", e);
}
+ LOG.error("Failed to check status", e);
return KO;
} catch (Exception e) {
LOG.error("Failed to check status", e);
*/
package org.sonar.application.process;
-import ch.qos.logback.classic.Level;
-import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import ch.qos.logback.core.AppenderBase;
import java.net.ConnectException;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import org.elasticsearch.ElasticsearchException;
-import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.cluster.health.ClusterHealthStatus;
-import org.elasticsearch.rest.RestStatus;
import org.junit.Test;
-import org.slf4j.LoggerFactory;
import org.sonar.application.es.EsConnector;
import org.sonar.process.ProcessId;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
}
@Test
- public void isOperational_should_return_false_if_ElasticsearchException_thrown() {
+ public void isOperational_should_not_be_os_language_sensitive() {
EsConnector esConnector = mock(EsConnector.class);
when(esConnector.getClusterHealthStatus())
- .thenThrow(new ElasticsearchException("test"));
- EsManagedProcess underTest = new EsManagedProcess(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector, WAIT_FOR_UP_TIMEOUT);
+ .thenThrow(new ElasticsearchException(new ExecutionException(new ConnectException("Connexion refusée"))));
+ EsManagedProcess underTest = new EsManagedProcess(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector, WAIT_FOR_UP_TIMEOUT_LONG);
assertThat(underTest.isOperational()).isFalse();
}
@Test
- public void isOperational_must_log_once_when_master_is_not_elected() {
- MemoryAppender<ILoggingEvent> memoryAppender = new MemoryAppender<>();
- LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
- lc.reset();
- memoryAppender.setContext(lc);
- memoryAppender.start();
- lc.getLogger(EsManagedProcess.class).addAppender(memoryAppender);
-
+ public void isOperational_if_exception_root_cause_returned_by_ES_is_not_ConnectException_should_return_false() {
EsConnector esConnector = mock(EsConnector.class);
when(esConnector.getClusterHealthStatus())
- .thenThrow(new ElasticsearchStatusException("foobar[type=master_not_discovered_exception,acme]...", RestStatus.SERVICE_UNAVAILABLE));
-
- EsManagedProcess underTest = new EsManagedProcess(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector, WAIT_FOR_UP_TIMEOUT);
- assertThat(underTest.isOperational()).isFalse();
- assertThat(memoryAppender.events).isNotEmpty();
- assertThat(memoryAppender.events)
- .extracting(ILoggingEvent::getLevel, ILoggingEvent::getMessage)
- .containsOnlyOnce(
- tuple(Level.INFO, "Elasticsearch is waiting for a master to be elected. Did you start all the search nodes ?"));
-
- // Second call must not log another message
+ .thenThrow(new ElasticsearchException(new ExecutionException(new Exception("Connexion refusée"))));
+ EsManagedProcess underTest = new EsManagedProcess(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector, WAIT_FOR_UP_TIMEOUT_LONG);
assertThat(underTest.isOperational()).isFalse();
- assertThat(memoryAppender.events)
- .extracting(ILoggingEvent::getLevel, ILoggingEvent::getMessage)
- .containsOnlyOnce(
- tuple(Level.INFO, "Elasticsearch is waiting for a master to be elected. Did you start all the search nodes ?"));
}
- private static class MemoryAppender<E> extends AppenderBase<E> {
- private final List<E> events = new ArrayList<>();
-
- @Override
- protected void append(E eventObject) {
- events.add(eventObject);
- }
+ @Test
+ public void isOperational_should_return_false_if_ElasticsearchException_thrown() {
+ EsConnector esConnector = mock(EsConnector.class);
+ when(esConnector.getClusterHealthStatus())
+ .thenThrow(new ElasticsearchException("test"));
+ EsManagedProcess underTest = new EsManagedProcess(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector, WAIT_FOR_UP_TIMEOUT);
+ assertThat(underTest.isOperational()).isFalse();
}
}