|
28 | 28 | import org.elasticsearch.health.node.FetchHealthInfoCacheAction; |
29 | 29 | import org.elasticsearch.reservedstate.action.ReservedClusterSettingsAction; |
30 | 30 | import org.elasticsearch.test.ESIntegTestCase; |
| 31 | +import org.elasticsearch.test.InternalTestCluster; |
31 | 32 | import org.junit.Before; |
32 | 33 |
|
33 | 34 | import java.io.IOException; |
|
40 | 41 | import java.util.concurrent.atomic.AtomicLong; |
41 | 42 | import java.util.stream.Stream; |
42 | 43 |
|
| 44 | +import static org.elasticsearch.cluster.metadata.ReservedStateMetadata.EMPTY_VERSION; |
43 | 45 | import static org.elasticsearch.health.HealthStatus.YELLOW; |
44 | 46 | import static org.elasticsearch.indices.recovery.RecoverySettings.INDICES_RECOVERY_MAX_BYTES_PER_SEC_SETTING; |
45 | 47 | import static org.elasticsearch.node.Node.INITIAL_STATE_TIMEOUT_SETTING; |
@@ -322,6 +324,68 @@ public void testReservedStatePersistsOnRestart() throws Exception { |
322 | 324 | ); |
323 | 325 | } |
324 | 326 |
|
| 327 | + public void testReservedStateClearedWhenFileAbsentAtStartup() throws Exception { |
| 328 | + internalCluster().setBootstrapMasterNodeIndex(0); |
| 329 | + logger.info("--> start master node"); |
| 330 | + final String masterNode = internalCluster().startMasterOnlyNode( |
| 331 | + Settings.builder().put(INITIAL_STATE_TIMEOUT_SETTING.getKey(), "0s").build() |
| 332 | + ); |
| 333 | + awaitMasterNode(internalCluster().getMasterName(), masterNode); |
| 334 | + var savedClusterState = setupClusterStateListener(masterNode, versionCounter.incrementAndGet()); |
| 335 | + |
| 336 | + FileSettingsService masterFileSettingsService = internalCluster().getInstance(FileSettingsService.class, masterNode); |
| 337 | + |
| 338 | + assertBusy(() -> assertTrue(masterFileSettingsService.watching())); |
| 339 | + |
| 340 | + logger.info("--> write some settings"); |
| 341 | + writeJSONFile(masterNode, testJSON, logger, versionCounter.get()); |
| 342 | + assertClusterStateSaveOK(savedClusterState.v1(), savedClusterState.v2(), "50mb"); |
| 343 | + |
| 344 | + logger.info("--> get file path before restarting node"); |
| 345 | + Path watchedFile = masterFileSettingsService.watchedFile(); |
| 346 | + assertTrue("File should exist before deletion", Files.exists(watchedFile)); |
| 347 | + |
| 348 | + logger.info("--> restart master and delete file while node is stopped"); |
| 349 | + internalCluster().restartNode(masterNode, new InternalTestCluster.RestartCallback() { |
| 350 | + @Override |
| 351 | + public Settings onNodeStopped(String nodeName) throws Exception { |
| 352 | + logger.info("--> delete the file settings file while node is stopped"); |
| 353 | + Files.deleteIfExists(watchedFile); |
| 354 | + assertFalse("File should not exist after deletion", Files.exists(watchedFile)); |
| 355 | + return super.onNodeStopped(nodeName); |
| 356 | + } |
| 357 | + }); |
| 358 | + |
| 359 | + logger.info("--> verify reserved state is cleared when missing file is processed at startup"); |
| 360 | + assertBusy(() -> { |
| 361 | + final ClusterStateResponse clusterStateResponse = clusterAdmin().state(new ClusterStateRequest(TEST_REQUEST_TIMEOUT)) |
| 362 | + .actionGet(); |
| 363 | + ReservedStateMetadata reservedState = clusterStateResponse.getState() |
| 364 | + .metadata() |
| 365 | + .reservedStateMetadata() |
| 366 | + .get(FileSettingsService.NAMESPACE); |
| 367 | + assertThat(reservedState, notNullValue()); |
| 368 | + assertThat(reservedState.version(), equalTo(EMPTY_VERSION)); |
| 369 | + assertTrue(reservedState.handlers().isEmpty()); |
| 370 | + }, 20, TimeUnit.SECONDS); |
| 371 | + |
| 372 | + logger.info("--> verify settings are no longer reserved and can be modified"); |
| 373 | + ClusterUpdateSettingsRequest req = new ClusterUpdateSettingsRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT).persistentSettings( |
| 374 | + Settings.builder().put(INDICES_RECOVERY_MAX_BYTES_PER_SEC_SETTING.getKey(), "1234kb") |
| 375 | + ); |
| 376 | + clusterAdmin().updateSettings(req).get(); |
| 377 | + |
| 378 | + assertThat( |
| 379 | + clusterAdmin().state(new ClusterStateRequest(TEST_REQUEST_TIMEOUT)) |
| 380 | + .actionGet() |
| 381 | + .getState() |
| 382 | + .metadata() |
| 383 | + .persistentSettings() |
| 384 | + .get(INDICES_RECOVERY_MAX_BYTES_PER_SEC_SETTING.getKey()), |
| 385 | + equalTo("1234kb") |
| 386 | + ); |
| 387 | + } |
| 388 | + |
325 | 389 | private Tuple<CountDownLatch, AtomicLong> setupClusterStateListenerForError(String node) { |
326 | 390 | ClusterService clusterService = internalCluster().clusterService(node); |
327 | 391 | CountDownLatch savedClusterState = new CountDownLatch(1); |
|
0 commit comments