Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compat rest api #22

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
28ffe75
minimal and temporary testing for rest api compatibility
jakelandis Mar 3, 2020
f539504
fix NPE and add compat test to temporary fixture
jakelandis Mar 4, 2020
8568434
Merge branch 'master' into compat_rest_api
pgomulka Mar 9, 2020
e5de47b
Fix issues which keep the temporary compat test fixutre (#53301)
jakelandis Mar 10, 2020
163a5aa
Merge branch 'master' into compat_rest_api
pgomulka Mar 16, 2020
878ed12
Compatible version of typed Index And Get API (#53228)
pgomulka Mar 25, 2020
8015944
Merge branch 'master' into compat_rest_api
pgomulka Mar 27, 2020
0fb7f7b
Merge branch 'master' into compat_rest_api
pgomulka Mar 30, 2020
d8a900d
update actions to use supplier for nodes
pgomulka Mar 30, 2020
dae8f7f
Merge branch 'master' into compat_rest_api
pgomulka Apr 3, 2020
36ac271
fix
pgomulka Apr 8, 2020
c9d60c2
Merge branch 'master' into compat_rest_api
pgomulka Apr 9, 2020
abb657e
Merge branch 'master' into compat_rest_api
pgomulka Apr 16, 2020
3b3da9d
Validate Accept and Content-Type header for compatible API (#54103)
pgomulka Apr 20, 2020
3c517b8
Merge branch 'master' into compat_rest_api
pgomulka Apr 21, 2020
144dd89
Merge branch 'master' into compat_rest_api
pgomulka Apr 23, 2020
7f54c45
Merge branch 'master' into compat_rest_api
pgomulka Apr 28, 2020
3a8303e
Compatible logic for include_type_param and RestCreateIndexAction (#5…
pgomulka Apr 28, 2020
04ab109
Merge branch 'master' into compat_rest_api
pgomulka Apr 29, 2020
876b394
Merge branch 'master' into compat_rest_api
pgomulka Apr 29, 2020
a45d278
Merge branch 'master' into compat_rest_api
pgomulka May 28, 2020
9b3b2ea
Merge branch 'master' into compat_rest_api
pgomulka Jun 4, 2020
4a2391f
fix compilation error
pgomulka Jun 5, 2020
4fea8c3
Merge branch 'master' into compat_rest_api
pgomulka Jun 8, 2020
e01df04
temporary fix to data streams to allow compat testing
pgomulka Jun 16, 2020
fb3ca5a
Merge branch 'master' into compat_rest_api
pgomulka Jun 16, 2020
8fbadff
Merge branch 'master' into compat_rest_api
pgomulka Jul 7, 2020
a0a2f63
fix after merge master
pgomulka Jul 7, 2020
edcffb3
Merge branch 'master' into compat_rest_api
pgomulka Jul 8, 2020
c21f493
Merge branch 'master' into compat_rest_api
pgomulka Jul 8, 2020
2df6157
Compatible logic for Removes typed endpoint from search and related A…
pgomulka Jul 14, 2020
9e522ee
Merge branch 'master' into compat_rest_api
pgomulka Jul 14, 2020
cacef33
Validate compatible handlers have correct version (#58304)
pgomulka Jul 14, 2020
e457a92
Compatible Delete and Update rest actions (#58246)
pgomulka Jul 14, 2020
b09bd5a
Mappings get put and get mappings (#58426)
pgomulka Jul 14, 2020
40783d5
draft
pgomulka Jul 15, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1223,7 +1223,7 @@ public void testMultiSearch() throws IOException {
};
MultiSearchRequest.readMultiLineFormat(new BytesArray(EntityUtils.toByteArray(request.getEntity())),
REQUEST_BODY_CONTENT_TYPE.xContent(), consumer, null, multiSearchRequest.indicesOptions(), null, null, null,
xContentRegistry(), true);
xContentRegistry(), true, key -> false);
assertEquals(requests, multiSearchRequest.requests());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public static Iterable<Object[]> parameters() throws Exception {
entries.add(new NamedXContentRegistry.Entry(ExecutableSection.class,
new ParseField("compare_analyzers"), CompareAnalyzers::parse));
NamedXContentRegistry executableSectionRegistry = new NamedXContentRegistry(entries);
return ESClientYamlSuiteTestCase.createParameters(executableSectionRegistry);
return ESClientYamlSuiteTestCase.createParameters(executableSectionRegistry, TESTS_PATH);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ public interface HumanReadableTransformer {
*/
private boolean humanReadable = false;

private byte compatibleMajorVersion;

/**
* Constructs a new builder using the provided XContent and an OutputStream. Make sure
* to call {@link #close()} when the builder is done with.
Expand Down Expand Up @@ -998,6 +1000,16 @@ public XContentBuilder copyCurrentStructure(XContentParser parser) throws IOExce
return this;
}

public XContentBuilder setCompatibleMajorVersion(byte compatibleMajorVersion){
this.compatibleMajorVersion = compatibleMajorVersion;
return this;
}

public byte getCompatibleMajorVersion() {
return compatibleMajorVersion;
}


@Override
public void flush() throws IOException {
generator.flush();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

import java.util.Locale;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* The content type of {@link org.elasticsearch.common.xcontent.XContent}.
Expand Down Expand Up @@ -114,13 +116,19 @@ public XContent xContent() {
}
};

private static final Pattern COMPATIBLE_API_HEADER_PATTERN = Pattern.compile(
"(application|text)/(vnd.elasticsearch\\+)?([^;]+)(\\s*;\\s*compatible-with=(\\d+))?",
Pattern.CASE_INSENSITIVE);

/**
* Accepts either a format string, which is equivalent to {@link XContentType#shortName()} or a media type that optionally has
* parameters and attempts to match the value to an {@link XContentType}. The comparisons are done in lower case format and this method
* also supports a wildcard accept for {@code application/*}. This method can be used to parse the {@code Accept} HTTP header or a
* format query string parameter. This method will return {@code null} if no match is found
*/
public static XContentType fromMediaTypeOrFormat(String mediaType) {
public static XContentType fromMediaTypeOrFormat(String mediaTypeHeaderValue) {
String mediaType = parseMediaType(mediaTypeHeaderValue);

if (mediaType == null) {
return null;
}
Expand All @@ -130,7 +138,7 @@ public static XContentType fromMediaTypeOrFormat(String mediaType) {
}
}
final String lowercaseMediaType = mediaType.toLowerCase(Locale.ROOT);
if (lowercaseMediaType.startsWith("application/*")) {
if (lowercaseMediaType.startsWith("application/*") || lowercaseMediaType.equals("*/*")) {
return JSON;
}

Expand All @@ -142,7 +150,9 @@ public static XContentType fromMediaTypeOrFormat(String mediaType) {
* The provided media type should not include any parameters. This method is suitable for parsing part of the {@code Content-Type}
* HTTP header. This method will return {@code null} if no match is found
*/
public static XContentType fromMediaType(String mediaType) {
public static XContentType fromMediaType(String mediaTypeHeaderValue) {
String mediaType = parseMediaType(mediaTypeHeaderValue);

final String lowercaseMediaType = Objects.requireNonNull(mediaType, "mediaType cannot be null").toLowerCase(Locale.ROOT);
for (XContentType type : values()) {
if (type.mediaTypeWithoutParameters().equals(lowercaseMediaType)) {
Expand All @@ -157,6 +167,28 @@ public static XContentType fromMediaType(String mediaType) {
return null;
}

//public scope needed for text formats hack
public static String parseMediaType(String mediaType) {
if (mediaType != null) {
Matcher matcher = COMPATIBLE_API_HEADER_PATTERN.matcher(mediaType);
if (matcher.find()) {
return (matcher.group(1) + "/" + matcher.group(3)).toLowerCase(Locale.ROOT);
}
}

return mediaType;
}

public static String parseVersion(String mediaType){
if(mediaType != null){
Matcher matcher = COMPATIBLE_API_HEADER_PATTERN.matcher(mediaType);
if (matcher.find() && "vnd.elasticsearch+".equalsIgnoreCase(matcher.group(2))) {

return matcher.group(5);
}
}
return null;
}
private static boolean isSameMediaTypeOrFormatAs(String stringType, XContentType type) {
return type.mediaTypeWithoutParameters().equalsIgnoreCase(stringType) ||
stringType.toLowerCase(Locale.ROOT).startsWith(type.mediaTypeWithoutParameters().toLowerCase(Locale.ROOT) + ";") ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;

import static java.util.Arrays.asList;
import static org.elasticsearch.rest.RestRequest.Method.GET;
Expand All @@ -49,7 +50,7 @@ public class RestMultiSearchTemplateAction extends BaseRestHandler {
}


private final boolean allowExplicitIndex;
protected final boolean allowExplicitIndex;

public RestMultiSearchTemplateAction(Settings settings) {
this.allowExplicitIndex = MULTI_ALLOW_EXPLICIT_INDEX.get(settings);
Expand Down Expand Up @@ -79,6 +80,19 @@ public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client
* Parses a {@link RestRequest} body and returns a {@link MultiSearchTemplateRequest}
*/
public static MultiSearchTemplateRequest parseRequest(RestRequest restRequest, boolean allowExplicitIndex) throws IOException {
return parseRequest(restRequest,allowExplicitIndex, k->false);
}

/**
* Parses a {@link RestRequest} body and returns a {@link MultiSearchTemplateRequest}
* @param typeConsumer - A function used to validate if a provided xContent key is allowed.
* This is useful for xContent compatibility to determine
* if a key is allowed to be present in version agnostic manner.
* The provided function should return false if the key is not allowed.
*/
public static MultiSearchTemplateRequest parseRequest(RestRequest restRequest,
boolean allowExplicitIndex,
Function<String,Boolean> typeConsumer) throws IOException {
MultiSearchTemplateRequest multiRequest = new MultiSearchTemplateRequest();
if (restRequest.hasParam("max_concurrent_searches")) {
multiRequest.maxConcurrentSearchRequests(restRequest.paramAsInt("max_concurrent_searches", 0));
Expand All @@ -94,7 +108,7 @@ public static MultiSearchTemplateRequest parseRequest(RestRequest restRequest, b
throw new IllegalArgumentException("Malformed search template");
}
RestSearchAction.checkRestTotalHits(restRequest, searchRequest);
});
}, typeConsumer);
return multiRequest;
}

Expand Down
31 changes: 31 additions & 0 deletions modules/rest-compatibility/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

esplugin {
description 'Adds a compatiblity layer for the prior major versions REST API'
classname 'org.elasticsearch.compat.RestCompatPlugin'
}

dependencies {
implementation project(':modules:lang-mustache')
implementation project(':modules:reindex')
}

integTest.enabled = false
test.enabled = true
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.elasticsearch.compat;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.IndexScopedSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsFilter;
import org.elasticsearch.index.reindex.RestDeleteByQueryActionV7;
import org.elasticsearch.index.reindex.RestUpdateByQueryActionV7;
import org.elasticsearch.plugins.ActionPlugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestHandler;
import org.elasticsearch.rest.action.admin.indices.RestCreateIndexActionV7;
import org.elasticsearch.rest.action.document.RestDeleteActionV7;
import org.elasticsearch.rest.action.document.RestGetActionV7;
import org.elasticsearch.rest.action.document.RestIndexActionV7;
import org.elasticsearch.rest.action.document.RestMultiTermVectorsActionV7;
import org.elasticsearch.rest.action.document.RestTermVectorsActionV7;
import org.elasticsearch.rest.action.document.RestUpdateActionV7;
import org.elasticsearch.rest.action.search.RestMultiSearchActionV7;
import org.elasticsearch.rest.action.search.RestSearchActionV7;
import org.elasticsearch.script.mustache.RestMultiSearchTemplateActionV7;
import org.elasticsearch.script.mustache.RestSearchTemplateActionV7;

import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.function.Supplier;

public class RestCompatPlugin extends Plugin implements ActionPlugin {
Logger log = LogManager.getLogger(RestCompatPlugin.class);
@Override
public List<RestHandler> getRestHandlers(
Settings settings,
RestController restController,
ClusterSettings clusterSettings,
IndexScopedSettings indexScopedSettings,
SettingsFilter settingsFilter,
IndexNameExpressionResolver indexNameExpressionResolver,
Supplier<DiscoveryNodes> nodesInCluster
) {
boolean compatibilityEnabled = Boolean.parseBoolean(settings.get("compat.setting"));
log.warn(" compat setting "+compatibilityEnabled);
if (compatibilityEnabled && Version.CURRENT.major == 8) {
return validateCompatibleHandlers(
7,
new RestDeleteByQueryActionV7(),
new RestUpdateByQueryActionV7(),
new RestCreateIndexActionV7(),
new RestGetActionV7(),
new RestIndexActionV7.CompatibleRestIndexAction(),
new RestIndexActionV7.CompatibleCreateHandler(),
new RestIndexActionV7.CompatibleAutoIdHandler(nodesInCluster),
new RestTermVectorsActionV7(),
new RestMultiTermVectorsActionV7(),
new RestSearchActionV7(),
new RestMultiSearchActionV7(settings),
new RestSearchTemplateActionV7(),
new RestMultiSearchTemplateActionV7(settings),
new RestDeleteActionV7(),
new RestUpdateActionV7()
);
}
return Collections.emptyList();
}

// default scope for testing
List<RestHandler> validateCompatibleHandlers(int expectedVersion, RestHandler... handlers) {
for (RestHandler handler : handlers) {
if (handler.compatibleWithVersion().major != expectedVersion) {
String msg = String.format(
Locale.ROOT,
"Handler %s is of incorrect version %s.",
handler.getClass().getSimpleName(),
handler.compatibleWithVersion()
);
throw new IllegalStateException(msg);
}
}
return List.of(handlers);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.elasticsearch.compat;

import org.elasticsearch.common.Strings;
import org.elasticsearch.rest.RestRequest;

import java.util.Set;
import java.util.function.Function;

public class TypeConsumer implements Function<String, Boolean> {

private final RestRequest request;
private final Set<String> fieldNames;
private boolean foundTypeInBody = false;

public TypeConsumer(RestRequest request, String... fieldNames) {
this.request = request;
this.fieldNames = Set.of(fieldNames);
}

@Override
public Boolean apply(String fieldName) {
if (fieldNames.contains(fieldName)) {
foundTypeInBody = true;
return true;
}
return false;
}

public boolean hasTypes() {
// TODO can params be types too? or _types?
String[] types = Strings.splitStringByCommaToArray(request.param("type"));
return types.length > 0 || foundTypeInBody;
}
}
Loading