### Description

When using the DiffableUtils.diff with a vanilla OpenJDK Map, instead of the legacy ImmutableOpenMap interface, we return a mutable map (generic HashMap), which isn't the expected behaviour of the API:

https://github.com/elastic/elasticsearch/blob/45c56b22f946733712ad6d92600411c0885594c5/server/src/main/java/org/elasticsearch/cluster/DiffableUtils.java#L85

We should wrap the map returned by the diff API in an unmodifiable version.
server/src/main/java/org/elasticsearch/cluster/metadata/Metadata.java
public Builder putCustom(String type, Custom custom) {
            customs.put(type, Objects.requireNonNull(custom, type));
            return this;
        }
        public Builder removeCustom(String type) {
            customs.remove(type);
            return this;
        }
        public Builder removeCustomIf(BiPredicate<String, Custom> p) {
            customs.removeAll(p::test);
            return this;
        }
        public Builder customs(Map<String, Custom> customs) {
            customs.forEach((key, value) -> Objects.requireNonNull(value, key));
            this.customs.putAllFromMap(customs);
            return this;
        }
        /**
         * Adds a map of namespace to {@link ImmutableStateMetadata} into the metadata builder
         * @param immutableStateMetadata a map of namespace to {@link ImmutableStateMetadata}
         * @return {@link Builder}
         */
        public Builder put(Map<String, ImmutableStateMetadata> immutableStateMetadata) {
            this.immutableStateMetadata.putAll(immutableStateMetadata);
            return this;
        }
        /**
         * Adds a {@link ImmutableStateMetadata} for a given namespace to the metadata builder
         * @param metadata an {@link ImmutableStateMetadata}
         * @return {@link Builder}