Forráskód Böngészése

[CCR] Change get autofollow patterns API response format (#36203)

The current response format is:

```
{
    "pattern1": {
        ...
    },
    "pattern2": {
        ...
    }
}
```

The new format is:

```
{
    "patterns": [
        {
            "name": "pattern1",
            "pattern": {
                ...
            }
        },
        {
            "name": "pattern2",
            "pattern": {
                ...
            }
        }
    ]
}
```

This format is more structured and more friendly for parsing and generating specs.
This is a breaking change, but it is better to do this now while ccr
is still a beta feature than later.

Follow up from #36049
Martijn van Groningen 6 éve
szülő
commit
b9707c29a1

+ 35 - 17
client/rest-high-level/src/main/java/org/elasticsearch/client/ccr/GetAutoFollowPatternResponse.java

@@ -19,41 +19,59 @@
 
 package org.elasticsearch.client.ccr;
 
+import org.elasticsearch.common.ParseField;
 import org.elasticsearch.common.unit.ByteSizeValue;
 import org.elasticsearch.common.unit.TimeValue;
 import org.elasticsearch.common.xcontent.ConstructingObjectParser;
 import org.elasticsearch.common.xcontent.ObjectParser;
 import org.elasticsearch.common.xcontent.XContentParser;
-import org.elasticsearch.common.xcontent.XContentParser.Token;
 
-import java.io.IOException;
+import java.util.AbstractMap;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.NavigableMap;
 import java.util.Objects;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
 
 public final class GetAutoFollowPatternResponse {
 
-    public static GetAutoFollowPatternResponse fromXContent(final XContentParser parser) throws IOException {
-        final Map<String, Pattern> patterns = new HashMap<>();
-        for (Token token = parser.nextToken(); token != Token.END_OBJECT; token = parser.nextToken()) {
-            if (token == Token.FIELD_NAME) {
-                final String name = parser.currentName();
-                final Pattern pattern = Pattern.PARSER.parse(parser, null);
-                patterns.put(name, pattern);
-            }
-        }
-        return new GetAutoFollowPatternResponse(patterns);
+    static final ParseField PATTERNS_FIELD = new ParseField("patterns");
+    static final ParseField NAME_FIELD = new ParseField("name");
+    static final ParseField PATTERN_FIELD = new ParseField("pattern");
+
+    private static final ConstructingObjectParser<Map.Entry<String, Pattern>, Void> ENTRY_PARSER = new ConstructingObjectParser<>(
+        "get_auto_follow_pattern_response", args -> new AbstractMap.SimpleEntry<>((String) args[0], (Pattern) args[1]));
+
+    static {
+        ENTRY_PARSER.declareString(ConstructingObjectParser.constructorArg(), NAME_FIELD);
+        ENTRY_PARSER.declareObject(ConstructingObjectParser.constructorArg(), Pattern.PARSER, PATTERN_FIELD);
+    }
+
+    private static final ConstructingObjectParser<GetAutoFollowPatternResponse, Void> PARSER = new ConstructingObjectParser<>(
+        "get_auto_follow_pattern_response", args -> {
+            @SuppressWarnings("unchecked")
+            List<Map.Entry<String, Pattern>> entries = (List<Map.Entry<String, Pattern>>) args[0];
+            return new GetAutoFollowPatternResponse(new TreeMap<>(entries.stream()
+                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))));
+    });
+
+    static {
+        PARSER.declareObjectArray(ConstructingObjectParser.constructorArg(), ENTRY_PARSER, PATTERNS_FIELD);
+    }
+
+    public static GetAutoFollowPatternResponse fromXContent(final XContentParser parser) {
+        return PARSER.apply(parser, null);
     }
 
-    private final Map<String, Pattern> patterns;
+    private final NavigableMap<String, Pattern> patterns;
 
-    GetAutoFollowPatternResponse(Map<String, Pattern> patterns) {
-        this.patterns = Collections.unmodifiableMap(patterns);
+    GetAutoFollowPatternResponse(NavigableMap<String, Pattern> patterns) {
+        this.patterns = Collections.unmodifiableNavigableMap(patterns);
     }
 
-    public Map<String, Pattern> getPatterns() {
+    public NavigableMap<String, Pattern> getPatterns() {
         return patterns;
     }
 

+ 19 - 9
client/rest-high-level/src/test/java/org/elasticsearch/client/ccr/GetAutoFollowPatternResponseTests.java

@@ -27,8 +27,9 @@ import org.elasticsearch.test.ESTestCase;
 
 import java.io.IOException;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.Map;
+import java.util.NavigableMap;
+import java.util.TreeMap;
 
 import static org.elasticsearch.client.ccr.PutAutoFollowPatternRequest.FOLLOW_PATTERN_FIELD;
 import static org.elasticsearch.client.ccr.PutAutoFollowPatternRequest.LEADER_PATTERNS_FIELD;
@@ -48,7 +49,7 @@ public class GetAutoFollowPatternResponseTests extends ESTestCase {
 
     private GetAutoFollowPatternResponse createTestInstance() {
         int numPatterns = randomIntBetween(0, 16);
-        Map<String, GetAutoFollowPatternResponse.Pattern> patterns = new HashMap<>(numPatterns);
+        NavigableMap<String, GetAutoFollowPatternResponse.Pattern> patterns = new TreeMap<>();
         for (int i = 0; i < numPatterns; i++) {
             GetAutoFollowPatternResponse.Pattern pattern = new GetAutoFollowPatternResponse.Pattern(
                 randomAlphaOfLength(4), Collections.singletonList(randomAlphaOfLength(4)), randomAlphaOfLength(4));
@@ -90,17 +91,26 @@ public class GetAutoFollowPatternResponseTests extends ESTestCase {
     public static void toXContent(GetAutoFollowPatternResponse response, XContentBuilder builder) throws IOException {
         builder.startObject();
         {
+            builder.startArray(GetAutoFollowPatternResponse.PATTERNS_FIELD.getPreferredName());
             for (Map.Entry<String, GetAutoFollowPatternResponse.Pattern> entry : response.getPatterns().entrySet()) {
-                builder.startObject(entry.getKey());
-                GetAutoFollowPatternResponse.Pattern pattern = entry.getValue();
-                builder.field(REMOTE_CLUSTER_FIELD.getPreferredName(), pattern.getRemoteCluster());
-                builder.field(LEADER_PATTERNS_FIELD.getPreferredName(), pattern.getLeaderIndexPatterns());
-                if (pattern.getFollowIndexNamePattern()!= null) {
-                    builder.field(FOLLOW_PATTERN_FIELD.getPreferredName(), pattern.getFollowIndexNamePattern());
+                builder.startObject();
+                {
+                    builder.field(GetAutoFollowPatternResponse.NAME_FIELD.getPreferredName(), entry.getKey());
+                    builder.startObject(GetAutoFollowPatternResponse.PATTERN_FIELD.getPreferredName());
+                    {
+                        GetAutoFollowPatternResponse.Pattern pattern = entry.getValue();
+                        builder.field(REMOTE_CLUSTER_FIELD.getPreferredName(), pattern.getRemoteCluster());
+                        builder.field(LEADER_PATTERNS_FIELD.getPreferredName(), pattern.getLeaderIndexPatterns());
+                        if (pattern.getFollowIndexNamePattern()!= null) {
+                            builder.field(FOLLOW_PATTERN_FIELD.getPreferredName(), pattern.getFollowIndexNamePattern());
+                        }
+                        entry.getValue().toXContentFragment(builder, ToXContent.EMPTY_PARAMS);
+                    }
+                    builder.endObject();
                 }
-                entry.getValue().toXContentFragment(builder, ToXContent.EMPTY_PARAMS);
                 builder.endObject();
             }
+            builder.endArray();
         }
         builder.endObject();
     }

+ 13 - 9
docs/reference/ccr/apis/auto-follow/get-auto-follow-pattern.asciidoc

@@ -87,15 +87,19 @@ The API returns the following result:
 [source,js]
 --------------------------------------------------
 {
-  "my_auto_follow_pattern" :
-  {
-    "remote_cluster" : "remote_cluster",
-    "leader_index_patterns" :
-    [
-      "leader_index*"
-    ],
-    "follow_index_pattern" : "{{leader_index}}-follower"
-  }
+  "patterns": [
+    {
+      "name": "my_auto_follow_pattern",
+      "pattern": {
+        "remote_cluster" : "remote_cluster",
+        "leader_index_patterns" :
+        [
+          "leader_index*"
+        ],
+        "follow_index_pattern" : "{{leader_index}}-follower"
+      }
+    }
+  ]
 }
 --------------------------------------------------
 // TESTRESPONSE

+ 8 - 6
x-pack/plugin/ccr/qa/rest/src/test/resources/rest-api-spec/test/ccr/auto_follow.yml

@@ -31,15 +31,17 @@
   - do:
       ccr.get_auto_follow_pattern:
         name: my_pattern
-  - match: { my_pattern.remote_cluster: 'local' }
-  - match: { my_pattern.leader_index_patterns: ['logs-*'] }
-  - match: { my_pattern.max_outstanding_read_requests: 2 }
+  - match: { patterns.0.name: 'my_pattern' }
+  - match: { patterns.0.pattern.remote_cluster: 'local' }
+  - match: { patterns.0.pattern.leader_index_patterns: ['logs-*'] }
+  - match: { patterns.0.pattern.max_outstanding_read_requests: 2 }
 
   - do:
       ccr.get_auto_follow_pattern: {}
-  - match: { my_pattern.remote_cluster: 'local' }
-  - match: { my_pattern.leader_index_patterns: ['logs-*'] }
-  - match: { my_pattern.max_outstanding_read_requests: 2 }
+  - match: { patterns.0.name: 'my_pattern' }
+  - match: { patterns.0.pattern.remote_cluster: 'local' }
+  - match: { patterns.0.pattern.leader_index_patterns: ['logs-*'] }
+  - match: { patterns.0.pattern.max_outstanding_read_requests: 2 }
 
   - do:
       ccr.delete_auto_follow_pattern:

+ 15 - 4
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/GetAutoFollowPatternAction.java

@@ -111,10 +111,21 @@ public class GetAutoFollowPatternAction extends Action<GetAutoFollowPatternActio
         @Override
         public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
             builder.startObject();
-            for (Map.Entry<String, AutoFollowPattern> entry : autoFollowPatterns.entrySet()) {
-                builder.startObject(entry.getKey());
-                entry.getValue().toXContent(builder, params);
-                builder.endObject();
+            {
+                builder.startArray("patterns");
+                for (Map.Entry<String, AutoFollowPattern> entry : autoFollowPatterns.entrySet()) {
+                    builder.startObject();
+                    {
+                        builder.field("name", entry.getKey());
+                        builder.startObject("pattern");
+                        {
+                            entry.getValue().toXContent(builder, params);
+                        }
+                        builder.endObject();
+                    }
+                    builder.endObject();
+                }
+                builder.endArray();
             }
             builder.endObject();
             return builder;