4747import org .opensearch .cluster .metadata .Metadata ;
4848import org .opensearch .cluster .node .DiscoveryNode ;
4949import org .opensearch .cluster .node .DiscoveryNodes ;
50+ import org .opensearch .cluster .routing .RoutingTable ;
5051import org .opensearch .cluster .routing .allocation .AllocationService ;
5152import org .opensearch .cluster .service .ClusterManagerTaskKeys ;
5253import org .opensearch .cluster .service .ClusterManagerTaskThrottler ;
6667
6768import java .io .IOException ;
6869import java .util .Collection ;
70+ import java .util .Collections ;
71+ import java .util .List ;
72+ import java .util .Map ;
6973import java .util .Set ;
7074import java .util .stream .Collectors ;
7175
72- import static org .opensearch .index .remote .RemoteMigrationIndexMetadataUpdater .indexHasAllRemoteStoreRelatedMetadata ;
76+ import static org .opensearch .index .remote .RemoteMigrationIndexMetadataUpdater .indexHasRemoteStoreSettings ;
7377
7478/**
7579 * Transport action for updating cluster settings
@@ -270,6 +274,13 @@ public ClusterState execute(final ClusterState currentState) {
270274 logger
271275 );
272276 changed = clusterState != currentState ;
277+ // Remote Store migration: Checks if the applied cluster settings
278+ // has switched the cluster to STRICT mode. If so, checks and applies
279+ // appropriate index settings depending on the current set of node types
280+ // in the cluster
281+ if (isSwitchToStrictCompatibilityMode (clusterState .metadata ().settings ())) {
282+ return finalizeMigration (clusterState );
283+ }
273284 return clusterState ;
274285 }
275286 }
@@ -284,11 +295,9 @@ public ClusterState execute(final ClusterState currentState) {
284295 public void validateCompatibilityModeSettingRequest (ClusterUpdateSettingsRequest request , ClusterState clusterState ) {
285296 Settings settings = Settings .builder ().put (request .persistentSettings ()).put (request .transientSettings ()).build ();
286297 if (RemoteStoreNodeService .REMOTE_STORE_COMPATIBILITY_MODE_SETTING .exists (settings )) {
287- String value = RemoteStoreNodeService .REMOTE_STORE_COMPATIBILITY_MODE_SETTING .get (settings ).mode ;
288298 validateAllNodesOfSameVersion (clusterState .nodes ());
289- if (RemoteStoreNodeService . CompatibilityMode . STRICT . mode . equals ( value )) {
299+ if (isSwitchToStrictCompatibilityMode ( settings )) {
290300 validateAllNodesOfSameType (clusterState .nodes ());
291- validateIndexSettings (clusterState );
292301 }
293302 }
294303 }
@@ -323,18 +332,83 @@ private void validateAllNodesOfSameType(DiscoveryNodes discoveryNodes) {
323332 }
324333
325334 /**
326- * Verifies that while trying to switch to STRICT compatibility mode,
327- * all indices in the cluster have {@link RemoteMigrationIndexMetadataUpdater#indexHasAllRemoteStoreRelatedMetadata(IndexMetadata)} as <code>true</code>.
328- * If not, throws {@link SettingsException}
329- * @param clusterState current cluster state
335+ * Finalizes the docrep to remote-store migration process by applying remote store based index settings
336+ * on indices that are missing them. No-Op if all indices already have the settings applied through
337+ * IndexMetadataUpdater
338+ *
339+ * @param incomingState mutated cluster state after cluster settings were applied
340+ * @return new cluster state with index settings updated
341+ */
342+ public ClusterState finalizeMigration (ClusterState incomingState ) {
343+ Map <String , DiscoveryNode > discoveryNodeMap = incomingState .nodes ().getNodes ();
344+ if (discoveryNodeMap .isEmpty () == false ) {
345+ boolean allNodesRemote = discoveryNodeMap .values ().stream ().allMatch (discoNode -> discoNode .isRemoteStoreNode () == true );
346+ if (allNodesRemote == true ) {
347+ List <IndexMetadata > indicesWithoutRemoteStoreSettings = getIndicesWithoutRemoteStoreSettings (incomingState );
348+ if (indicesWithoutRemoteStoreSettings .isEmpty () == true ) {
349+ logger .info ("All indices in the cluster has remote store based index settings" );
350+ } else {
351+ Metadata mutatedMetadata = applyRemoteStoreSettings (incomingState , indicesWithoutRemoteStoreSettings );
352+ return ClusterState .builder (incomingState ).metadata (mutatedMetadata ).build ();
353+ }
354+ } else {
355+ // TODO: Revert all remote store settings for remote store -> docrep migration
356+ logger .debug ("All nodes in the cluster are not remote nodes. Skipping." );
357+ }
358+ }
359+ return incomingState ;
360+ }
361+
362+ /**
363+ * Filters out indices which does not have remote store based
364+ * index settings applied even after all shard copies have
365+ * migrated to remote store enabled nodes
330366 */
331- private void validateIndexSettings (ClusterState clusterState ) {
367+ private List < IndexMetadata > getIndicesWithoutRemoteStoreSettings (ClusterState clusterState ) {
332368 Collection <IndexMetadata > allIndicesMetadata = clusterState .metadata ().indices ().values ();
333- if (allIndicesMetadata .isEmpty () == false
334- && allIndicesMetadata .stream ().anyMatch (indexMetadata -> indexHasAllRemoteStoreRelatedMetadata (indexMetadata ) == false )) {
335- throw new SettingsException (
336- "can not switch to STRICT compatibility mode since all indices in the cluster does not have remote store based index settings"
369+ if (allIndicesMetadata .isEmpty () == false ) {
370+ List <IndexMetadata > indicesWithoutRemoteSettings = allIndicesMetadata .stream ()
371+ .filter (idxMd -> indexHasRemoteStoreSettings (idxMd .getSettings ()) == false )
372+ .collect (Collectors .toList ());
373+ logger .debug (
374+ "Attempting to switch to strict mode. Count of indices without remote store settings {}" ,
375+ indicesWithoutRemoteSettings .size ()
376+ );
377+ return indicesWithoutRemoteSettings ;
378+ }
379+ return Collections .emptyList ();
380+ }
381+
382+ /**
383+ * Applies remote store index settings through {@link RemoteMigrationIndexMetadataUpdater}
384+ */
385+ private Metadata applyRemoteStoreSettings (ClusterState clusterState , List <IndexMetadata > indicesWithRemoteStoreSettings ) {
386+ Metadata .Builder metadataBuilder = Metadata .builder (clusterState .getMetadata ());
387+ RoutingTable currentRoutingTable = clusterState .getRoutingTable ();
388+ DiscoveryNodes currentDiscoveryNodes = clusterState .getNodes ();
389+ for (IndexMetadata indexMetadata : indicesWithRemoteStoreSettings ) {
390+ IndexMetadata .Builder indexMetadataBuilder = IndexMetadata .builder (indexMetadata );
391+ RemoteMigrationIndexMetadataUpdater indexMetadataUpdater = new RemoteMigrationIndexMetadataUpdater (
392+ currentDiscoveryNodes ,
393+ currentRoutingTable ,
394+ indexMetadata ,
395+ null ,
396+ logger
337397 );
398+ indexMetadataUpdater .maybeAddRemoteIndexSettings (indexMetadataBuilder , indexMetadata .getIndex ().getName ());
399+ metadataBuilder .put (indexMetadataBuilder );
338400 }
401+ return metadataBuilder .build ();
402+ }
403+
404+ /**
405+ * Checks if the incoming cluster settings payload is attempting to switch
406+ * the cluster to `STRICT` compatibility mode
407+ * Visible only for tests
408+ */
409+ public boolean isSwitchToStrictCompatibilityMode (Settings settings ) {
410+ return RemoteStoreNodeService .CompatibilityMode .STRICT .mode .equals (
411+ RemoteStoreNodeService .REMOTE_STORE_COMPATIBILITY_MODE_SETTING .get (settings ).mode
412+ );
339413 }
340414}
0 commit comments