A transport put follow-action can be triggered for an index that is part of a data stream and already exists.
Normally this is not an issue because the restore operation will just fail because the index already exists.
If however, the index is currently closed (for example due to ILM doing a force-merge with codec change step on the index),
this causes the currently closed index to be restored into. As a result we run into a bug in the following code in

`org.elasticsearch.xpack.ccr.action.TransportPutFollowAction#createFollowerIndex`:

```java
BiConsumer<ClusterState, Metadata.Builder> updater = (currentState, mdBuilder) -> {
   DataStream localDataStream = currentState.getMetadata().dataStreams().get(remoteDataStream.getName());
   Index followerIndex = mdBuilder.get(followerIndexName).getIndex();
   assert followerIndex != null;

   DataStream updatedDataStream = updateLocalDataStream(followerIndex, localDataStream, remoteDataStream);
      mdBuilder.put(updatedDataStream);
   };
   restoreService.restoreSnapshot(restoreRequest, delegatelistener, updater);
 }
```

This code updates the local data stream when following an index without checking if that index already is part of the data stream, thus now creating two entries for the same `Index` in the data stream's indices list. Code like `org.elasticsearch.cluster.metadata.DataStream#removeBackingIndex` however assumes no duplicates and will when deleting an index, only remove it from the data stream once. Thus leaving a dangling `Index` instance that does not point to any existing index any more, corrupting the cluster state.


cc @martijnvg thanks for the help with reasoning this out
server/src/main/java/org/elasticsearch/cluster/metadata/MetadataIndexTemplateService.java
*
     * @param metadata The {@link Metadata} containing all of the {@link IndexTemplateMetadata} values
     * @param indexName The name of the index that templates are being found for
     * @param isHidden Whether or not the index is known to be hidden. May be {@code null} if the index
     *                 being hidden has not been explicitly requested. When {@code null} if the result
     *                 of template application results in a hidden index, then global templates will
     *                 not be returned
     * @return a list of templates sorted by {@link IndexTemplateMetadata#order()} descending.
     *
     */
    public static List<IndexTemplateMetadata> findV1Templates(Metadata metadata, String indexName, @Nullable Boolean isHidden) {
        final String resolvedIndexName = IndexNameExpressionResolver.DateMathExpressionResolver.resolveExpression(indexName);
        final Predicate<String> patternMatchPredicate = pattern -> Regex.simpleMatch(pattern, resolvedIndexName);
        final List<IndexTemplateMetadata> matchedTemplates = new ArrayList<>();
        for (IndexTemplateMetadata template : metadata.templates().values()) {
            if (isHidden == null || isHidden == Boolean.FALSE) {
                final boolean matched = template.patterns().stream().anyMatch(patternMatchPredicate);
                if (matched) {
                    matchedTemplates.add(template);
                }
            } else {
                assert isHidden == Boolean.TRUE;
                final boolean isNotMatchAllTemplate = template.patterns().stream().noneMatch(Regex::isMatchAllPattern);
                if (isNotMatchAllTemplate) {
                    if (template.patterns().stream().anyMatch(patternMatchPredicate)) {
                        matchedTemplates.add(template);
                    }
                }
            }
        }