|  | 
|  | 1 | +/* | 
|  | 2 | + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | 
|  | 3 | + * or more contributor license agreements. Licensed under the Elastic License | 
|  | 4 | + * 2.0; you may not use this file except in compliance with the Elastic License | 
|  | 5 | + * 2.0. | 
|  | 6 | + */ | 
|  | 7 | + | 
|  | 8 | +package org.elasticsearch.xpack.remotecluster; | 
|  | 9 | + | 
|  | 10 | +import org.elasticsearch.action.search.SearchResponse; | 
|  | 11 | +import org.elasticsearch.client.Request; | 
|  | 12 | +import org.elasticsearch.client.RequestOptions; | 
|  | 13 | +import org.elasticsearch.client.Response; | 
|  | 14 | +import org.elasticsearch.client.ResponseException; | 
|  | 15 | +import org.elasticsearch.common.xcontent.support.XContentMapValues; | 
|  | 16 | +import org.elasticsearch.core.Tuple; | 
|  | 17 | +import org.elasticsearch.search.SearchHit; | 
|  | 18 | +import org.elasticsearch.search.SearchResponseUtils; | 
|  | 19 | + | 
|  | 20 | +import java.io.IOException; | 
|  | 21 | +import java.util.Arrays; | 
|  | 22 | +import java.util.List; | 
|  | 23 | +import java.util.Map; | 
|  | 24 | +import java.util.stream.Collectors; | 
|  | 25 | + | 
|  | 26 | +import static org.hamcrest.Matchers.containsInAnyOrder; | 
|  | 27 | +import static org.hamcrest.Matchers.containsString; | 
|  | 28 | +import static org.hamcrest.Matchers.equalTo; | 
|  | 29 | + | 
|  | 30 | +abstract class AbstractRemoteClusterSecurityFailureStoreRestIT extends AbstractRemoteClusterSecurityTestCase { | 
|  | 31 | + | 
|  | 32 | +    protected void assertSearchResponseContainsIndices(Response response, String... expectedIndices) throws IOException { | 
|  | 33 | +        assertOK(response); | 
|  | 34 | +        final SearchResponse searchResponse = SearchResponseUtils.parseSearchResponse(responseAsParser(response)); | 
|  | 35 | +        try { | 
|  | 36 | +            final List<String> actualIndices = Arrays.stream(searchResponse.getHits().getHits()) | 
|  | 37 | +                .map(SearchHit::getIndex) | 
|  | 38 | +                .collect(Collectors.toList()); | 
|  | 39 | +            assertThat(actualIndices, containsInAnyOrder(expectedIndices)); | 
|  | 40 | +        } finally { | 
|  | 41 | +            searchResponse.decRef(); | 
|  | 42 | +        } | 
|  | 43 | +    } | 
|  | 44 | + | 
|  | 45 | +    protected void setupTestDataStreamOnFulfillingCluster() throws IOException { | 
|  | 46 | +        // Create data stream and index some documents | 
|  | 47 | +        final Request createComponentTemplate = new Request("PUT", "/_component_template/component1"); | 
|  | 48 | +        createComponentTemplate.setJsonEntity(""" | 
|  | 49 | +            { | 
|  | 50 | +                "template": { | 
|  | 51 | +                    "mappings": { | 
|  | 52 | +                        "properties": { | 
|  | 53 | +                            "@timestamp": { | 
|  | 54 | +                                "type": "date" | 
|  | 55 | +                            }, | 
|  | 56 | +                            "age": { | 
|  | 57 | +                                "type": "integer" | 
|  | 58 | +                            }, | 
|  | 59 | +                            "email": { | 
|  | 60 | +                                "type": "keyword" | 
|  | 61 | +                            }, | 
|  | 62 | +                            "name": { | 
|  | 63 | +                                "type": "text" | 
|  | 64 | +                            } | 
|  | 65 | +                        } | 
|  | 66 | +                    }, | 
|  | 67 | +                    "data_stream_options": { | 
|  | 68 | +                        "failure_store": { | 
|  | 69 | +                            "enabled": true | 
|  | 70 | +                        } | 
|  | 71 | +                    } | 
|  | 72 | +                } | 
|  | 73 | +            }"""); | 
|  | 74 | +        assertOK(performRequestAgainstFulfillingCluster(createComponentTemplate)); | 
|  | 75 | + | 
|  | 76 | +        final Request createTemplate = new Request("PUT", "/_index_template/template1"); | 
|  | 77 | +        createTemplate.setJsonEntity(""" | 
|  | 78 | +            { | 
|  | 79 | +                "index_patterns": ["test*"], | 
|  | 80 | +                "data_stream": {}, | 
|  | 81 | +                "priority": 500, | 
|  | 82 | +                "composed_of": ["component1"] | 
|  | 83 | +            }"""); | 
|  | 84 | +        assertOK(performRequestAgainstFulfillingCluster(createTemplate)); | 
|  | 85 | + | 
|  | 86 | +        final Request createDoc1 = new Request("PUT", "/test1/_doc/1?refresh=true&op_type=create"); | 
|  | 87 | +        createDoc1.setJsonEntity(""" | 
|  | 88 | +            { | 
|  | 89 | +                "@timestamp": 1, | 
|  | 90 | +                "age" : 1, | 
|  | 91 | +                "name" : "jack", | 
|  | 92 | + | 
|  | 93 | +            }"""); | 
|  | 94 | +        assertOK(performRequestAgainstFulfillingCluster(createDoc1)); | 
|  | 95 | + | 
|  | 96 | +        final Request createDoc2 = new Request("PUT", "/test1/_doc/2?refresh=true&op_type=create"); | 
|  | 97 | +        createDoc2.setJsonEntity(""" | 
|  | 98 | +            { | 
|  | 99 | +                "@timestamp": 2, | 
|  | 100 | +                "age" : "this should be an int", | 
|  | 101 | +                "name" : "jack", | 
|  | 102 | + | 
|  | 103 | +            }"""); | 
|  | 104 | +        assertOK(performRequestAgainstFulfillingCluster(createDoc2)); | 
|  | 105 | +        { | 
|  | 106 | +            final Request otherTemplate = new Request("PUT", "/_index_template/other_template"); | 
|  | 107 | +            otherTemplate.setJsonEntity(""" | 
|  | 108 | +                { | 
|  | 109 | +                    "index_patterns": ["other*"], | 
|  | 110 | +                    "data_stream": {}, | 
|  | 111 | +                    "priority": 500, | 
|  | 112 | +                    "composed_of": ["component1"] | 
|  | 113 | +                }"""); | 
|  | 114 | +            assertOK(performRequestAgainstFulfillingCluster(otherTemplate)); | 
|  | 115 | +        } | 
|  | 116 | +        { | 
|  | 117 | +            final Request createOtherDoc3 = new Request("PUT", "/other1/_doc/3?refresh=true&op_type=create"); | 
|  | 118 | +            createOtherDoc3.setJsonEntity(""" | 
|  | 119 | +                { | 
|  | 120 | +                    "@timestamp": 3, | 
|  | 121 | +                    "age" : 3, | 
|  | 122 | +                    "name" : "jane", | 
|  | 123 | + | 
|  | 124 | +                }"""); | 
|  | 125 | +            assertOK(performRequestAgainstFulfillingCluster(createOtherDoc3)); | 
|  | 126 | +        } | 
|  | 127 | +        { | 
|  | 128 | +            final Request createOtherDoc4 = new Request("PUT", "/other1/_doc/4?refresh=true&op_type=create"); | 
|  | 129 | +            createOtherDoc4.setJsonEntity(""" | 
|  | 130 | +                { | 
|  | 131 | +                    "@timestamp": 4, | 
|  | 132 | +                    "age" : "this should be an int", | 
|  | 133 | +                    "name" : "jane", | 
|  | 134 | + | 
|  | 135 | +                }"""); | 
|  | 136 | +            assertOK(performRequestAgainstFulfillingCluster(createOtherDoc4)); | 
|  | 137 | +        } | 
|  | 138 | +    } | 
|  | 139 | + | 
|  | 140 | +    protected Response performRequestWithRemoteSearchUser(final Request request) throws IOException { | 
|  | 141 | +        request.setOptions( | 
|  | 142 | +            RequestOptions.DEFAULT.toBuilder().addHeader("Authorization", headerFromRandomAuthMethod(REMOTE_SEARCH_USER, PASS)) | 
|  | 143 | +        ); | 
|  | 144 | +        return client().performRequest(request); | 
|  | 145 | +    } | 
|  | 146 | + | 
|  | 147 | +    protected Response performRequestWithUser(final String user, final Request request) throws IOException { | 
|  | 148 | +        request.setOptions(RequestOptions.DEFAULT.toBuilder().addHeader("Authorization", headerFromRandomAuthMethod(user, PASS))); | 
|  | 149 | +        return client().performRequest(request); | 
|  | 150 | +    } | 
|  | 151 | + | 
|  | 152 | +    @SuppressWarnings("unchecked") | 
|  | 153 | +    protected Tuple<List<String>, List<String>> getDataAndFailureIndices(String dataStreamName) throws IOException { | 
|  | 154 | +        Request dataStream = new Request("GET", "/_data_stream/" + dataStreamName); | 
|  | 155 | +        Response response = performRequestAgainstFulfillingCluster(dataStream); | 
|  | 156 | +        Map<String, Object> dataStreams = entityAsMap(response); | 
|  | 157 | +        List<String> dataIndexNames = (List<String>) XContentMapValues.extractValue("data_streams.indices.index_name", dataStreams); | 
|  | 158 | +        List<String> failureIndexNames = (List<String>) XContentMapValues.extractValue( | 
|  | 159 | +            "data_streams.failure_store.indices.index_name", | 
|  | 160 | +            dataStreams | 
|  | 161 | +        ); | 
|  | 162 | +        return new Tuple<>(dataIndexNames, failureIndexNames); | 
|  | 163 | +    } | 
|  | 164 | + | 
|  | 165 | +    protected Tuple<String, String> getSingleDataAndFailureIndices(String dataStreamName) throws IOException { | 
|  | 166 | +        Tuple<List<String>, List<String>> indices = getDataAndFailureIndices(dataStreamName); | 
|  | 167 | +        assertThat(indices.v1().size(), equalTo(1)); | 
|  | 168 | +        assertThat(indices.v2().size(), equalTo(1)); | 
|  | 169 | +        return new Tuple<>(indices.v1().get(0), indices.v2().get(0)); | 
|  | 170 | +    } | 
|  | 171 | + | 
|  | 172 | +    protected static void assertSelectorsNotSupported(ResponseException exception) { | 
|  | 173 | +        assertThat(exception.getResponse().getStatusLine().getStatusCode(), equalTo(403)); | 
|  | 174 | +        assertThat(exception.getMessage(), containsString("Selectors are not yet supported on remote cluster patterns")); | 
|  | 175 | +    } | 
|  | 176 | + | 
|  | 177 | +} | 
0 commit comments