Skip to content

Commit 90dc01a

Browse files
authored
[8.0] Always re-run Feature migrations which have encountered errors (#83918) (#84138)
* Always re-run Feature migrations which have encountered errors (#83918) This PR addressed the behavior described in #83917, in which Feature migrations which have encountered errors are not re-run in some cases. As of this PR, Features which have encountered errors during migration are treated the same as Features requiring migration. This PR also adds a test which artificially replicates #83917. * Resolve compilation failures for 8.0 branch
1 parent d5c29ac commit 90dc01a

File tree

3 files changed

+80
-2
lines changed

3 files changed

+80
-2
lines changed

docs/changelog/83918.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 83918
2+
summary: Always re-run Feature migrations which have encountered errors
3+
area: Infra/Core
4+
type: bug
5+
issues:
6+
- 83917

modules/reindex/src/internalClusterTest/java/org/elasticsearch/migration/FeatureMigrationIT.java

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.elasticsearch.action.support.ActiveShardCount;
2626
import org.elasticsearch.client.Client;
2727
import org.elasticsearch.cluster.ClusterState;
28+
import org.elasticsearch.cluster.ClusterStateUpdateTask;
2829
import org.elasticsearch.cluster.metadata.IndexMetadata;
2930
import org.elasticsearch.cluster.metadata.Metadata;
3031
import org.elasticsearch.cluster.service.ClusterService;
@@ -37,6 +38,7 @@
3738
import org.elasticsearch.reindex.ReindexPlugin;
3839
import org.elasticsearch.test.ESIntegTestCase;
3940
import org.elasticsearch.upgrades.FeatureMigrationResults;
41+
import org.elasticsearch.upgrades.SingleFeatureMigrationResult;
4042
import org.elasticsearch.xcontent.XContentBuilder;
4143
import org.elasticsearch.xcontent.json.JsonXContent;
4244

@@ -50,6 +52,8 @@
5052
import java.util.Map;
5153
import java.util.Optional;
5254
import java.util.Set;
55+
import java.util.concurrent.CountDownLatch;
56+
import java.util.concurrent.TimeUnit;
5357
import java.util.concurrent.atomic.AtomicReference;
5458
import java.util.function.BiConsumer;
5559
import java.util.function.Function;
@@ -268,6 +272,67 @@ public void testMigrateIndexWithWriteBlock() throws Exception {
268272
});
269273
}
270274

275+
public void testMigrationWillRunAfterError() throws Exception {
276+
createSystemIndexForDescriptor(INTERNAL_MANAGED);
277+
278+
TestPlugin.preMigrationHook.set((state) -> Collections.emptyMap());
279+
TestPlugin.postMigrationHook.set((state, metadata) -> {});
280+
281+
ensureGreen();
282+
283+
SetOnce<Exception> failure = new SetOnce<>();
284+
CountDownLatch clusterStateUpdated = new CountDownLatch(1);
285+
internalCluster().getCurrentMasterNodeInstance(ClusterService.class)
286+
.submitStateUpdateTask(this.getTestName(), new ClusterStateUpdateTask() {
287+
@Override
288+
public ClusterState execute(ClusterState currentState) throws Exception {
289+
FeatureMigrationResults newResults = new FeatureMigrationResults(
290+
Collections.singletonMap(
291+
FEATURE_NAME,
292+
SingleFeatureMigrationResult.failure(INTERNAL_MANAGED_INDEX_NAME, new RuntimeException("it failed :("))
293+
)
294+
);
295+
Metadata newMetadata = Metadata.builder(currentState.metadata())
296+
.putCustom(FeatureMigrationResults.TYPE, newResults)
297+
.build();
298+
return ClusterState.builder(currentState).metadata(newMetadata).build();
299+
}
300+
301+
@Override
302+
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
303+
clusterStateUpdated.countDown();
304+
}
305+
306+
@Override
307+
public void onFailure(String source, Exception e) {
308+
failure.set(e);
309+
clusterStateUpdated.countDown();
310+
}
311+
});
312+
313+
clusterStateUpdated.await(10, TimeUnit.SECONDS); // Should be basically instantaneous
314+
if (failure.get() != null) {
315+
logger.error("cluster state update to inject migration failure state did not succeed", failure.get());
316+
fail("cluster state update failed, see log for details");
317+
}
318+
319+
PostFeatureUpgradeRequest migrationRequest = new PostFeatureUpgradeRequest();
320+
PostFeatureUpgradeResponse migrationResponse = client().execute(PostFeatureUpgradeAction.INSTANCE, migrationRequest).get();
321+
// Make sure we actually started the migration
322+
assertTrue(
323+
"could not find [" + FEATURE_NAME + "] in response: " + Strings.toString(migrationResponse),
324+
migrationResponse.getFeatures().stream().anyMatch(feature -> feature.getFeatureName().equals(FEATURE_NAME))
325+
);
326+
327+
// Now wait for the migration to finish (otherwise the test infra explodes)
328+
assertBusy(() -> {
329+
GetFeatureUpgradeStatusRequest getStatusRequest = new GetFeatureUpgradeStatusRequest();
330+
GetFeatureUpgradeStatusResponse statusResp = client().execute(GetFeatureUpgradeStatusAction.INSTANCE, getStatusRequest).get();
331+
logger.info(Strings.toString(statusResp));
332+
assertThat(statusResp.getUpgradeStatus(), equalTo(GetFeatureUpgradeStatusResponse.UpgradeStatus.NO_MIGRATION_NEEDED));
333+
});
334+
}
335+
271336
public void assertIndexHasCorrectProperties(
272337
Metadata metadata,
273338
String indexName,
@@ -345,6 +410,7 @@ public void createSystemIndexForDescriptor(SystemIndexDescriptor descriptor) thr
345410
static final String FEATURE_NAME = "A-test-feature"; // Sorts alphabetically before the feature from MultiFeatureMigrationIT
346411
static final String ORIGIN = FeatureMigrationIT.class.getSimpleName();
347412
static final String FlAG_SETTING_KEY = IndexMetadata.INDEX_PRIORITY_SETTING.getKey();
413+
static final String INTERNAL_MANAGED_INDEX_NAME = ".int-man-old";
348414
static final int INDEX_DOC_COUNT = 100; // arbitrarily chosen
349415
public static final Version NEEDS_UPGRADE_VERSION = Version.V_7_0_0;
350416

@@ -355,7 +421,7 @@ public void createSystemIndexForDescriptor(SystemIndexDescriptor descriptor) thr
355421
static final SystemIndexDescriptor INTERNAL_MANAGED = SystemIndexDescriptor.builder()
356422
.setIndexPattern(".int-man-*")
357423
.setAliasName(".internal-managed-alias")
358-
.setPrimaryIndex(".int-man-old")
424+
.setPrimaryIndex(INTERNAL_MANAGED_INDEX_NAME)
359425
.setType(SystemIndexDescriptor.Type.INTERNAL_MANAGED)
360426
.setSettings(createSimpleSettings(NEEDS_UPGRADE_VERSION, INTERNAL_MANAGED_FLAG_VALUE))
361427
.setMappings(createSimpleMapping(true, true))

server/src/main/java/org/elasticsearch/action/admin/cluster/migration/TransportPostFeatureUpgradeAction.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
import org.elasticsearch.upgrades.SystemIndexMigrationTaskParams;
2929

3030
import java.util.Comparator;
31+
import java.util.EnumSet;
3132
import java.util.List;
33+
import java.util.Set;
3234
import java.util.stream.Collectors;
3335

3436
import static org.elasticsearch.action.admin.cluster.migration.TransportGetFeatureUpgradeStatusAction.getFeatureUpgradeStatus;
@@ -75,11 +77,15 @@ protected void masterOperation(
7577
ClusterState state,
7678
ActionListener<PostFeatureUpgradeResponse> listener
7779
) throws Exception {
80+
final Set<GetFeatureUpgradeStatusResponse.UpgradeStatus> upgradableStatuses = EnumSet.of(
81+
GetFeatureUpgradeStatusResponse.UpgradeStatus.MIGRATION_NEEDED,
82+
GetFeatureUpgradeStatusResponse.UpgradeStatus.ERROR
83+
);
7884
List<PostFeatureUpgradeResponse.Feature> featuresToMigrate = systemIndices.getFeatures()
7985
.values()
8086
.stream()
8187
.map(feature -> getFeatureUpgradeStatus(state, feature))
82-
.filter(status -> status.getUpgradeStatus().equals(GetFeatureUpgradeStatusResponse.UpgradeStatus.MIGRATION_NEEDED))
88+
.filter(status -> upgradableStatuses.contains(status.getUpgradeStatus()))
8389
.map(GetFeatureUpgradeStatusResponse.FeatureUpgradeStatus::getFeatureName)
8490
.map(PostFeatureUpgradeResponse.Feature::new)
8591
.sorted(Comparator.comparing(PostFeatureUpgradeResponse.Feature::getFeatureName)) // consistent ordering to simplify testing

0 commit comments

Comments
 (0)