Synchronize opensearch config to a user-defined directory (#15307)

* Synchronize opensearch config to a user-defined directory (fixes #15223)

* fixed check naming

* fixed opensearch configuration location

* simplified Environment constructor

* point gc logs of datanodes opensearch to /tmp for now

* full dir sync for opensearch config

* Fixed full dir sync when removing non-empty dir

* simpified recursive directory deletion
This commit is contained in:
Tomas Dvorak
2023-05-02 15:01:12 +02:00
committed by GitHub
parent 9ab315ea49
commit 2fa7b7b9aa
41 changed files with 2546 additions and 67 deletions

View File

@@ -17,6 +17,7 @@
package org.graylog.datanode.bootstrap;
import org.assertj.core.api.Assertions;
import org.graylog.datanode.bootstrap.preflight.OpensearchBinPreflightCheck;
import org.graylog2.bootstrap.preflight.PreflightCheckException;
import org.graylog2.shared.utilities.StringUtils;
import org.junit.jupiter.api.Test;
@@ -28,9 +29,7 @@ import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.*;
class OpensearchBinPreflightCheckTest {
public class OpensearchBinPreflightCheckTest {
@TempDir
private Path tempDir;

View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2020 Graylog, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
package org.graylog.datanode.bootstrap.preflight;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
class FullDirSyncTest {
@TempDir
private Path source;
@TempDir
private Path target;
@BeforeEach
void setUp() throws IOException {
/*
source:
-a.txt
-b.txt
-subdir
-c.txt
target:
-a.txt
-x.txt
-empty-dir
-subdir
-y.txt
-unused-dir
-z.txt
*/
Files.createFile(source.resolve("a.txt"));
Files.createFile(source.resolve("b.txt"));
Files.createDirectories(source.resolve("subdir"));
Files.createFile(source.resolve("subdir").resolve("c.txt"));
Files.createFile(target.resolve("a.txt"));
Files.createFile(target.resolve("x.txt"));
Files.createDirectories(target.resolve("subdir"));
Files.createDirectories(target.resolve("empty-dir"));
Files.createFile(target.resolve("subdir").resolve("y.txt"));
Files.createDirectories(target.resolve("unused-dir"));
Files.createFile(target.resolve("unused-dir").resolve("z.txt"));
}
@Test
void run() throws IOException {
FullDirSync.run(source, target);
List<Path> afterSyncState = new ArrayList<>();
Files.walkFileTree(target, new SimpleFileVisitor<>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
if(!target.equals(dir)) {
afterSyncState.add(dir);
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
afterSyncState.add(file);
return super.visitFile(file, attrs);
}
});
Assertions.assertThat(afterSyncState)
.extracting(target::relativize)
.extracting(Path::toString)
.hasSize(4)
.contains("a.txt", "b.txt", "subdir", "subdir/c.txt");
}
}

View File

@@ -21,16 +21,13 @@ import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.ExecuteException;
import org.assertj.core.api.Assertions;
import org.graylog.datanode.ProcessProvidingExecutor;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
@@ -62,7 +59,7 @@ class CommandLineProcessTest {
}
@Test
void testManualStop() throws IOException, ExecutionException, RetryException, URISyntaxException {
void testManualStop() throws IOException, ExecutionException, RetryException {
List<String> stdout = new LinkedList<>();
List<String> stdErr = new LinkedList<>();
@@ -93,13 +90,11 @@ class CommandLineProcessTest {
LOG.info("On process failed:", e);
}
};
final TestExecutor testExecutor = new TestExecutor();
final CommandLineProcess process = new CommandLineProcess(
binPath,
Collections.emptyList(),
listener,
() -> testExecutor,
() -> Map.of("USER", "test", "JAVA_HOME", "/path/to/jre")
new Environment(Map.of("USER", "test", "JAVA_HOME", "/path/to/jre"))
);
process.start();
@@ -117,8 +112,6 @@ class CommandLineProcessTest {
.hasSize(1)
.contains("This message goes to stderr");
Assertions.assertThat(testExecutor.getEnvironment())
.doesNotContainKey("JAVA_HOME");
}
private void waitTillLogsAreAvailable(List<String> logs, int expectedLinesCount) throws ExecutionException, RetryException {
@@ -161,28 +154,11 @@ class CommandLineProcessTest {
exitCodeFuture.complete(e.getExitValue());
}
};
final CommandLineProcess process = new CommandLineProcess(binPath, List.of("143"), listener);
final CommandLineProcess process = new CommandLineProcess(binPath, List.of("143"), listener, new Environment(System.getenv()));
process.start();
final Integer exitCode = exitCodeFuture.get(10, TimeUnit.SECONDS);
Assertions.assertThat(exitCode).isEqualTo(143);
}
/**
* Implementation that allows access to the environment argument.
*/
private static class TestExecutor extends ProcessProvidingExecutor {
private Map<String, String> environment = Map.of();
@Override
protected Process launch(CommandLine command, Map<String, String> env, File dir) throws IOException {
this.environment = env;
return super.launch(command, env, dir);
}
public Map<String, String> getEnvironment() {
return environment;
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2020 Graylog, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
package org.graylog.datanode.management;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
class EnvironmentTest {
@Test
void testFiltering() {
final Environment env = new Environment(Map.of("USER", "test", "JAVA_HOME", "/path/to/jre"));
Assertions.assertThat(env.getEnv())
.doesNotContainKey("JAVA_HOME");
}
}

View File

@@ -78,12 +78,6 @@ public class DatanodeContainerizedBackend {
.withEnv("GRAYLOG_DATANODE_OPENSEARCH_NETWORK_HOST", nodeName)
//datanode_transport_certificate=datanode-transport-certificates.p12
//datanode_transport_certificate_password=password
//datanode_http_certificate=datanode-http-certificates.p12
//datanode_http_certificate_password=password
.withEnv("GRAYLOG_DATANODE_REST_API_USERNAME", "admin")
.withEnv("GRAYLOG_DATANODE_REST_API_PASSWORD", "admin")
.withEnv("GRAYLOG_DATANODE_PASSWORD_SECRET", "this_is_not_used_but_required")