package org.sonar.application.es;
import java.io.File;
-import org.apache.commons.lang.StringUtils;
+import java.util.Collections;
+import java.util.List;
import org.sonar.process.ProcessProperties;
import org.sonar.process.Props;
*/
public class EsFileSystem {
private final File homeDirectory;
+ private final List<File> outdatedDataDirectories;
private final File dataDirectory;
private final File confDirectory;
private final File logDirectory;
File sqHomeDir = props.nonNullValueAsFile(ProcessProperties.PATH_HOME);
this.homeDirectory = new File(sqHomeDir, "elasticsearch");
- this.dataDirectory = buildDataDir(props, sqHomeDir);
+ this.outdatedDataDirectories = buildOutdatedDataDirs(props);
+ this.dataDirectory = buildDataDir(props);
this.confDirectory = buildConfDir(props);
this.logDirectory = buildLogPath(props);
}
- private static File buildDataDir(Props props, File sqHomeDir) {
- String dataPath = props.value(ProcessProperties.PATH_DATA);
- if (StringUtils.isNotEmpty(dataPath)) {
- return new File(dataPath, "es");
- }
- return new File(sqHomeDir, "data/es");
+ private static List<File> buildOutdatedDataDirs(Props props) {
+ String dataPath = props.nonNullValue(ProcessProperties.PATH_DATA);
+ return Collections.singletonList(new File(dataPath, "es"));
+ }
+
+ private static File buildDataDir(Props props) {
+ String dataPath = props.nonNullValue(ProcessProperties.PATH_DATA);
+ return new File(dataPath, "es5");
}
private static File buildLogPath(Props props) {
return homeDirectory;
}
+ public List<File> getOutdatedDataDirectories() {
+ return Collections.unmodifiableList(outdatedDataDirectories);
+ }
+
public File getDataDirectory() {
return dataDirectory;
}
import java.util.Map;
import java.util.Properties;
import java.util.function.Supplier;
+import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.application.command.AbstractCommand;
public ProcessMonitor launch(EsCommand esCommand) {
Process process = null;
try {
+ cleanupOutdatedEsData(esCommand);
writeConfFiles(esCommand);
ProcessBuilder processBuilder = create(esCommand);
logLaunchedCommand(esCommand, processBuilder);
}
}
+ private static void cleanupOutdatedEsData(EsCommand esCommand) {
+ EsFileSystem esFileSystem = esCommand.getFileSystem();
+ esFileSystem.getOutdatedDataDirectories().forEach(outdatedDir -> {
+ if (outdatedDir.exists()) {
+ LOG.info("Deleting outdated search index data directory {}", outdatedDir.getAbsolutePath());
+ try {
+ FileUtils.deleteDirectory(outdatedDir);
+ } catch (IOException e) {
+ LOG.info("Failed to delete outdated search index data directory " + outdatedDir.getAbsolutePath(), e);
+ }
+ }
+ });
+ }
+
private static void writeConfFiles(EsCommand esCommand) {
EsFileSystem esFileSystem = esCommand.getFileSystem();
File confDir = esFileSystem.getConfDirectory();
@Test
public void constructor_fails_with_IAE_if_temp_dir_property_is_not_defined() throws IOException {
Props props = new Props(new Properties());
+ props.set(ProcessProperties.PATH_DATA, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_HOME, temp.newFolder().getAbsolutePath());
expectedException.expect(IllegalArgumentException.class);
}
@Test
- public void getHomeDirectory_is_elasticsearch_subdirectory_of_sq_home_directory() throws IOException {
- File sqHomeDir = temp.newFolder();
+ public void constructor_fails_with_IAE_if_data_dir_property_is_not_defined() throws IOException {
Props props = new Props(new Properties());
- props.set(ProcessProperties.PATH_HOME, sqHomeDir.getAbsolutePath());
- props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath());
- props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
+ props.set(ProcessProperties.PATH_HOME, temp.newFolder().getAbsolutePath());
- EsFileSystem underTest = new EsFileSystem(props);
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Missing property: sonar.path.data");
- assertThat(underTest.getHomeDirectory()).isEqualTo(new File(sqHomeDir, "elasticsearch"));
+ new EsFileSystem(props);
}
@Test
- public void getDataDirectory_is_data_es_subdirectory_of_sq_home_directory_by_default() throws IOException {
+ public void getHomeDirectory_is_elasticsearch_subdirectory_of_sq_home_directory() throws IOException {
File sqHomeDir = temp.newFolder();
Props props = new Props(new Properties());
+ props.set(ProcessProperties.PATH_DATA, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_HOME, sqHomeDir.getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
EsFileSystem underTest = new EsFileSystem(props);
- assertThat(underTest.getDataDirectory()).isEqualTo(new File(sqHomeDir, "data/es"));
+ assertThat(underTest.getHomeDirectory()).isEqualTo(new File(sqHomeDir, "elasticsearch"));
}
@Test
EsFileSystem underTest = new EsFileSystem(props);
- assertThat(underTest.getDataDirectory()).isEqualTo(new File(dataDir, "es"));
+ assertThat(underTest.getDataDirectory()).isEqualTo(new File(dataDir, "es5"));
}
@Test
File sqHomeDir = temp.newFolder();
File logDir = temp.newFolder();
Props props = new Props(new Properties());
+ props.set(ProcessProperties.PATH_DATA, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_HOME, sqHomeDir.getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_LOGS, logDir.getAbsolutePath());
public void conf_directory_is_conf_es_subdirectory_of_sq_temp_directory() throws IOException {
File tempDir = temp.newFolder();
Props props = new Props(new Properties());
+ props.set(ProcessProperties.PATH_DATA, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_HOME, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, tempDir.getAbsolutePath());
props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
public void getExecutable_resolve_executable_for_platform() throws IOException {
File sqHomeDir = temp.newFolder();
Props props = new Props(new Properties());
+ props.set(ProcessProperties.PATH_DATA, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_HOME, sqHomeDir.getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
public void getLog4j2Properties_is_in_es_conf_directory() throws IOException {
File tempDir = temp.newFolder();
Props props = new Props(new Properties());
+ props.set(ProcessProperties.PATH_DATA, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_HOME, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, tempDir.getAbsolutePath());
props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
public void getElasticsearchYml_is_in_es_conf_directory() throws IOException {
File tempDir = temp.newFolder();
Props props = new Props(new Properties());
+ props.set(ProcessProperties.PATH_DATA, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_HOME, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, tempDir.getAbsolutePath());
props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
public void getJvmOptions_is_in_es_conf_directory() throws IOException {
File tempDir = temp.newFolder();
Props props = new Props(new Properties());
+ props.set(ProcessProperties.PATH_DATA, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_HOME, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, tempDir.getAbsolutePath());
props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
private Props minimalProps() {
Props props = new Props(new Properties());
props.set(ProcessProperties.PATH_HOME, randomAlphanumeric(12));
+ props.set(ProcessProperties.PATH_DATA, randomAlphanumeric(12));
props.set(ProcessProperties.PATH_TEMP, randomAlphanumeric(12));
props.set(ProcessProperties.PATH_LOGS, randomAlphanumeric(12));
props.set(CLUSTER_NAME, randomAlphanumeric(12));
props.set(ProcessProperties.SEARCH_PORT, "1234");
props.set(ProcessProperties.SEARCH_HOST, "127.0.0.1");
props.set(ProcessProperties.PATH_HOME, homeDir.getAbsolutePath());
+ props.set(ProcessProperties.PATH_DATA, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
props.set(CLUSTER_NAME, "sonarqube");
props.set(ProcessProperties.SEARCH_PORT, "1234");
props.set(ProcessProperties.SEARCH_HOST, "127.0.0.1");
props.set(ProcessProperties.PATH_HOME, homeDir.getAbsolutePath());
+ props.set(ProcessProperties.PATH_DATA, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.CLUSTER_NAME, "sonarqube-1");
props.set(ProcessProperties.SEARCH_PORT, "1234");
props.set(ProcessProperties.SEARCH_HOST, "127.0.0.1");
props.set(ProcessProperties.PATH_HOME, homeDir.getAbsolutePath());
+ props.set(ProcessProperties.PATH_DATA, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
EsSettings esSettings = new EsSettings(props, new EsFileSystem(props), System2.INSTANCE);
props.set(ProcessProperties.SEARCH_PORT, "1234");
props.set(ProcessProperties.SEARCH_HOST, "127.0.0.1");
props.set(ProcessProperties.PATH_HOME, homeDir.getAbsolutePath());
+ props.set(ProcessProperties.PATH_DATA, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
EsSettings esSettings = new EsSettings(props, new EsFileSystem(props), System2.INSTANCE);
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
-import org.sonar.process.ProcessId;
+import org.sonar.application.command.EsCommand;
+import org.sonar.application.command.EsJvmOptions;
import org.sonar.application.command.JavaCommand;
import org.sonar.application.command.JvmOptions;
+import org.sonar.application.es.EsFileSystem;
+import org.sonar.application.es.EsYmlSettings;
+import org.sonar.process.ProcessId;
+import org.sonar.process.Props;
import org.sonar.process.sharedmemoryfile.AllProcessesCommands;
import static org.assertj.core.api.Assertions.assertThat;
}
}
+ @Test
+ public void clean_up_old_es_data() throws Exception {
+ File tempDir = temp.newFolder();
+ File homeDir = temp.newFolder();
+ File dataDir = temp.newFolder();
+ File logDir = temp.newFolder();
+ ProcessLauncher underTest = new ProcessLauncherImpl(tempDir, commands, () -> new TestProcessBuilder());
+ EsCommand command = createEsCommand(tempDir, homeDir, dataDir, logDir);
+
+ File outdatedEsDir = new File(dataDir, "es");
+ assertThat(outdatedEsDir.mkdir()).isTrue();
+ assertThat(outdatedEsDir.exists()).isTrue();
+
+ underTest.launch(command);
+
+ assertThat(outdatedEsDir.exists()).isFalse();
+ }
+
+ @Test
+ public void do_not_fail_if_outdated_es_directory_does_not_exist() throws Exception {
+ File tempDir = temp.newFolder();
+ File homeDir = temp.newFolder();
+ File dataDir = temp.newFolder();
+ File logDir = temp.newFolder();
+ ProcessLauncher underTest = new ProcessLauncherImpl(tempDir, commands, () -> new TestProcessBuilder());
+ EsCommand command = createEsCommand(tempDir, homeDir, dataDir, logDir);
+
+ File outdatedEsDir = new File(dataDir, "es");
+ assertThat(outdatedEsDir.exists()).isFalse();
+
+ underTest.launch(command);
+
+ assertThat(outdatedEsDir.exists()).isFalse();
+ }
+
@Test
public void throw_ISE_if_command_fails() throws IOException {
File tempDir = temp.newFolder();
underTest.launch(new JavaCommand(ProcessId.ELASTICSEARCH, temp.newFolder()));
}
+ private EsCommand createEsCommand(File tempDir, File homeDir, File dataDir, File logDir) throws IOException {
+ EsCommand command = new EsCommand(ProcessId.ELASTICSEARCH, temp.newFolder());
+ Props props = new Props(new Properties());
+ props.set("sonar.path.temp", tempDir.getAbsolutePath());
+ props.set("sonar.path.home", homeDir.getAbsolutePath());
+ props.set("sonar.path.data", dataDir.getAbsolutePath());
+ props.set("sonar.path.logs", logDir.getAbsolutePath());
+ command.setFileSystem(new EsFileSystem(props));
+ command.setEsYmlSettings(mock(EsYmlSettings.class));
+ command.setEsJvmOptions(mock(EsJvmOptions.class));
+ command.setLog4j2Properties(new Properties());
+ return command;
+ }
+
private static class TestProcessBuilder implements ProcessLauncherImpl.ProcessBuilder {
private List<String> commands = null;
private File dir = null;