You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

EsSettingsTest.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2019 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.application.es;
  21. import ch.qos.logback.classic.spi.ILoggingEvent;
  22. import com.google.common.collect.ImmutableSet;
  23. import java.io.File;
  24. import java.io.IOException;
  25. import java.util.Map;
  26. import java.util.Properties;
  27. import java.util.Random;
  28. import org.junit.After;
  29. import org.junit.Rule;
  30. import org.junit.Test;
  31. import org.junit.rules.ExpectedException;
  32. import org.junit.rules.TemporaryFolder;
  33. import org.sonar.application.logging.ListAppender;
  34. import org.sonar.core.extension.ServiceLoaderWrapper;
  35. import org.sonar.process.ProcessProperties;
  36. import org.sonar.process.ProcessProperties.Property;
  37. import org.sonar.process.Props;
  38. import org.sonar.process.System2;
  39. import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
  40. import static org.assertj.core.api.Assertions.assertThat;
  41. import static org.mockito.Mockito.mock;
  42. import static org.mockito.Mockito.when;
  43. import static org.sonar.process.ProcessProperties.Property.CLUSTER_NAME;
  44. import static org.sonar.process.ProcessProperties.Property.CLUSTER_NODE_NAME;
  45. import static org.sonar.process.ProcessProperties.Property.CLUSTER_SEARCH_HOSTS;
  46. import static org.sonar.process.ProcessProperties.Property.PATH_DATA;
  47. import static org.sonar.process.ProcessProperties.Property.PATH_HOME;
  48. import static org.sonar.process.ProcessProperties.Property.PATH_LOGS;
  49. import static org.sonar.process.ProcessProperties.Property.PATH_TEMP;
  50. import static org.sonar.process.ProcessProperties.Property.SEARCH_HOST;
  51. import static org.sonar.process.ProcessProperties.Property.SEARCH_HTTP_PORT;
  52. import static org.sonar.process.ProcessProperties.Property.SEARCH_INITIAL_STATE_TIMEOUT;
  53. import static org.sonar.process.ProcessProperties.Property.SEARCH_MINIMUM_MASTER_NODES;
  54. import static org.sonar.process.ProcessProperties.Property.SEARCH_PORT;
  55. public class EsSettingsTest {
  56. private static final boolean CLUSTER_ENABLED = true;
  57. private static final boolean CLUSTER_DISABLED = false;
  58. @Rule
  59. public TemporaryFolder temp = new TemporaryFolder();
  60. @Rule
  61. public ExpectedException expectedException = ExpectedException.none();
  62. private ListAppender listAppender;
  63. @After
  64. public void tearDown() {
  65. if (listAppender != null) {
  66. ListAppender.detachMemoryAppenderToLoggerOf(EsSettings.class, listAppender);
  67. }
  68. }
  69. @Test
  70. public void constructor_does_not_logs_warning_if_env_variable_ES_JVM_OPTIONS_is_not_set() {
  71. this.listAppender = ListAppender.attachMemoryAppenderToLoggerOf(EsSettings.class);
  72. Props props = minimalProps();
  73. System2 system2 = mock(System2.class);
  74. new EsSettings(props, new EsInstallation(props), system2);
  75. assertThat(listAppender.getLogs()).isEmpty();
  76. }
  77. @Test
  78. public void constructor_does_not_logs_warning_if_env_variable_ES_JVM_OPTIONS_is_set_and_empty() {
  79. this.listAppender = ListAppender.attachMemoryAppenderToLoggerOf(EsSettings.class);
  80. Props props = minimalProps();
  81. System2 system2 = mock(System2.class);
  82. when(system2.getenv("ES_JVM_OPTIONS")).thenReturn(" ");
  83. new EsSettings(props, new EsInstallation(props), system2);
  84. assertThat(listAppender.getLogs()).isEmpty();
  85. }
  86. @Test
  87. public void constructor_logs_warning_if_env_variable_ES_JVM_OPTIONS_is_set_and_non_empty() {
  88. this.listAppender = ListAppender.attachMemoryAppenderToLoggerOf(EsSettings.class);
  89. Props props = minimalProps();
  90. System2 system2 = mock(System2.class);
  91. when(system2.getenv("ES_JVM_OPTIONS")).thenReturn(randomAlphanumeric(2));
  92. new EsSettings(props, new EsInstallation(props), system2);
  93. assertThat(listAppender.getLogs())
  94. .extracting(ILoggingEvent::getMessage)
  95. .containsOnly("ES_JVM_OPTIONS is defined but will be ignored. " +
  96. "Use sonar.search.javaOpts and/or sonar.search.javaAdditionalOpts in sonar.properties to specify jvm options for Elasticsearch");
  97. }
  98. private Props minimalProps() {
  99. Props props = new Props(new Properties());
  100. props.set(PATH_HOME.getKey(), randomAlphanumeric(12));
  101. props.set(PATH_DATA.getKey(), randomAlphanumeric(12));
  102. props.set(PATH_TEMP.getKey(), randomAlphanumeric(12));
  103. props.set(PATH_LOGS.getKey(), randomAlphanumeric(12));
  104. props.set(CLUSTER_NAME.getKey(), randomAlphanumeric(12));
  105. return props;
  106. }
  107. @Test
  108. public void test_default_settings_for_standalone_mode() throws Exception {
  109. File homeDir = temp.newFolder();
  110. Props props = new Props(new Properties());
  111. props.set(SEARCH_PORT.getKey(), "1234");
  112. props.set(SEARCH_HOST.getKey(), "127.0.0.1");
  113. props.set(PATH_HOME.getKey(), homeDir.getAbsolutePath());
  114. props.set(PATH_DATA.getKey(), temp.newFolder().getAbsolutePath());
  115. props.set(PATH_TEMP.getKey(), temp.newFolder().getAbsolutePath());
  116. props.set(PATH_LOGS.getKey(), temp.newFolder().getAbsolutePath());
  117. props.set(CLUSTER_NAME.getKey(), "sonarqube");
  118. EsSettings esSettings = new EsSettings(props, new EsInstallation(props), System2.INSTANCE);
  119. Map<String, String> generated = esSettings.build();
  120. assertThat(generated.get("transport.tcp.port")).isEqualTo("1234");
  121. assertThat(generated.get("transport.host")).isEqualTo("127.0.0.1");
  122. // no cluster, but cluster and node names are set though
  123. assertThat(generated.get("cluster.name")).isEqualTo("sonarqube");
  124. assertThat(generated.get("node.name")).isEqualTo("sonarqube");
  125. assertThat(generated.get("path.data")).isNotNull();
  126. assertThat(generated.get("path.logs")).isNotNull();
  127. assertThat(generated.get("path.home")).isNull();
  128. assertThat(generated.get("path.conf")).isNull();
  129. // http is disabled for security reasons
  130. assertThat(generated.get("http.enabled")).isEqualTo("false");
  131. assertThat(generated.get("discovery.zen.ping.unicast.hosts")).isNull();
  132. assertThat(generated.get("discovery.zen.minimum_master_nodes")).isEqualTo("1");
  133. assertThat(generated.get("discovery.initial_state_timeout")).isEqualTo("30s");
  134. assertThat(generated.get("action.auto_create_index")).isEqualTo("false");
  135. }
  136. @Test
  137. public void test_default_settings_for_cluster_mode() throws Exception {
  138. File homeDir = temp.newFolder();
  139. Props props = new Props(new Properties());
  140. props.set(SEARCH_PORT.getKey(), "1234");
  141. props.set(SEARCH_HOST.getKey(), "127.0.0.1");
  142. props.set(PATH_HOME.getKey(), homeDir.getAbsolutePath());
  143. props.set(PATH_DATA.getKey(), temp.newFolder().getAbsolutePath());
  144. props.set(PATH_TEMP.getKey(), temp.newFolder().getAbsolutePath());
  145. props.set(PATH_LOGS.getKey(), temp.newFolder().getAbsolutePath());
  146. props.set(CLUSTER_NAME.getKey(), "sonarqube-1");
  147. props.set(Property.CLUSTER_ENABLED.getKey(), "true");
  148. props.set(CLUSTER_NODE_NAME.getKey(), "node-1");
  149. EsSettings esSettings = new EsSettings(props, new EsInstallation(props), System2.INSTANCE);
  150. Map<String, String> generated = esSettings.build();
  151. assertThat(generated.get("cluster.name")).isEqualTo("sonarqube-1");
  152. assertThat(generated.get("node.name")).isEqualTo("node-1");
  153. }
  154. @Test
  155. public void test_node_name_default_for_cluster_mode() throws Exception {
  156. File homeDir = temp.newFolder();
  157. Props props = new Props(new Properties());
  158. props.set(CLUSTER_NAME.getKey(), "sonarqube");
  159. props.set(Property.CLUSTER_ENABLED.getKey(), "true");
  160. props.set(SEARCH_PORT.getKey(), "1234");
  161. props.set(SEARCH_HOST.getKey(), "127.0.0.1");
  162. props.set(PATH_HOME.getKey(), homeDir.getAbsolutePath());
  163. props.set(PATH_DATA.getKey(), temp.newFolder().getAbsolutePath());
  164. props.set(PATH_TEMP.getKey(), temp.newFolder().getAbsolutePath());
  165. props.set(PATH_LOGS.getKey(), temp.newFolder().getAbsolutePath());
  166. EsSettings esSettings = new EsSettings(props, new EsInstallation(props), System2.INSTANCE);
  167. Map<String, String> generated = esSettings.build();
  168. assertThat(generated.get("node.name")).startsWith("sonarqube-");
  169. }
  170. @Test
  171. public void test_node_name_default_for_standalone_mode() throws Exception {
  172. File homeDir = temp.newFolder();
  173. Props props = new Props(new Properties());
  174. props.set(CLUSTER_NAME.getKey(), "sonarqube");
  175. props.set(Property.CLUSTER_ENABLED.getKey(), "false");
  176. props.set(SEARCH_PORT.getKey(), "1234");
  177. props.set(SEARCH_HOST.getKey(), "127.0.0.1");
  178. props.set(PATH_HOME.getKey(), homeDir.getAbsolutePath());
  179. props.set(PATH_DATA.getKey(), temp.newFolder().getAbsolutePath());
  180. props.set(PATH_TEMP.getKey(), temp.newFolder().getAbsolutePath());
  181. props.set(PATH_LOGS.getKey(), temp.newFolder().getAbsolutePath());
  182. EsSettings esSettings = new EsSettings(props, new EsInstallation(props), System2.INSTANCE);
  183. Map<String, String> generated = esSettings.build();
  184. assertThat(generated.get("node.name")).isEqualTo("sonarqube");
  185. }
  186. @Test
  187. public void path_properties_are_values_from_EsFileSystem_argument() throws IOException {
  188. File foo = temp.newFolder();
  189. EsInstallation mockedEsInstallation = mock(EsInstallation.class);
  190. File home = new File(foo, "home");
  191. when(mockedEsInstallation.getHomeDirectory()).thenReturn(home);
  192. File conf = new File(foo, "conf");
  193. when(mockedEsInstallation.getConfDirectory()).thenReturn(conf);
  194. File log = new File(foo, "log");
  195. when(mockedEsInstallation.getLogDirectory()).thenReturn(log);
  196. File data = new File(foo, "data");
  197. when(mockedEsInstallation.getDataDirectory()).thenReturn(data);
  198. EsSettings underTest = new EsSettings(minProps(new Random().nextBoolean()), mockedEsInstallation, System2.INSTANCE);
  199. Map<String, String> generated = underTest.build();
  200. assertThat(generated.get("path.data")).isEqualTo(data.getPath());
  201. assertThat(generated.get("path.logs")).isEqualTo(log.getPath());
  202. assertThat(generated.get("path.conf")).isNull();
  203. }
  204. @Test
  205. public void set_discovery_settings_if_cluster_is_enabled() throws Exception {
  206. Props props = minProps(CLUSTER_ENABLED);
  207. props.set(CLUSTER_SEARCH_HOSTS.getKey(), "1.2.3.4:9000,1.2.3.5:8080");
  208. Map<String, String> settings = new EsSettings(props, new EsInstallation(props), System2.INSTANCE).build();
  209. assertThat(settings.get("discovery.zen.ping.unicast.hosts")).isEqualTo("1.2.3.4:9000,1.2.3.5:8080");
  210. assertThat(settings.get("discovery.zen.minimum_master_nodes")).isEqualTo("2");
  211. assertThat(settings.get("discovery.initial_state_timeout")).isEqualTo("120s");
  212. }
  213. @Test
  214. public void incorrect_values_of_minimum_master_nodes() throws Exception {
  215. Props props = minProps(CLUSTER_ENABLED);
  216. props.set(SEARCH_MINIMUM_MASTER_NODES.getKey(), "ꝱꝲꝳପ");
  217. EsSettings underTest = new EsSettings(props, new EsInstallation(props), System2.INSTANCE);
  218. expectedException.expect(IllegalStateException.class);
  219. expectedException.expectMessage("Value of property sonar.search.minimumMasterNodes is not an integer:");
  220. underTest.build();
  221. }
  222. @Test
  223. public void cluster_is_enabled_with_defined_minimum_master_nodes() throws Exception {
  224. Props props = minProps(CLUSTER_ENABLED);
  225. props.set(SEARCH_MINIMUM_MASTER_NODES.getKey(), "5");
  226. Map<String, String> settings = new EsSettings(props, new EsInstallation(props), System2.INSTANCE).build();
  227. assertThat(settings.get("discovery.zen.minimum_master_nodes")).isEqualTo("5");
  228. }
  229. @Test
  230. public void cluster_is_enabled_with_defined_initialTimeout() throws Exception {
  231. Props props = minProps(CLUSTER_ENABLED);
  232. props.set(SEARCH_INITIAL_STATE_TIMEOUT.getKey(), "10s");
  233. Map<String, String> settings = new EsSettings(props, new EsInstallation(props), System2.INSTANCE).build();
  234. assertThat(settings.get("discovery.initial_state_timeout")).isEqualTo("10s");
  235. }
  236. @Test
  237. public void in_standalone_initialTimeout_is_not_overridable() throws Exception {
  238. Props props = minProps(CLUSTER_DISABLED);
  239. props.set(SEARCH_INITIAL_STATE_TIMEOUT.getKey(), "10s");
  240. Map<String, String> settings = new EsSettings(props, new EsInstallation(props), System2.INSTANCE).build();
  241. assertThat(settings.get("discovery.initial_state_timeout")).isEqualTo("30s");
  242. }
  243. @Test
  244. public void in_standalone_minimumMasterNodes_is_not_overridable() throws Exception {
  245. Props props = minProps(CLUSTER_DISABLED);
  246. props.set(SEARCH_MINIMUM_MASTER_NODES.getKey(), "5");
  247. Map<String, String> settings = new EsSettings(props, new EsInstallation(props), System2.INSTANCE).build();
  248. assertThat(settings.get("discovery.zen.minimum_master_nodes")).isEqualTo("1");
  249. }
  250. @Test
  251. public void enable_http_connector() throws Exception {
  252. Props props = minProps(CLUSTER_DISABLED);
  253. props.set(SEARCH_HTTP_PORT.getKey(), "9010");
  254. Map<String, String> settings = new EsSettings(props, new EsInstallation(props), System2.INSTANCE).build();
  255. assertThat(settings.get("http.port")).isEqualTo("9010");
  256. assertThat(settings.get("http.host")).isEqualTo("127.0.0.1");
  257. assertThat(settings.get("http.enabled")).isEqualTo("true");
  258. }
  259. @Test
  260. public void enable_http_connector_different_host() throws Exception {
  261. Props props = minProps(CLUSTER_DISABLED);
  262. props.set(SEARCH_HTTP_PORT.getKey(), "9010");
  263. props.set(SEARCH_HOST.getKey(), "127.0.0.2");
  264. Map<String, String> settings = new EsSettings(props, new EsInstallation(props), System2.INSTANCE).build();
  265. assertThat(settings.get("http.port")).isEqualTo("9010");
  266. assertThat(settings.get("http.host")).isEqualTo("127.0.0.2");
  267. assertThat(settings.get("http.enabled")).isEqualTo("true");
  268. }
  269. @Test
  270. public void enable_seccomp_filter_by_default() throws Exception {
  271. Props props = minProps(CLUSTER_DISABLED);
  272. Map<String, String> settings = new EsSettings(props, new EsInstallation(props), System2.INSTANCE).build();
  273. assertThat(settings.get("bootstrap.system_call_filter")).isNull();
  274. }
  275. @Test
  276. public void disable_seccomp_filter_if_configured_in_search_additional_props() throws Exception {
  277. Props props = minProps(CLUSTER_DISABLED);
  278. props.set("sonar.search.javaAdditionalOpts", "-Xmx1G -Dbootstrap.system_call_filter=false -Dfoo=bar");
  279. Map<String, String> settings = new EsSettings(props, new EsInstallation(props), System2.INSTANCE).build();
  280. assertThat(settings.get("bootstrap.system_call_filter")).isEqualTo("false");
  281. }
  282. @Test
  283. public void disable_mmap_if_configured_in_search_additional_props() throws Exception {
  284. Props props = minProps(CLUSTER_DISABLED);
  285. props.set("sonar.search.javaAdditionalOpts", "-Dnode.store.allow_mmapfs=false");
  286. Map<String, String> settings = new EsSettings(props, new EsInstallation(props), System2.INSTANCE).build();
  287. assertThat(settings.get("node.store.allow_mmapfs")).isEqualTo("false");
  288. }
  289. private Props minProps(boolean cluster) throws IOException {
  290. File homeDir = temp.newFolder();
  291. Props props = new Props(new Properties());
  292. ServiceLoaderWrapper serviceLoaderWrapper = mock(ServiceLoaderWrapper.class);
  293. when(serviceLoaderWrapper.load()).thenReturn(ImmutableSet.of());
  294. new ProcessProperties(serviceLoaderWrapper).completeDefaults(props);
  295. props.set(PATH_HOME.getKey(), homeDir.getAbsolutePath());
  296. props.set(Property.CLUSTER_ENABLED.getKey(), Boolean.toString(cluster));
  297. return props;
  298. }
  299. }