|
13 | 13 | import org.elasticsearch.TransportVersion; |
14 | 14 | import org.elasticsearch.TransportVersions; |
15 | 15 | import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; |
| 16 | +import org.elasticsearch.client.internal.Client; |
16 | 17 | import org.elasticsearch.cluster.ClusterModule; |
17 | 18 | import org.elasticsearch.cluster.ClusterState; |
18 | 19 | import org.elasticsearch.cluster.Diff; |
19 | 20 | import org.elasticsearch.cluster.coordination.CoordinationMetadata; |
20 | 21 | import org.elasticsearch.cluster.coordination.CoordinationMetadata.VotingConfigExclusion; |
| 22 | +import org.elasticsearch.cluster.service.ClusterService; |
21 | 23 | import org.elasticsearch.common.Strings; |
22 | 24 | import org.elasticsearch.common.UUIDs; |
23 | 25 | import org.elasticsearch.common.bytes.BytesArray; |
|
28 | 30 | import org.elasticsearch.common.io.stream.NamedWriteableRegistry; |
29 | 31 | import org.elasticsearch.common.io.stream.StreamInput; |
30 | 32 | import org.elasticsearch.common.io.stream.StreamOutput; |
| 33 | +import org.elasticsearch.common.settings.ClusterSettings; |
| 34 | +import org.elasticsearch.common.settings.IndexScopedSettings; |
31 | 35 | import org.elasticsearch.common.settings.Setting; |
32 | 36 | import org.elasticsearch.common.settings.Settings; |
33 | 37 | import org.elasticsearch.common.util.Maps; |
34 | 38 | import org.elasticsearch.common.util.set.Sets; |
35 | 39 | import org.elasticsearch.common.xcontent.ChunkedToXContent; |
36 | 40 | import org.elasticsearch.common.xcontent.XContentHelper; |
| 41 | +import org.elasticsearch.core.FixForMultiProject; |
37 | 42 | import org.elasticsearch.core.Nullable; |
38 | 43 | import org.elasticsearch.core.Predicates; |
39 | 44 | import org.elasticsearch.core.SuppressForbidden; |
|
47 | 52 | import org.elasticsearch.index.alias.RandomAliasActionsGenerator; |
48 | 53 | import org.elasticsearch.index.mapper.MapperService; |
49 | 54 | import org.elasticsearch.indices.IndicesModule; |
| 55 | +import org.elasticsearch.indices.SystemIndices; |
50 | 56 | import org.elasticsearch.ingest.IngestMetadata; |
| 57 | +import org.elasticsearch.persistent.ClusterPersistentTasksCustomMetadata; |
| 58 | +import org.elasticsearch.persistent.PersistentTasks; |
| 59 | +import org.elasticsearch.persistent.PersistentTasksCustomMetadata; |
| 60 | +import org.elasticsearch.persistent.PersistentTasksExecutorRegistry; |
| 61 | +import org.elasticsearch.persistent.PersistentTasksService; |
51 | 62 | import org.elasticsearch.plugins.FieldPredicate; |
52 | 63 | import org.elasticsearch.plugins.MapperPlugin; |
53 | 64 | import org.elasticsearch.test.AbstractChunkedSerializingTestCase; |
54 | 65 | import org.elasticsearch.test.ESTestCase; |
55 | 66 | import org.elasticsearch.test.TransportVersionUtils; |
56 | 67 | import org.elasticsearch.test.index.IndexVersionUtils; |
| 68 | +import org.elasticsearch.threadpool.ThreadPool; |
| 69 | +import org.elasticsearch.upgrades.SystemIndexMigrationExecutor; |
| 70 | +import org.elasticsearch.upgrades.SystemIndexMigrationTaskParams; |
57 | 71 | import org.elasticsearch.xcontent.NamedXContentRegistry; |
58 | 72 | import org.elasticsearch.xcontent.ToXContent; |
59 | 73 | import org.elasticsearch.xcontent.XContentBuilder; |
|
111 | 125 | import static org.hamcrest.Matchers.nullValue; |
112 | 126 | import static org.hamcrest.Matchers.sameInstance; |
113 | 127 | import static org.hamcrest.Matchers.startsWith; |
| 128 | +import static org.mockito.Mockito.mock; |
| 129 | +import static org.mockito.Mockito.when; |
114 | 130 |
|
115 | 131 | public class MetadataTests extends ESTestCase { |
116 | 132 |
|
@@ -750,6 +766,10 @@ public void testParseXContentFormatBeforeMultiProject() throws IOException { |
750 | 766 | { |
751 | 767 | "id": "health-node", |
752 | 768 | "task":{ "health-node": {"params":{}} } |
| 769 | + }, |
| 770 | + { |
| 771 | + "id": "upgrade-system-indices", |
| 772 | + "task":{ "upgrade-system-indices": {"params":{}} } |
753 | 773 | } |
754 | 774 | ] |
755 | 775 | }, |
@@ -797,17 +817,45 @@ public void testParseXContentFormatBeforeMultiProject() throws IOException { |
797 | 817 | registry.addAll(ClusterModule.getNamedXWriteables()); |
798 | 818 | registry.addAll(IndicesModule.getNamedXContents()); |
799 | 819 | registry.addAll(HealthNodeTaskExecutor.getNamedXContentParsers()); |
| 820 | + registry.addAll(SystemIndexMigrationExecutor.getNamedXContentParsers()); |
| 821 | + |
| 822 | + final var clusterService = mock(ClusterService.class); |
| 823 | + when(clusterService.threadPool()).thenReturn(mock(ThreadPool.class)); |
| 824 | + final var healthNodeTaskExecutor = HealthNodeTaskExecutor.create( |
| 825 | + clusterService, |
| 826 | + mock(PersistentTasksService.class), |
| 827 | + Settings.EMPTY, |
| 828 | + ClusterSettings.createBuiltInClusterSettings() |
| 829 | + ); |
| 830 | + final var systemIndexMigrationExecutor = new SystemIndexMigrationExecutor( |
| 831 | + mock(Client.class), |
| 832 | + clusterService, |
| 833 | + mock(SystemIndices.class), |
| 834 | + mock(MetadataUpdateSettingsService.class), |
| 835 | + mock(MetadataCreateIndexService.class), |
| 836 | + IndexScopedSettings.DEFAULT_SCOPED_SETTINGS |
| 837 | + ); |
| 838 | + new PersistentTasksExecutorRegistry(List.of(healthNodeTaskExecutor, systemIndexMigrationExecutor)); |
800 | 839 |
|
801 | 840 | XContentParserConfiguration config = XContentParserConfiguration.EMPTY.withRegistry(new NamedXContentRegistry(registry)); |
802 | 841 | try (XContentParser parser = JsonXContent.jsonXContent.createParser(config, json)) { |
803 | 842 | final var metatdata = Metadata.fromXContent(parser); |
804 | 843 | assertThat(metatdata, notNullValue()); |
805 | 844 | assertThat(metatdata.clusterUUID(), is("aba1aa1ababbbaabaabaab")); |
806 | | - assertThat(metatdata.customs().keySet(), containsInAnyOrder("desired_nodes")); |
| 845 | + assertThat(metatdata.customs().keySet(), containsInAnyOrder("desired_nodes", "cluster_persistent_tasks")); |
| 846 | + @FixForMultiProject(description = "adjust the assertion once health-node becomes cluster-scoped") |
| 847 | + final var clusterTasks = ClusterPersistentTasksCustomMetadata.get(metatdata); |
| 848 | + assertThat(clusterTasks.tasks(), hasSize(0)); |
807 | 849 | assertThat( |
808 | 850 | metatdata.getProject().customs().keySet(), |
809 | 851 | containsInAnyOrder("persistent_tasks", "index-graveyard", "component_template") |
810 | 852 | ); |
| 853 | + final var projectTasks = PersistentTasksCustomMetadata.get(metatdata.getProject()); |
| 854 | + assertThat( |
| 855 | + projectTasks.tasks().stream().map(PersistentTasksCustomMetadata.PersistentTask::getTaskName).toList(), |
| 856 | + containsInAnyOrder("health-node", "upgrade-system-indices") |
| 857 | + ); |
| 858 | + assertThat(clusterTasks.getLastAllocationId(), equalTo(projectTasks.getLastAllocationId())); |
811 | 859 | } |
812 | 860 | } |
813 | 861 |
|
@@ -2534,16 +2582,52 @@ public void testEmptyDiffReturnsSameInstance() throws IOException { |
2534 | 2582 | } |
2535 | 2583 |
|
2536 | 2584 | public void testMultiProjectXContent() throws IOException { |
2537 | | - final List<ProjectMetadata> projects = randomList(1, 5, () -> randomProject(new ProjectId(randomUUID()), randomIntBetween(1, 3))); |
| 2585 | + final long lastAllocationId = randomNonNegativeLong(); |
| 2586 | + final List<ProjectMetadata> projects = randomList(1, 5, () -> randomProject(new ProjectId(randomUUID()), randomIntBetween(1, 3))) |
| 2587 | + .stream() |
| 2588 | + .map( |
| 2589 | + project -> ProjectMetadata.builder(project) |
| 2590 | + .putCustom( |
| 2591 | + PersistentTasksCustomMetadata.TYPE, |
| 2592 | + new PersistentTasksCustomMetadata( |
| 2593 | + lastAllocationId, |
| 2594 | + Map.of( |
| 2595 | + SystemIndexMigrationTaskParams.SYSTEM_INDEX_UPGRADE_TASK_NAME, |
| 2596 | + new PersistentTasksCustomMetadata.PersistentTask<>( |
| 2597 | + SystemIndexMigrationTaskParams.SYSTEM_INDEX_UPGRADE_TASK_NAME, |
| 2598 | + SystemIndexMigrationTaskParams.SYSTEM_INDEX_UPGRADE_TASK_NAME, |
| 2599 | + new SystemIndexMigrationTaskParams(), |
| 2600 | + lastAllocationId, |
| 2601 | + PersistentTasks.INITIAL_ASSIGNMENT |
| 2602 | + ) |
| 2603 | + ) |
| 2604 | + ) |
| 2605 | + ) |
| 2606 | + .build() |
| 2607 | + ) |
| 2608 | + .toList(); |
| 2609 | + |
| 2610 | + @FixForMultiProject(description = "considering adding health-node into metadata customs once health-node becomes a cluster task") |
2538 | 2611 | final Metadata originalMeta = randomMetadata(projects); |
| 2612 | + |
2539 | 2613 | ToXContent.Params p = new ToXContent.MapParams( |
2540 | 2614 | Map.of("multi-project", "true", Metadata.CONTEXT_MODE_PARAM, Metadata.CONTEXT_MODE_GATEWAY) |
2541 | 2615 | ); |
2542 | 2616 |
|
2543 | 2617 | final BytesReference bytes = toXContentBytes(originalMeta, p); |
2544 | | - try (XContentParser parser = createParser(JsonXContent.jsonXContent, bytes)) { |
| 2618 | + final List<NamedXContentRegistry.Entry> registry = new ArrayList<>(); |
| 2619 | + registry.addAll(ClusterModule.getNamedXWriteables()); |
| 2620 | + registry.addAll(SystemIndexMigrationExecutor.getNamedXContentParsers()); |
| 2621 | + final var config = XContentParserConfiguration.EMPTY.withRegistry(new NamedXContentRegistry(registry)); |
| 2622 | + |
| 2623 | + try (XContentParser parser = createParser(config, JsonXContent.jsonXContent, bytes)) { |
2545 | 2624 | Metadata fromXContentMeta = Metadata.fromXContent(parser); |
2546 | 2625 | assertThat(fromXContentMeta.projects().keySet(), equalTo(originalMeta.projects().keySet())); |
| 2626 | + for (var project : fromXContentMeta.projects().values()) { |
| 2627 | + final var projectTasks = PersistentTasksCustomMetadata.get(project); |
| 2628 | + assertThat(projectTasks.getLastAllocationId(), equalTo(lastAllocationId)); |
| 2629 | + assertThat(projectTasks.taskMap().keySet(), equalTo(Set.of(SystemIndexMigrationTaskParams.SYSTEM_INDEX_UPGRADE_TASK_NAME))); |
| 2630 | + } |
2547 | 2631 | } |
2548 | 2632 | } |
2549 | 2633 |
|
|
0 commit comments