### 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
.map(FollowStatsAction.StatsResponse::status)
            .filter(status -> status.followerIndex().equals(followerIndex))
            .collect(Collectors.toList());
    }
    private BooleanSupplier hasFollowIndexBeenClosed(String indexName) {
        String electedMasterNode = getFollowerCluster().getMasterName();
        ClusterService clusterService = getFollowerCluster().getInstance(ClusterService.class, electedMasterNode);
        AtomicBoolean closed = new AtomicBoolean(false);
        clusterService.addListener(event -> {
            IndexMetadata indexMetadata = event.state().metadata().index(indexName);
            if (indexMetadata != null && indexMetadata.getState() == IndexMetadata.State.CLOSE) {
                closed.set(true);
            }
        });
        return closed::get;
    }
    private CheckedRunnable<Exception> assertTask(final int numberOfPrimaryShards, final Map<ShardId, Long> numDocsPerShard) {
        return () -> {
            final ClusterState clusterState = followerClient().admin().cluster().prepareState().get().getState();
            final PersistentTasksCustomMetadata taskMetadata = clusterState.getMetadata().custom(PersistentTasksCustomMetadata.TYPE);
            assertNotNull(taskMetadata);
            ListTasksRequest listTasksRequest = new ListTasksRequest();
            listTasksRequest.setDetailed(true);
            listTasksRequest.setActions(ShardFollowTask.NAME + "[c]");
            ListTasksResponse listTasksResponse = followerClient().admin().cluster().listTasks(listTasksRequest).actionGet();
            assertThat(listTasksResponse.getNodeFailures().size(), equalTo(0));
            assertThat(listTasksResponse.getTaskFailures().size(), equalTo(0));
            List<TaskInfo> taskInfos = listTasksResponse.getTasks();
            assertThat(taskInfos.size(), equalTo(numberOfPrimaryShards));
            Collection<PersistentTasksCustomMetadata.PersistentTask<?>> shardFollowTasks = taskMetadata.findTasks(