Skip to content

Commit

Permalink
[WIP] Add unit tests to RemoteClusterStateService
Browse files Browse the repository at this point in the history
Signed-off-by: Shivansh Arora <hishiv@amazon.com>
  • Loading branch information
shiv0408 committed Jun 20, 2024
1 parent 9729a92 commit d8f00f8
Show file tree
Hide file tree
Showing 6 changed files with 316 additions and 148 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,6 @@ PublishWithJoinResponse handleIncomingRemotePublishRequest(RemotePublishRequest
)
);
ClusterState clusterState = remoteClusterStateService.getClusterStateUsingDiff(
request.getClusterName(),
manifest,
lastSeen,
transportService.getLocalNode().getId()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand Down Expand Up @@ -563,7 +564,16 @@ public static class Builder {
private List<String> clusterStateCustomUpdated;
private List<String> clusterStateCustomDeleted;

public Builder() {}
public Builder() {
customMetadataUpdated = Collections.emptyList();
customMetadataDeleted = Collections.emptyList();
indicesUpdated = Collections.emptyList();
indicesDeleted = Collections.emptyList();
indicesRoutingUpdated = Collections.emptyList();
indicesRoutingDeleted = Collections.emptyList();
clusterStateCustomUpdated = Collections.emptyList();
clusterStateCustomDeleted = Collections.emptyList();
}

public Builder fromStateUUID(String fromStateUUID) {
this.fromStateUUID = fromStateUUID;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1320,12 +1320,11 @@ public ClusterState getClusterStateForManifest(
}

public ClusterState getClusterStateUsingDiff(
String clusterName,
ClusterMetadataManifest manifest,
ClusterState previousState,
String localNodeId
) throws IOException {
assert manifest.getDiffManifest() != null;
assert manifest.getDiffManifest() != null : "Diff manifest null which is required for downloading cluster state";
ClusterStateDiffManifest diff = manifest.getDiffManifest();
List<UploadedIndexMetadata> updatedIndices = diff.getIndicesUpdated().stream().map(idx -> {
Optional<UploadedIndexMetadata> uploadedIndexMetadataOptional = manifest.getIndices()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@
import org.opensearch.cluster.ClusterModule;
import org.opensearch.cluster.ClusterName;
import org.opensearch.cluster.ClusterState;
import org.opensearch.cluster.ClusterStateTests;
import org.opensearch.cluster.RepositoryCleanupInProgress;
import org.opensearch.cluster.RepositoryCleanupInProgress.Entry;
import org.opensearch.cluster.block.ClusterBlock;
import org.opensearch.cluster.block.ClusterBlocks;
import org.opensearch.cluster.coordination.CoordinationMetadata;
import org.opensearch.cluster.metadata.DiffableStringMap;
import org.opensearch.cluster.metadata.IndexGraveyard;
import org.opensearch.cluster.metadata.IndexMetadata;
import org.opensearch.cluster.metadata.IndexTemplateMetadata;
import org.opensearch.cluster.metadata.Metadata;
import org.opensearch.cluster.metadata.TemplatesMetadata;
import org.opensearch.cluster.node.DiscoveryNode;
import org.opensearch.cluster.node.DiscoveryNodes;
import org.opensearch.cluster.routing.RoutingTable;
import org.opensearch.cluster.routing.remote.InternalRemoteRoutingTableService;
Expand Down Expand Up @@ -82,6 +87,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.Function;
Expand All @@ -96,17 +102,25 @@
import static java.util.stream.Collectors.toList;
import static org.opensearch.common.util.FeatureFlags.REMOTE_PUBLICATION_EXPERIMENTAL;
import static org.opensearch.gateway.remote.ClusterMetadataManifest.CODEC_V1;
import static org.opensearch.gateway.remote.RemoteClusterStateAttributesManager.CLUSTER_BLOCKS;
import static org.opensearch.gateway.remote.RemoteClusterStateTestUtils.CustomMetadata1;
import static org.opensearch.gateway.remote.RemoteClusterStateTestUtils.CustomMetadata2;
import static org.opensearch.gateway.remote.RemoteClusterStateTestUtils.CustomMetadata3;
import static org.opensearch.gateway.remote.RemoteClusterStateUtils.DELIMITER;
import static org.opensearch.gateway.remote.RemoteClusterStateUtils.FORMAT_PARAMS;
import static org.opensearch.gateway.remote.RemoteClusterStateUtils.getFormattedIndexFileName;
import static org.opensearch.gateway.remote.model.RemoteClusterBlocksTests.randomClusterBlocks;
import static org.opensearch.gateway.remote.model.RemoteClusterMetadataManifest.MANIFEST_CURRENT_CODEC_VERSION;
import static org.opensearch.gateway.remote.model.RemoteCoordinationMetadata.COORDINATION_METADATA;
import static org.opensearch.gateway.remote.model.RemoteCoordinationMetadata.COORDINATION_METADATA_FORMAT;
import static org.opensearch.gateway.remote.model.RemoteDiscoveryNodes.DISCOVERY_NODES;
import static org.opensearch.gateway.remote.model.RemoteGlobalMetadata.GLOBAL_METADATA_FORMAT;
import static org.opensearch.gateway.remote.model.RemoteHashesOfConsistentSettings.HASHES_OF_CONSISTENT_SETTINGS;
import static org.opensearch.gateway.remote.model.RemotePersistentSettingsMetadata.SETTINGS_METADATA_FORMAT;
import static org.opensearch.gateway.remote.model.RemotePersistentSettingsMetadata.SETTING_METADATA;
import static org.opensearch.gateway.remote.model.RemoteTemplatesMetadata.TEMPLATES_METADATA;
import static org.opensearch.gateway.remote.model.RemoteTemplatesMetadata.TEMPLATES_METADATA_FORMAT;
import static org.opensearch.gateway.remote.model.RemoteTransientSettingsMetadata.TRANSIENT_SETTING_METADATA;
import static org.opensearch.node.remotestore.RemoteStoreNodeAttribute.REMOTE_STORE_CLUSTER_STATE_REPOSITORY_NAME_ATTRIBUTE_KEY;
import static org.opensearch.node.remotestore.RemoteStoreNodeAttribute.REMOTE_STORE_REPOSITORY_SETTINGS_ATTRIBUTE_KEY_PREFIX;
import static org.opensearch.node.remotestore.RemoteStoreNodeAttribute.REMOTE_STORE_REPOSITORY_TYPE_ATTRIBUTE_KEY_FORMAT;
Expand Down Expand Up @@ -545,6 +559,159 @@ public void testWriteIncrementalMetadataSuccess() throws IOException {
assertThat(manifest.getStateUUID(), is(expectedManifest.getStateUUID()));
}

public void testGetClusterStateUsingDiffFailWhenDiffManifestAbsent() {
ClusterMetadataManifest manifest = ClusterMetadataManifest.builder().build();
ClusterState previousState = ClusterState.EMPTY_STATE;
AssertionError error = assertThrows(
AssertionError.class,
() -> remoteClusterStateService.getClusterStateUsingDiff(manifest, previousState, "test-node")
);
assertEquals("Diff manifest null which is required for downloading cluster state", error.getMessage());
}

public void testGetClusterStateUsingDiff_NoDiff() throws IOException {
ClusterStateDiffManifest diffManifest = ClusterStateDiffManifest.builder().build();
ClusterState clusterState = generateClusterStateWithOneIndex().nodes(nodesWithLocalNodeClusterManager()).build();
ClusterMetadataManifest manifest = ClusterMetadataManifest.builder()
.diffManifest(diffManifest)
.stateUUID(clusterState.stateUUID())
.stateVersion(clusterState.version())
.metadataVersion(clusterState.metadata().version())
.clusterUUID(clusterState.getMetadata().clusterUUID())
.routingTableVersion(clusterState.routingTable().version())
.build();
ClusterState updatedClusterState = remoteClusterStateService.getClusterStateUsingDiff(manifest, clusterState, "test-node");
assertEquals(clusterState.getClusterName(), updatedClusterState.getClusterName());
assertEquals(clusterState.metadata().clusterUUID(), updatedClusterState.metadata().clusterUUID());
assertEquals(clusterState.metadata().version(), updatedClusterState.metadata().version());
assertEquals(clusterState.metadata().coordinationMetadata(), updatedClusterState.metadata().coordinationMetadata());
assertEquals(clusterState.metadata().getIndices(), updatedClusterState.metadata().getIndices());
assertEquals(clusterState.metadata().templates(), updatedClusterState.metadata().templates());
assertEquals(clusterState.metadata().persistentSettings(), updatedClusterState.metadata().persistentSettings());
assertEquals(clusterState.metadata().transientSettings(), updatedClusterState.metadata().transientSettings());
assertEquals(clusterState.metadata().getCustoms(), updatedClusterState.metadata().getCustoms());
assertEquals(clusterState.metadata().hashesOfConsistentSettings(), updatedClusterState.metadata().hashesOfConsistentSettings());
assertEquals(clusterState.getCustoms(), updatedClusterState.getCustoms());
assertEquals(clusterState.stateUUID(), updatedClusterState.stateUUID());
assertEquals(clusterState.version(), updatedClusterState.version());
assertEquals(clusterState.getRoutingTable().version(), updatedClusterState.getRoutingTable().version());
assertEquals(clusterState.getRoutingTable().getIndicesRouting(), updatedClusterState.getRoutingTable().getIndicesRouting());
assertEquals(clusterState.getNodes(), updatedClusterState.getNodes());
assertEquals(clusterState.getBlocks(), updatedClusterState.getBlocks());
}

public void testGetClusterStateUsingDiff() throws IOException {
ClusterState clusterState = generateClusterStateWithOneIndex().nodes(nodesWithLocalNodeClusterManager()).build();
ClusterState.Builder expectedClusterStateBuilder = ClusterState.builder(clusterState);
Metadata.Builder mb = Metadata.builder(clusterState.metadata());
ClusterStateDiffManifest.Builder diffManifestBuilder = ClusterStateDiffManifest.builder();
ClusterMetadataManifest.Builder manifestBuilder = ClusterMetadataManifest.builder();
BlobContainer blobContainer = mockBlobStoreObjects();
if (randomBoolean()) {
// updated coordination metadata
CoordinationMetadata coordinationMetadata = CoordinationMetadata.builder()
.term(clusterState.metadata().coordinationMetadata().term() + 1)
.build();
mb.coordinationMetadata(coordinationMetadata);
diffManifestBuilder.coordinationMetadataUpdated(true);
manifestBuilder.coordinationMetadata(new UploadedMetadataAttribute(COORDINATION_METADATA, "coordination-metadata-file__1"));
}
if (randomBoolean()) {
// updated templates
mb.templates(TemplatesMetadata.builder()
.put(
IndexTemplateMetadata.builder("template" + randomAlphaOfLength(3))
.patterns(Arrays.asList("bar-*", "foo-*"))
.settings(
Settings.builder()
.put("random_index_setting_" + randomAlphaOfLength(3), randomAlphaOfLength(5))
.build()
)
.build()
)
.build());
diffManifestBuilder.templatesMetadataUpdated(true);
manifestBuilder.templatesMetadata(new UploadedMetadataAttribute(TEMPLATES_METADATA, "templates-metadata-file__1"));
}
if (randomBoolean()) {
// updated persistent settings
mb.persistentSettings(Settings.builder().put("random_persistent_setting_" + randomAlphaOfLength(3), randomAlphaOfLength(5)).build());
diffManifestBuilder.settingsMetadataUpdated(true);
manifestBuilder.settingMetadata(new UploadedMetadataAttribute(SETTING_METADATA, "persistent-settings-file__1"));
}
if (randomBoolean()) {
// updated transient settings
mb.transientSettings(Settings.builder().put("random_transient_setting_" + randomAlphaOfLength(3), randomAlphaOfLength(5)).build());
diffManifestBuilder.settingsMetadataUpdated(true);
manifestBuilder.transientSettingsMetadata(new UploadedMetadataAttribute(TRANSIENT_SETTING_METADATA, "transient-settings-file__1"));
}
if (randomBoolean()) {
// updated customs
CustomMetadata2 addedCustom = new CustomMetadata2(randomAlphaOfLength(10));
mb.putCustom(addedCustom.getWriteableName(), addedCustom);
diffManifestBuilder.customMetadataUpdated(Collections.singletonList(addedCustom.getWriteableName()));
manifestBuilder.customMetadataMap(Map.of(addedCustom.getWriteableName(), new UploadedMetadataAttribute(addedCustom.getWriteableName(), "custom-md2-file__1")));
}
if (randomBoolean()) {
Set<String> customsToRemove = clusterState.metadata().customs().keySet();
customsToRemove.forEach(mb::removeCustom);
diffManifestBuilder.customMetadataDeleted(new ArrayList<>(customsToRemove));
}
if (randomBoolean()) {
// updated hashes of consistent settings
mb.hashesOfConsistentSettings(new DiffableStringMap(Map.of("secure_setting_key", "secure_setting_value")));
diffManifestBuilder.settingsMetadataUpdated(true);
manifestBuilder.hashesOfConsistentSettings(new UploadedMetadataAttribute(HASHES_OF_CONSISTENT_SETTINGS, "consistent-settings-hashes-file__1"));
}
if (randomBoolean()) {
// updated index metadata
IndexMetadata indexMetadata = new IndexMetadata.Builder("add-test-index").settings(
Settings.builder()
.put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT)
.put(IndexMetadata.SETTING_INDEX_UUID, "add-test-index-uuid")
.build()
).numberOfShards(1).numberOfReplicas(0).build();
mb.put(indexMetadata, true);
diffManifestBuilder.indicesUpdated(Collections.singletonList(indexMetadata.getIndex().getName()));
manifestBuilder.indices(List.of(new UploadedIndexMetadata(indexMetadata.getIndex().getName(), indexMetadata.getIndexUUID(), "add-test-index-file__2")));
}
if (randomBoolean()) {
// remove index metadata
Set<String> indicesToDelete = clusterState.metadata().getIndices().keySet();
indicesToDelete.forEach(mb::remove);
diffManifestBuilder.indicesDeleted(new ArrayList<>(indicesToDelete));
}
if (randomBoolean()) {
// update nodes
DiscoveryNode node = new DiscoveryNode("node_id", buildNewFakeTransportAddress(), Version.CURRENT);
DiscoveryNodes.Builder nodesBuilder = DiscoveryNodes.builder(clusterState.nodes()).add(node);
expectedClusterStateBuilder.nodes(nodesBuilder.build());
diffManifestBuilder.discoveryNodesUpdated(true);
manifestBuilder.discoveryNodesMetadata(new UploadedMetadataAttribute(DISCOVERY_NODES, "nodes-file__1"));
}
if (randomBoolean()) {
// update blocks
expectedClusterStateBuilder.blocks(randomClusterBlocks());
diffManifestBuilder.clusterBlocksUpdated(true);
manifestBuilder.clusterBlocksMetadata(new UploadedMetadataAttribute(CLUSTER_BLOCKS, "blocks-file__1"));
}
ClusterState expectedClusterState = expectedClusterStateBuilder.metadata(mb).build();
ClusterStateDiffManifest diffManifest = diffManifestBuilder.build();
manifestBuilder.diffManifest(diffManifest)
.stateUUID(clusterState.stateUUID())
.stateVersion(clusterState.version())
.metadataVersion(clusterState.metadata().version())
.clusterUUID(clusterState.getMetadata().clusterUUID())
.routingTableVersion(clusterState.getRoutingTable().version());
remoteClusterStateService.start();
ClusterState updatedClusterState = remoteClusterStateService.getClusterStateUsingDiff(
manifestBuilder.build(),
clusterState,
"test-node"
);
assertEquals(expectedClusterState.getClusterName(), updatedClusterState.getClusterName());
}

/*
* Here we will verify the migration of manifest file from codec V0.
*
Expand Down Expand Up @@ -2034,28 +2201,4 @@ static ClusterState.Builder generateClusterStateWithOneIndex() {
static DiscoveryNodes nodesWithLocalNodeClusterManager() {
return DiscoveryNodes.builder().clusterManagerNodeId("cluster-manager-id").localNodeId("cluster-manager-id").build();
}

private static class CustomMetadata1 extends TestCustomMetadata {
public static final String TYPE = "custom_md_1";

CustomMetadata1(String data) {
super(data);
}

@Override
public String getWriteableName() {
return TYPE;
}

@Override
public Version getMinimalSupportedVersion() {
return Version.CURRENT;
}

@Override
public EnumSet<Metadata.XContentContext> context() {
return EnumSet.of(Metadata.XContentContext.GATEWAY);
}
}

}
Loading

0 comments on commit d8f00f8

Please sign in to comment.