### Description

It is impossible to create a follower index with a `$` character in its name (please note, it is possible to create a regular index with `$` in its name).

This could be reproduced by rest request:
```
PUT /my-index/_ccr/follow
{
    "remote_cluster": "my-remote-cluster",
    "leader_index": "my-index$follower"
}
```

or `CcrIntegTestCase`:

```
    public void testFollowIndex() throws Exception {
        assertAcked(leaderClient().admin().indices().prepareCreate("my$index"));
        setupRemoteCluster();
        final PutFollowAction.Request followRequest = putFollow("my$index", "my$index");
        followerClient().execute(PutFollowAction.INSTANCE, followRequest).get();
    }
```

This is happening as during initial follow phase we restore the leader cluster from the remote using a snapshot restore.
Corresponding request is created with index name added to `RestoreSnapshotRequest#renamePattern` (regexp) without escaping `$`.

x-pack/plugin/ccr/src/internalClusterTest/java/org/elasticsearch/xpack/ccr/IndexFollowingIT.java
});
        ForceMergeRequest forceMergeRequest = new ForceMergeRequest("index1");
        forceMergeRequest.maxNumSegments(1);
        leaderClient().admin().indices().forceMerge(forceMergeRequest).actionGet();
        followerClient().execute(ResumeFollowAction.INSTANCE, resumeFollow("index2")).get();
        assertBusy(() -> {
            List<ShardFollowNodeTaskStatus> statuses = getFollowTaskStatuses("index2");
            Set<ResourceNotFoundException> exceptions = statuses.stream()
                .map(ShardFollowNodeTaskStatus::getFatalException)
                .filter(Objects::nonNull)
                .map(ExceptionsHelper::unwrapCause)
                .filter(e -> e instanceof ResourceNotFoundException)
                .map(e -> (ResourceNotFoundException) e)
                .filter(e -> e.getMetadataKeys().contains("es.requested_operations_missing"))
                .collect(Collectors.toSet());
            exceptionConsumer.accept(exceptions);
        });
        followerClient().admin().indices().prepareClose("index2").setMasterNodeTimeout(TimeValue.MAX_VALUE).get();
        pauseFollow("index2");
        if (randomBoolean()) {
            assertAcked(followerClient().execute(UnfollowAction.INSTANCE, new UnfollowAction.Request("index2")).actionGet());
        }
        final PutFollowAction.Request followRequest2 = putFollow("index1", "index2");
        PutFollowAction.Response response2 = followerClient().execute(PutFollowAction.INSTANCE, followRequest2).get();
        assertTrue(response2.isFollowIndexCreated());
        assertTrue(response2.isFollowIndexShardsAcked());
        assertTrue(response2.isIndexFollowingStarted());
        ensureFollowerGreen("index2");
        assertIndexFullyReplicatedToFollower("index1", "index2");
        for (int i = 2; i < numDocs; i++) {