|
@@ -10,6 +10,7 @@
|
|
|
package org.elasticsearch.reservedstate.service;
|
|
|
|
|
|
import org.apache.logging.log4j.Logger;
|
|
|
+import org.apache.lucene.tests.util.LuceneTestCase;
|
|
|
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
|
|
|
import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest;
|
|
|
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
|
|
@@ -20,6 +21,7 @@ import org.elasticsearch.cluster.metadata.ReservedStateErrorMetadata;
|
|
|
import org.elasticsearch.cluster.metadata.ReservedStateHandlerMetadata;
|
|
|
import org.elasticsearch.cluster.metadata.ReservedStateMetadata;
|
|
|
import org.elasticsearch.cluster.service.ClusterService;
|
|
|
+import org.elasticsearch.common.Randomness;
|
|
|
import org.elasticsearch.common.settings.Settings;
|
|
|
import org.elasticsearch.core.Strings;
|
|
|
import org.elasticsearch.core.Tuple;
|
|
@@ -27,7 +29,7 @@ import org.elasticsearch.reservedstate.action.ReservedClusterSettingsAction;
|
|
|
import org.elasticsearch.test.ESIntegTestCase;
|
|
|
import org.junit.Before;
|
|
|
|
|
|
-import java.nio.charset.StandardCharsets;
|
|
|
+import java.io.IOException;
|
|
|
import java.nio.file.Files;
|
|
|
import java.nio.file.Path;
|
|
|
import java.nio.file.StandardCopyOption;
|
|
@@ -50,6 +52,7 @@ import static org.hamcrest.Matchers.notNullValue;
|
|
|
import static org.hamcrest.Matchers.nullValue;
|
|
|
|
|
|
@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, autoManageMasterNodes = false)
|
|
|
+@LuceneTestCase.SuppressFileSystems("*")
|
|
|
public class FileSettingsServiceIT extends ESIntegTestCase {
|
|
|
|
|
|
private final AtomicLong versionCounter = new AtomicLong(1);
|
|
@@ -129,29 +132,37 @@ public class FileSettingsServiceIT extends ESIntegTestCase {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- public static void writeJSONFile(String node, String json, AtomicLong versionCounter, Logger logger, boolean incrementVersion)
|
|
|
- throws Exception {
|
|
|
- long version = incrementVersion ? versionCounter.incrementAndGet() : versionCounter.get();
|
|
|
-
|
|
|
+ public static void writeJSONFile(String node, String json, Logger logger, Long version) throws Exception {
|
|
|
FileSettingsService fileSettingsService = internalCluster().getInstance(FileSettingsService.class, node);
|
|
|
|
|
|
Files.createDirectories(fileSettingsService.watchedFileDir());
|
|
|
Path tempFilePath = createTempFile();
|
|
|
|
|
|
- String settingsFileContent = Strings.format(json, version);
|
|
|
- Files.write(tempFilePath, settingsFileContent.getBytes(StandardCharsets.UTF_8));
|
|
|
- logger.info("--> Before writing new settings file with version [{}]", version);
|
|
|
- Files.move(tempFilePath, fileSettingsService.watchedFile(), StandardCopyOption.ATOMIC_MOVE);
|
|
|
- logger.info("--> After writing new settings file: [{}]", settingsFileContent);
|
|
|
- }
|
|
|
-
|
|
|
- public static void writeJSONFile(String node, String json, AtomicLong versionCounter, Logger logger) throws Exception {
|
|
|
- writeJSONFile(node, json, versionCounter, logger, true);
|
|
|
+ String jsonWithVersion = Strings.format(json, version);
|
|
|
+ logger.info("--> before writing JSON config to node {} with path {}", node, tempFilePath);
|
|
|
+ logger.info(jsonWithVersion);
|
|
|
+
|
|
|
+ Files.writeString(tempFilePath, jsonWithVersion);
|
|
|
+ int retryCount = 0;
|
|
|
+ do {
|
|
|
+ try {
|
|
|
+ // this can fail on Windows because of timing
|
|
|
+ Files.move(tempFilePath, fileSettingsService.watchedFile(), StandardCopyOption.ATOMIC_MOVE);
|
|
|
+ logger.info("--> after writing JSON config to node {} with path {}", node, tempFilePath);
|
|
|
+ return;
|
|
|
+ } catch (IOException e) {
|
|
|
+ logger.info("--> retrying writing a settings file [{}]", retryCount);
|
|
|
+ if (retryCount == 4) { // retry 5 times
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
+ Thread.sleep(retryDelay(retryCount));
|
|
|
+ retryCount++;
|
|
|
+ }
|
|
|
+ } while (true);
|
|
|
}
|
|
|
|
|
|
- public static void writeJSONFileWithoutVersionIncrement(String node, String json, AtomicLong versionCounter, Logger logger)
|
|
|
- throws Exception {
|
|
|
- writeJSONFile(node, json, versionCounter, logger, false);
|
|
|
+ private static long retryDelay(int retryCount) {
|
|
|
+ return 100 * (1 << retryCount) + Randomness.get().nextInt(10);
|
|
|
}
|
|
|
|
|
|
private Tuple<CountDownLatch, AtomicLong> setupCleanupClusterStateListener(String node) {
|
|
@@ -245,7 +256,7 @@ public class FileSettingsServiceIT extends ESIntegTestCase {
|
|
|
assertTrue(masterFileSettingsService.watching());
|
|
|
assertFalse(dataFileSettingsService.watching());
|
|
|
|
|
|
- writeJSONFile(masterNode, testJSON, versionCounter, logger);
|
|
|
+ writeJSONFile(masterNode, testJSON, logger, versionCounter.incrementAndGet());
|
|
|
assertClusterStateSaveOK(savedClusterState.v1(), savedClusterState.v2(), "50mb");
|
|
|
}
|
|
|
|
|
@@ -260,7 +271,7 @@ public class FileSettingsServiceIT extends ESIntegTestCase {
|
|
|
|
|
|
// In internal cluster tests, the nodes share the config directory, so when we write with the data node path
|
|
|
// the master will pick it up on start
|
|
|
- writeJSONFile(dataNode, testJSON, versionCounter, logger);
|
|
|
+ writeJSONFile(dataNode, testJSON, logger, versionCounter.incrementAndGet());
|
|
|
|
|
|
logger.info("--> start master node");
|
|
|
final String masterNode = internalCluster().startMasterOnlyNode();
|
|
@@ -288,7 +299,7 @@ public class FileSettingsServiceIT extends ESIntegTestCase {
|
|
|
assertBusy(() -> assertTrue(masterFileSettingsService.watching()));
|
|
|
|
|
|
logger.info("--> write some settings");
|
|
|
- writeJSONFile(masterNode, testJSON, versionCounter, logger);
|
|
|
+ writeJSONFile(masterNode, testJSON, logger, versionCounter.incrementAndGet());
|
|
|
assertClusterStateSaveOK(savedClusterState.v1(), savedClusterState.v2(), "50mb");
|
|
|
|
|
|
logger.info("--> restart master");
|
|
@@ -366,7 +377,7 @@ public class FileSettingsServiceIT extends ESIntegTestCase {
|
|
|
assertTrue(masterFileSettingsService.watching());
|
|
|
assertFalse(dataFileSettingsService.watching());
|
|
|
|
|
|
- writeJSONFile(masterNode, testErrorJSON, versionCounter, logger);
|
|
|
+ writeJSONFile(masterNode, testErrorJSON, logger, versionCounter.incrementAndGet());
|
|
|
assertClusterStateNotSaved(savedClusterState.v1(), savedClusterState.v2());
|
|
|
}
|
|
|
|
|
@@ -390,14 +401,14 @@ public class FileSettingsServiceIT extends ESIntegTestCase {
|
|
|
assertTrue(masterFileSettingsService.watching());
|
|
|
assertFalse(dataFileSettingsService.watching());
|
|
|
|
|
|
- writeJSONFile(masterNode, testErrorJSON, versionCounter, logger);
|
|
|
+ writeJSONFile(masterNode, testErrorJSON, logger, versionCounter.incrementAndGet());
|
|
|
AtomicLong metadataVersion = savedClusterState.v2();
|
|
|
assertClusterStateNotSaved(savedClusterState.v1(), metadataVersion);
|
|
|
assertHasErrors(metadataVersion, "not_cluster_settings");
|
|
|
|
|
|
// write valid json without version increment to simulate ES being able to process settings after a restart (usually, this would be
|
|
|
// due to a code change)
|
|
|
- writeJSONFileWithoutVersionIncrement(masterNode, testJSON, versionCounter, logger);
|
|
|
+ writeJSONFile(masterNode, testJSON, logger, versionCounter.get());
|
|
|
internalCluster().restartNode(masterNode);
|
|
|
ensureGreen();
|
|
|
|
|
@@ -426,14 +437,14 @@ public class FileSettingsServiceIT extends ESIntegTestCase {
|
|
|
assertTrue(masterFileSettingsService.watching());
|
|
|
assertFalse(dataFileSettingsService.watching());
|
|
|
|
|
|
- writeJSONFile(masterNode, testErrorJSON, versionCounter, logger);
|
|
|
+ writeJSONFile(masterNode, testErrorJSON, logger, versionCounter.incrementAndGet());
|
|
|
AtomicLong metadataVersion = savedClusterState.v2();
|
|
|
assertClusterStateNotSaved(savedClusterState.v1(), metadataVersion);
|
|
|
assertHasErrors(metadataVersion, "not_cluster_settings");
|
|
|
|
|
|
// write json with new error without version increment to simulate ES failing to process settings after a restart for a new reason
|
|
|
// (usually, this would be due to a code change)
|
|
|
- writeJSONFileWithoutVersionIncrement(masterNode, testOtherErrorJSON, versionCounter, logger);
|
|
|
+ writeJSONFile(masterNode, testOtherErrorJSON, logger, versionCounter.get());
|
|
|
assertHasErrors(metadataVersion, "not_cluster_settings");
|
|
|
internalCluster().restartNode(masterNode);
|
|
|
ensureGreen();
|
|
@@ -461,7 +472,7 @@ public class FileSettingsServiceIT extends ESIntegTestCase {
|
|
|
|
|
|
assertTrue(masterFileSettingsService.watching());
|
|
|
|
|
|
- writeJSONFile(masterNode, testJSON, versionCounter, logger);
|
|
|
+ writeJSONFile(masterNode, testJSON, logger, versionCounter.incrementAndGet());
|
|
|
assertClusterStateSaveOK(savedClusterState.v1(), savedClusterState.v2(), "50mb");
|
|
|
|
|
|
internalCluster().stopCurrentMasterNode();
|
|
@@ -476,13 +487,13 @@ public class FileSettingsServiceIT extends ESIntegTestCase {
|
|
|
ensureStableCluster(3);
|
|
|
|
|
|
savedClusterState = setupCleanupClusterStateListener(internalCluster().getMasterName());
|
|
|
- writeJSONFile(internalCluster().getMasterName(), testCleanupJSON, versionCounter, logger);
|
|
|
+ writeJSONFile(internalCluster().getMasterName(), testCleanupJSON, logger, versionCounter.incrementAndGet());
|
|
|
|
|
|
boolean awaitSuccessful = savedClusterState.v1().await(20, TimeUnit.SECONDS);
|
|
|
assertTrue(awaitSuccessful);
|
|
|
|
|
|
savedClusterState = setupClusterStateListener(internalCluster().getMasterName());
|
|
|
- writeJSONFile(internalCluster().getMasterName(), testJSON43mb, versionCounter, logger);
|
|
|
+ writeJSONFile(internalCluster().getMasterName(), testJSON43mb, logger, versionCounter.incrementAndGet());
|
|
|
|
|
|
assertClusterStateSaveOK(savedClusterState.v1(), savedClusterState.v2(), "43mb");
|
|
|
}
|