]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9764 Add a dedicated message when there is no Elasticsearch master
authorEric Hartmann <hartmann.eric@gmail.com>
Mon, 11 Sep 2017 13:37:47 +0000 (15:37 +0200)
committerEric Hartmann <hartmann.eric@gmail.Com>
Thu, 14 Sep 2017 15:55:38 +0000 (17:55 +0200)
server/sonar-main/src/main/java/org/sonar/application/process/EsProcessMonitor.java
server/sonar-main/src/test/java/org/sonar/application/process/EsProcessMonitorTest.java

index ff049e69e67875fe5490012df938913063c703dc..e4730c7303d4bd766942fe69f22f3486598faec5 100644 (file)
@@ -34,6 +34,7 @@ import org.elasticsearch.common.network.NetworkModule;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.transport.InetSocketTransportAddress;
 import org.elasticsearch.common.transport.TransportAddress;
+import org.elasticsearch.discovery.MasterNotDiscoveredException;
 import org.elasticsearch.transport.Netty4Plugin;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -54,6 +55,7 @@ public class EsProcessMonitor extends AbstractProcessMonitor {
 
   private final AtomicBoolean nodeUp = new AtomicBoolean(false);
   private final AtomicBoolean nodeOperational = new AtomicBoolean(false);
+  private final AtomicBoolean firstMasterNotDiscoveredLog = new AtomicBoolean(true);
   private final EsCommand esCommand;
   private final EsConnector esConnector;
   private AtomicReference<TransportClient> transportClient = new AtomicReference<>(null);
@@ -140,6 +142,11 @@ public class EsProcessMonitor extends AbstractProcessMonitor {
       }
     } catch (NoNodeAvailableException e) {
       return CONNECTION_REFUSED;
+    } catch (MasterNotDiscoveredException e) {
+      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 (Exception e) {
       LOG.error("Failed to check status", e);
       return KO;
index f1993b462f6f0febad13462a7d153cad72754c6d..d0ef83444fc3eec690e31c7260ff9e75d885338f 100644 (file)
  */
 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.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Random;
 import org.elasticsearch.client.transport.NoNodeAvailableException;
 import org.elasticsearch.cluster.health.ClusterHealthStatus;
+import org.elasticsearch.discovery.MasterNotDiscoveredException;
 import org.junit.Test;
+import org.slf4j.LoggerFactory;
 import org.sonar.process.ProcessId;
 import org.sonar.process.command.EsCommand;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -90,10 +99,50 @@ public class EsProcessMonitorTest {
     assertThat(underTest.isOperational()).isFalse();
   }
 
+  @Test
+  public void isOperational_must_log_once_when_master_is_not_elected() throws Exception {
+    MemoryAppender<ILoggingEvent> memoryAppender = new MemoryAppender<>();
+    LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
+    lc.reset();
+    memoryAppender.setContext(lc);
+    memoryAppender.start();
+    lc.getLogger(EsProcessMonitor.class).addAppender(memoryAppender);
+
+    EsConnector esConnector = mock(EsConnector.class);
+    when(esConnector.getClusterHealthStatus(any()))
+      .thenThrow(new MasterNotDiscoveredException("Master not elected -test-"));
+
+    EsProcessMonitor underTest = new EsProcessMonitor(mock(Process.class), getEsCommand(), esConnector);
+    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
+    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 EsCommand getEsCommand() throws IOException {
     Path tempDirectory = Files.createTempDirectory(getClass().getSimpleName());
     return new EsCommand(ProcessId.ELASTICSEARCH, tempDirectory.toFile())
       .setHost("localhost")
       .setPort(new Random().nextInt(40000));
   }
+
+  private class MemoryAppender<E> extends AppenderBase<E> {
+    private final List<E> events = new ArrayList();
+
+    @Override
+    protected void append(E eventObject) {
+      events.add(eventObject);
+    }
+  }
 }