diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/dangling/delete/TransportDeleteDanglingIndexAction.java b/server/src/main/java/org/elasticsearch/action/admin/indices/dangling/delete/TransportDeleteDanglingIndexAction.java index 3d9ace9635333..5fb629957b286 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/dangling/delete/TransportDeleteDanglingIndexAction.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/dangling/delete/TransportDeleteDanglingIndexAction.java @@ -29,7 +29,7 @@ import org.elasticsearch.cluster.block.ClusterBlockException; import org.elasticsearch.cluster.metadata.IndexGraveyard; import org.elasticsearch.cluster.metadata.IndexMetadata; -import org.elasticsearch.cluster.metadata.Metadata; +import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.core.SuppressForbidden; @@ -126,9 +126,9 @@ private void submitUnbatchedTask(@SuppressWarnings("SameParameterValue") String } private ClusterState deleteDanglingIndex(ClusterState currentState, Index indexToDelete) { - final Metadata metaData = currentState.getMetadata(); + final var project = currentState.metadata().getProject(); - for (Map.Entry each : metaData.getProject().indices().entrySet()) { + for (Map.Entry each : project.indices().entrySet()) { if (indexToDelete.getUUID().equals(each.getValue().getIndexUUID())) { throw new IllegalArgumentException( "Refusing to delete dangling index " @@ -143,18 +143,13 @@ private ClusterState deleteDanglingIndex(ClusterState currentState, Index indexT // By definition, a dangling index is an index not present in the cluster state and with no tombstone, // so we shouldn't reach this point if these conditions aren't met. For super-safety, however, check // that a tombstone doesn't already exist for this index. - if (metaData.getProject().indexGraveyard().containsIndex(indexToDelete)) { + if (project.indexGraveyard().containsIndex(indexToDelete)) { return currentState; } - Metadata.Builder metaDataBuilder = Metadata.builder(metaData); - - final IndexGraveyard newGraveyard = IndexGraveyard.builder(metaDataBuilder.indexGraveyard()) - .addTombstone(indexToDelete) - .build(settings); - metaDataBuilder.indexGraveyard(newGraveyard); - - return ClusterState.builder(currentState).metadata(metaDataBuilder.build()).build(); + final IndexGraveyard newGraveyard = IndexGraveyard.builder(project.indexGraveyard()).addTombstone(indexToDelete).build(settings); + final ProjectMetadata updatedProject = ProjectMetadata.builder(project).indexGraveyard(newGraveyard).build(); + return ClusterState.builder(currentState).putProjectMetadata(updatedProject).build(); } @Override diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/Metadata.java b/server/src/main/java/org/elasticsearch/cluster/metadata/Metadata.java index dc55f4516d252..5309bff27f8c0 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/Metadata.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/Metadata.java @@ -1780,17 +1780,6 @@ public Builder removeReservedState(ReservedStateMetadata metadata) { return this; } - @Deprecated(forRemoval = true) - public Builder indexGraveyard(final IndexGraveyard indexGraveyard) { - getSingleProject().indexGraveyard(indexGraveyard); - return this; - } - - @Deprecated(forRemoval = true) - public IndexGraveyard indexGraveyard() { - return getSingleProject().indexGraveyard(); - } - @Deprecated(forRemoval = true) public Builder updateSettings(Settings settings, String... indices) { getSingleProject().updateSettings(settings, indices); diff --git a/server/src/test/java/org/elasticsearch/cluster/ClusterChangedEventTests.java b/server/src/test/java/org/elasticsearch/cluster/ClusterChangedEventTests.java index ed5f6cf3ca411..ea83c92bfcdd6 100644 --- a/server/src/test/java/org/elasticsearch/cluster/ClusterChangedEventTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/ClusterChangedEventTests.java @@ -702,20 +702,24 @@ private static ClusterState nextState( final ClusterState.Builder builder = ClusterState.builder(previousState); builder.stateUUID(UUIDs.randomBase64UUID()); final Metadata.Builder metaBuilder = Metadata.builder(previousState.metadata()); + // The refactorings required to pass an explicit project ID to this method (and the state creation methods) is not worth it. + final var previousProject = previousState.metadata().projects().values().iterator().next(); + final ProjectMetadata.Builder projectBuilder = ProjectMetadata.builder(previousProject); if (changeClusterUUID || addedIndices.size() > 0 || deletedIndices.size() > 0) { // there is some change in metadata cluster state if (changeClusterUUID) { metaBuilder.clusterUUID(UUIDs.randomBase64UUID()); } for (Index index : addedIndices) { - metaBuilder.put(createIndexMetadata(index), true); + projectBuilder.put(createIndexMetadata(index), true); } for (Index index : deletedIndices) { - metaBuilder.remove(index.getName()); - IndexGraveyard.Builder graveyardBuilder = IndexGraveyard.builder(metaBuilder.indexGraveyard()); + projectBuilder.remove(index.getName()); + IndexGraveyard.Builder graveyardBuilder = IndexGraveyard.builder(projectBuilder.indexGraveyard()); graveyardBuilder.addTombstone(index); - metaBuilder.indexGraveyard(graveyardBuilder.build()); + projectBuilder.indexGraveyard(graveyardBuilder.build()); } + metaBuilder.put(projectBuilder); builder.metadata(metaBuilder); } if (numNodesToRemove > 0) { diff --git a/server/src/test/java/org/elasticsearch/cluster/coordination/ElasticsearchNodeCommandTests.java b/server/src/test/java/org/elasticsearch/cluster/coordination/ElasticsearchNodeCommandTests.java index 9a01f44fa067f..f51debe8a5b24 100644 --- a/server/src/test/java/org/elasticsearch/cluster/coordination/ElasticsearchNodeCommandTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/coordination/ElasticsearchNodeCommandTests.java @@ -13,8 +13,11 @@ import org.elasticsearch.cluster.metadata.IndexGraveyard; import org.elasticsearch.cluster.metadata.IndexMetadata; import org.elasticsearch.cluster.metadata.Metadata; +import org.elasticsearch.cluster.metadata.ProjectId; +import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.common.UUIDs; import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.core.FixForMultiProject; import org.elasticsearch.index.Index; import org.elasticsearch.indices.IndicesModule; import org.elasticsearch.test.ESTestCase; @@ -93,8 +96,8 @@ private void runLoadStateTest(boolean hasMissingCustoms, boolean preserveUnknown } private Metadata randomMeta() { - Metadata.Builder mdBuilder = Metadata.builder(); - mdBuilder.generateClusterUuidIfNeeded(); + @FixForMultiProject // Pass random project ID when usages are namespaced. + ProjectMetadata.Builder projectBuilder = ProjectMetadata.builder(ProjectId.DEFAULT); int numDelIndices = randomIntBetween(0, 5); final IndexGraveyard.Builder graveyard = IndexGraveyard.builder(); for (int i = 0; i < numDelIndices; i++) { @@ -105,11 +108,11 @@ private Metadata randomMeta() { for (int i = 0; i < numDataStreams; i++) { String dataStreamName = "name" + 1; IndexMetadata backingIndex = createFirstBackingIndex(dataStreamName).build(); - mdBuilder.put(newInstance(dataStreamName, List.of(backingIndex.getIndex()))); + projectBuilder.put(newInstance(dataStreamName, List.of(backingIndex.getIndex()))); } } - mdBuilder.indexGraveyard(graveyard.build()); - return mdBuilder.build(); + projectBuilder.indexGraveyard(graveyard.build()); + return Metadata.builder().generateClusterUuidIfNeeded().put(projectBuilder).build(); } @Override diff --git a/server/src/test/java/org/elasticsearch/cluster/metadata/MetadataTests.java b/server/src/test/java/org/elasticsearch/cluster/metadata/MetadataTests.java index b36b9de3dab8a..b32f290f0f3c7 100644 --- a/server/src/test/java/org/elasticsearch/cluster/metadata/MetadataTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/metadata/MetadataTests.java @@ -34,6 +34,7 @@ import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.common.xcontent.ChunkedToXContent; import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.core.FixForMultiProject; import org.elasticsearch.core.Nullable; import org.elasticsearch.core.Predicates; import org.elasticsearch.core.SuppressForbidden; @@ -607,27 +608,35 @@ public void testUnknownFieldIndexMetadata() throws IOException { } public void testMetadataGlobalStateChangesOnIndexDeletions() { + final var projectId = randomProjectIdOrDefault(); IndexGraveyard.Builder builder = IndexGraveyard.builder(); builder.addTombstone(new Index("idx1", UUIDs.randomBase64UUID())); - final Metadata metadata1 = Metadata.builder().indexGraveyard(builder.build()).build(); - builder = IndexGraveyard.builder(metadata1.getProject().indexGraveyard()); + final Metadata metadata1 = Metadata.builder().put(ProjectMetadata.builder(projectId).indexGraveyard(builder.build())).build(); + builder = IndexGraveyard.builder(metadata1.getProject(projectId).indexGraveyard()); builder.addTombstone(new Index("idx2", UUIDs.randomBase64UUID())); - final Metadata metadata2 = Metadata.builder(metadata1).indexGraveyard(builder.build()).build(); + final Metadata metadata2 = Metadata.builder(metadata1) + .put(ProjectMetadata.builder(metadata1.getProject(projectId)).indexGraveyard(builder.build())) + .build(); assertFalse("metadata not equal after adding index deletions", Metadata.isGlobalStateEquals(metadata1, metadata2)); final Metadata metadata3 = Metadata.builder(metadata2).build(); assertTrue("metadata equal when not adding index deletions", Metadata.isGlobalStateEquals(metadata2, metadata3)); } public void testXContentWithIndexGraveyard() throws IOException { + @FixForMultiProject // XContent serialization and parsing with a random project ID currently only works when serializing in MP mode + final var projectId = ProjectId.DEFAULT; final IndexGraveyard graveyard = IndexGraveyardTests.createRandom(); - final Metadata originalMeta = Metadata.builder().indexGraveyard(graveyard).build(); + final Metadata originalMeta = Metadata.builder().put(ProjectMetadata.builder(projectId).indexGraveyard(graveyard)).build(); final XContentBuilder builder = JsonXContent.contentBuilder(); builder.startObject(); Metadata.FORMAT.toXContent(builder, originalMeta); builder.endObject(); try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { final Metadata fromXContentMeta = Metadata.fromXContent(parser); - assertThat(fromXContentMeta.getProject().indexGraveyard(), equalTo(originalMeta.getProject().indexGraveyard())); + assertThat( + fromXContentMeta.getProject(projectId).indexGraveyard(), + equalTo(originalMeta.getProject(projectId).indexGraveyard()) + ); } } @@ -975,15 +984,16 @@ public void testGlobalStateEqualsCoordinationMetadata() { } public void testSerializationWithIndexGraveyard() throws IOException { + final var projectId = randomProjectIdOrDefault(); final IndexGraveyard graveyard = IndexGraveyardTests.createRandom(); - final Metadata originalMeta = Metadata.builder().indexGraveyard(graveyard).build(); + final Metadata originalMeta = Metadata.builder().put(ProjectMetadata.builder(projectId).indexGraveyard(graveyard)).build(); final BytesStreamOutput out = new BytesStreamOutput(); originalMeta.writeTo(out); NamedWriteableRegistry namedWriteableRegistry = new NamedWriteableRegistry(ClusterModule.getNamedWriteables()); final Metadata fromStreamMeta = Metadata.readFrom( new NamedWriteableAwareStreamInput(out.bytes().streamInput(), namedWriteableRegistry) ); - assertThat(fromStreamMeta.getProject().indexGraveyard(), equalTo(fromStreamMeta.getProject().indexGraveyard())); + assertThat(fromStreamMeta.getProject(projectId).indexGraveyard(), equalTo(originalMeta.getProject(projectId).indexGraveyard())); } public void testFindMappings() throws IOException { diff --git a/server/src/test/java/org/elasticsearch/gateway/DanglingIndicesStateTests.java b/server/src/test/java/org/elasticsearch/gateway/DanglingIndicesStateTests.java index 9ac96378ba8c2..f426f4cff626d 100644 --- a/server/src/test/java/org/elasticsearch/gateway/DanglingIndicesStateTests.java +++ b/server/src/test/java/org/elasticsearch/gateway/DanglingIndicesStateTests.java @@ -13,8 +13,11 @@ import org.elasticsearch.cluster.metadata.IndexGraveyard; import org.elasticsearch.cluster.metadata.IndexMetadata; import org.elasticsearch.cluster.metadata.Metadata; +import org.elasticsearch.cluster.metadata.ProjectId; +import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.core.FixForMultiProject; import org.elasticsearch.env.NodeEnvironment; import org.elasticsearch.index.Index; import org.elasticsearch.index.IndexVersion; @@ -85,7 +88,8 @@ public void testDanglingIndicesNotReportedWhenTombstonePresent() throws Exceptio MetaStateWriterUtils.writeIndex(env, "test_write", dangledIndex); final IndexGraveyard graveyard = IndexGraveyard.builder().addTombstone(dangledIndex.getIndex()).build(); - final Metadata metadata = Metadata.builder().indexGraveyard(graveyard).build(); + @FixForMultiProject // Use random project ID + final Metadata metadata = Metadata.builder().put(ProjectMetadata.builder(ProjectId.DEFAULT).indexGraveyard(graveyard)).build(); DanglingIndicesState danglingState = createDanglingIndicesState(metaStateService, metadata); diff --git a/server/src/test/java/org/elasticsearch/indices/IndicesServiceTests.java b/server/src/test/java/org/elasticsearch/indices/IndicesServiceTests.java index 967dd3d7626b7..7f2aa62f7cf83 100644 --- a/server/src/test/java/org/elasticsearch/indices/IndicesServiceTests.java +++ b/server/src/test/java/org/elasticsearch/indices/IndicesServiceTests.java @@ -33,6 +33,7 @@ import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.EsExecutors; +import org.elasticsearch.core.FixForMultiProject; import org.elasticsearch.core.TimeValue; import org.elasticsearch.env.NodeEnvironment; import org.elasticsearch.env.ShardLockObtainFailedException; @@ -546,8 +547,9 @@ public void testIndexAndTombstoneWithSameNameOnStartup() throws Exception { .build(); final Index tombstonedIndex = new Index(indexName, UUIDs.randomBase64UUID()); final IndexGraveyard graveyard = IndexGraveyard.builder().addTombstone(tombstonedIndex).build(); - final Metadata metadata = Metadata.builder().put(indexMetadata, true).indexGraveyard(graveyard).build(); - final ClusterState clusterState = new ClusterState.Builder(new ClusterName("testCluster")).metadata(metadata).build(); + @FixForMultiProject // Use random project-id + final var project = ProjectMetadata.builder(ProjectId.DEFAULT).put(indexMetadata, true).indexGraveyard(graveyard).build(); + final ClusterState clusterState = new ClusterState.Builder(new ClusterName("testCluster")).putProjectMetadata(project).build(); // if all goes well, this won't throw an exception, otherwise, it will throw an IllegalStateException indicesService.verifyIndexIsDeleted(tombstonedIndex, clusterState); }