Merge remote-tracking branch 'origin/master'

This commit is contained in:
David Pilato 2016-12-17 08:31:57 +01:00
commit efe5a75d26
27 changed files with 244 additions and 594 deletions

View File

@ -216,7 +216,6 @@
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]bootstrap[/\\]JNANatives.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]bootstrap[/\\]JVMCheck.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]bootstrap[/\\]JarHell.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]bootstrap[/\\]Seccomp.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]bootstrap[/\\]Security.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]client[/\\]ElasticsearchClient.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]client[/\\]FilterClient.java" checks="LineLength" />

View File

@ -310,7 +310,6 @@ import org.elasticsearch.rest.action.search.RestExplainAction;
import org.elasticsearch.rest.action.search.RestMultiSearchAction;
import org.elasticsearch.rest.action.search.RestSearchAction;
import org.elasticsearch.rest.action.search.RestSearchScrollAction;
import org.elasticsearch.rest.action.search.RestSuggestAction;
import org.elasticsearch.threadpool.ThreadPool;
import static java.util.Collections.unmodifiableList;
@ -550,7 +549,6 @@ public class ActionModule extends AbstractModule {
registerRestHandler(handlers, RestMultiGetAction.class);
registerRestHandler(handlers, RestDeleteAction.class);
registerRestHandler(handlers, org.elasticsearch.rest.action.document.RestCountAction.class);
registerRestHandler(handlers, RestSuggestAction.class);
registerRestHandler(handlers, RestTermVectorsAction.class);
registerRestHandler(handlers, RestMultiTermVectorsAction.class);
registerRestHandler(handlers, RestBulkAction.class);

View File

@ -30,11 +30,13 @@ import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.StringHelper;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.Version;
import org.elasticsearch.cli.ExitCodes;
import org.elasticsearch.cli.Terminal;
import org.elasticsearch.cli.UserException;
import org.elasticsearch.common.PidFile;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.inject.CreationException;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.common.logging.LogConfigurator;
import org.elasticsearch.common.logging.Loggers;
@ -56,7 +58,9 @@ import java.net.URISyntaxException;
import java.nio.file.Path;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
/**
@ -93,7 +97,7 @@ final class Bootstrap {
}
/** initialize native resources */
public static void initializeNatives(Path tmpFile, boolean mlockAll, boolean seccomp, boolean ctrlHandler) {
public static void initializeNatives(Path tmpFile, boolean mlockAll, boolean systemCallFilter, boolean ctrlHandler) {
final Logger logger = Loggers.getLogger(Bootstrap.class);
// check if the user is running as root, and bail
@ -101,9 +105,9 @@ final class Bootstrap {
throw new RuntimeException("can not run elasticsearch as root");
}
// enable secure computing mode
if (seccomp) {
Natives.trySeccomp(tmpFile);
// enable system call filter
if (systemCallFilter) {
Natives.tryInstallSystemCallFilter(tmpFile);
}
// mlockall if requested
@ -177,7 +181,7 @@ final class Bootstrap {
initializeNatives(
environment.tmpFile(),
BootstrapSettings.MEMORY_LOCK_SETTING.get(settings),
BootstrapSettings.SECCOMP_SETTING.get(settings),
BootstrapSettings.SYSTEM_CALL_FILTER_SETTING.get(settings),
BootstrapSettings.CTRLHANDLER_SETTING.get(settings));
// initialize probes before the security manager is installed

View File

@ -166,7 +166,7 @@ final class BootstrapChecks {
}
checks.add(new ClientJvmCheck());
checks.add(new UseSerialGCCheck());
checks.add(new SystemCallFilterCheck(BootstrapSettings.SECCOMP_SETTING.get(settings)));
checks.add(new SystemCallFilterCheck(BootstrapSettings.SYSTEM_CALL_FILTER_SETTING.get(settings)));
checks.add(new OnErrorCheck());
checks.add(new OnOutOfMemoryErrorCheck());
checks.add(new G1GCCheck());
@ -463,12 +463,12 @@ final class BootstrapChecks {
@Override
public boolean check() {
return areSystemCallFiltersEnabled && !isSeccompInstalled();
return areSystemCallFiltersEnabled && !isSystemCallFilterInstalled();
}
// visible for testing
boolean isSeccompInstalled() {
return Natives.isSeccompInstalled();
boolean isSystemCallFilterInstalled() {
return Natives.isSystemCallFilterInstalled();
}
@Override
@ -483,12 +483,12 @@ final class BootstrapChecks {
@Override
public boolean check() {
return isSeccompInstalled() && mightFork();
return isSystemCallFilterInstalled() && mightFork();
}
// visible for testing
boolean isSeccompInstalled() {
return Natives.isSeccompInstalled();
boolean isSystemCallFilterInstalled() {
return Natives.isSystemCallFilterInstalled();
}
// visible for testing
@ -521,7 +521,7 @@ final class BootstrapChecks {
"OnError [%s] requires forking but is prevented by system call filters ([%s=true]);" +
" upgrade to at least Java 8u92 and use ExitOnOutOfMemoryError",
onError(),
BootstrapSettings.SECCOMP_SETTING.getKey());
BootstrapSettings.SYSTEM_CALL_FILTER_SETTING.getKey());
}
}
@ -546,7 +546,7 @@ final class BootstrapChecks {
"OnOutOfMemoryError [%s] requires forking but is prevented by system call filters ([%s=true]);" +
" upgrade to at least Java 8u92 and use ExitOnOutOfMemoryError",
onOutOfMemoryError(),
BootstrapSettings.SECCOMP_SETTING.getKey());
BootstrapSettings.SYSTEM_CALL_FILTER_SETTING.getKey());
}
}

View File

@ -24,16 +24,16 @@ import org.elasticsearch.common.SuppressForbidden;
import java.util.Dictionary;
import java.util.Enumeration;
/**
* Exposes system startup information
/**
* Exposes system startup information
*/
@SuppressForbidden(reason = "exposes read-only view of system properties")
public final class BootstrapInfo {
/** no instantiation */
private BootstrapInfo() {}
/**
/**
* Returns true if we successfully loaded native libraries.
* <p>
* If this returns false, then native operations such as locking
@ -42,19 +42,19 @@ public final class BootstrapInfo {
public static boolean isNativesAvailable() {
return Natives.JNA_AVAILABLE;
}
/**
/**
* Returns true if we were able to lock the process's address space.
*/
public static boolean isMemoryLocked() {
return Natives.isMemoryLocked();
}
/**
* Returns true if secure computing mode is enabled (supported systems only)
* Returns true if system call filter is installed (supported systems only)
*/
public static boolean isSeccompInstalled() {
return Natives.isSeccompInstalled();
public static boolean isSystemCallFilterInstalled() {
return Natives.isSystemCallFilterInstalled();
}
/**

View File

@ -33,8 +33,8 @@ public final class BootstrapSettings {
public static final Setting<Boolean> MEMORY_LOCK_SETTING =
Setting.boolSetting("bootstrap.memory_lock", false, Property.NodeScope);
public static final Setting<Boolean> SECCOMP_SETTING =
Setting.boolSetting("bootstrap.seccomp", true, Property.NodeScope);
public static final Setting<Boolean> SYSTEM_CALL_FILTER_SETTING =
Setting.boolSetting("bootstrap.system_call_filter", true, Property.NodeScope);
public static final Setting<Boolean> CTRLHANDLER_SETTING =
Setting.boolSetting("bootstrap.ctrlhandler", true, Property.NodeScope);

View File

@ -43,11 +43,11 @@ class JNANatives {
// Set to true, in case native mlockall call was successful
static boolean LOCAL_MLOCKALL = false;
// Set to true, in case native seccomp call was successful
static boolean LOCAL_SECCOMP = false;
// Set to true, in case native system call filter install was successful
static boolean LOCAL_SYSTEM_CALL_FILTER = false;
// Set to true, in case policy can be applied to all threads of the process (even existing ones)
// otherwise they are only inherited for new threads (ES app threads)
static boolean LOCAL_SECCOMP_ALL = false;
static boolean LOCAL_SYSTEM_CALL_FILTER_ALL = false;
// set to the maximum number of threads that can be created for
// the user ID that owns the running Elasticsearch process
static long MAX_NUMBER_OF_THREADS = -1;
@ -210,12 +210,12 @@ class JNANatives {
}
}
static void trySeccomp(Path tmpFile) {
static void tryInstallSystemCallFilter(Path tmpFile) {
try {
int ret = Seccomp.init(tmpFile);
LOCAL_SECCOMP = true;
int ret = SystemCallFilter.init(tmpFile);
LOCAL_SYSTEM_CALL_FILTER = true;
if (ret == 1) {
LOCAL_SECCOMP_ALL = true;
LOCAL_SYSTEM_CALL_FILTER_ALL = true;
}
} catch (Exception e) {
// this is likely to happen unless the kernel is newish, its a best effort at the moment

View File

@ -91,12 +91,12 @@ final class Natives {
return JNANatives.LOCAL_MLOCKALL;
}
static void trySeccomp(Path tmpFile) {
static void tryInstallSystemCallFilter(Path tmpFile) {
if (!JNA_AVAILABLE) {
logger.warn("cannot install syscall filters because JNA is not available");
logger.warn("cannot install system call filter because JNA is not available");
return;
}
JNANatives.trySeccomp(tmpFile);
JNANatives.tryInstallSystemCallFilter(tmpFile);
}
static void trySetMaxNumberOfThreads() {
@ -115,10 +115,10 @@ final class Natives {
JNANatives.trySetMaxSizeVirtualMemory();
}
static boolean isSeccompInstalled() {
static boolean isSystemCallFilterInstalled() {
if (!JNA_AVAILABLE) {
return false;
}
return JNANatives.LOCAL_SECCOMP;
return JNANatives.LOCAL_SYSTEM_CALL_FILTER;
}
}

View File

@ -34,7 +34,7 @@ import java.util.List;
import java.util.Locale;
/**
* Spawns native plugin controller processes if present. Will only work prior to seccomp being set up.
* Spawns native plugin controller processes if present. Will only work prior to a system call filter being installed.
*/
final class Spawner implements Closeable {

View File

@ -43,8 +43,7 @@ import java.util.List;
import java.util.Map;
/**
* Installs a limited form of secure computing mode,
* to filters system calls to block process execution.
* Installs a system call filter to block process execution.
* <p>
* This is supported on Linux, Solaris, FreeBSD, OpenBSD, Mac OS X, and Windows.
* <p>
@ -91,8 +90,8 @@ import java.util.Map;
* https://docs.oracle.com/cd/E23824_01/html/821-1456/prbac-2.html</a>
*/
// not an example of how to write code!!!
final class Seccomp {
private static final Logger logger = Loggers.getLogger(Seccomp.class);
final class SystemCallFilter {
private static final Logger logger = Loggers.getLogger(SystemCallFilter.class);
// Linux implementation, based on seccomp(2) or prctl(2) with bpf filtering
@ -269,7 +268,8 @@ final class Seccomp {
// we couldn't link methods, could be some really ancient kernel (e.g. < 2.1.57) or some bug
if (linux_libc == null) {
throw new UnsupportedOperationException("seccomp unavailable: could not link methods. requires kernel 3.5+ with CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER compiled in");
throw new UnsupportedOperationException("seccomp unavailable: could not link methods. requires kernel 3.5+ " +
"with CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER compiled in");
}
// pure paranoia:
@ -319,7 +319,8 @@ final class Seccomp {
switch (errno) {
case ENOSYS: break; // ok
case EINVAL: break; // ok
default: throw new UnsupportedOperationException("seccomp(SECCOMP_SET_MODE_FILTER, BOGUS_FLAG): " + JNACLibrary.strerror(errno));
default: throw new UnsupportedOperationException("seccomp(SECCOMP_SET_MODE_FILTER, BOGUS_FLAG): "
+ JNACLibrary.strerror(errno));
}
}
@ -346,7 +347,8 @@ final class Seccomp {
int errno = Native.getLastError();
if (errno == EINVAL) {
// friendly error, this will be the typical case for an old kernel
throw new UnsupportedOperationException("seccomp unavailable: requires kernel 3.5+ with CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER compiled in");
throw new UnsupportedOperationException("seccomp unavailable: requires kernel 3.5+ with" +
" CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER compiled in");
} else {
throw new UnsupportedOperationException("prctl(PR_GET_NO_NEW_PRIVS): " + JNACLibrary.strerror(errno));
}
@ -358,7 +360,8 @@ final class Seccomp {
default:
int errno = Native.getLastError();
if (errno == EINVAL) {
throw new UnsupportedOperationException("seccomp unavailable: CONFIG_SECCOMP not compiled into kernel, CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER are needed");
throw new UnsupportedOperationException("seccomp unavailable: CONFIG_SECCOMP not compiled into kernel," +
" CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER are needed");
} else {
throw new UnsupportedOperationException("prctl(PR_GET_SECCOMP): " + JNACLibrary.strerror(errno));
}
@ -368,7 +371,8 @@ final class Seccomp {
int errno = Native.getLastError();
switch (errno) {
case EFAULT: break; // available
case EINVAL: throw new UnsupportedOperationException("seccomp unavailable: CONFIG_SECCOMP_FILTER not compiled into kernel, CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER are needed");
case EINVAL: throw new UnsupportedOperationException("seccomp unavailable: CONFIG_SECCOMP_FILTER not" +
" compiled into kernel, CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER are needed");
default: throw new UnsupportedOperationException("prctl(PR_SET_SECCOMP): " + JNACLibrary.strerror(errno));
}
}
@ -380,10 +384,12 @@ final class Seccomp {
// check it worked
if (linux_prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) != 1) {
throw new UnsupportedOperationException("seccomp filter did not really succeed: prctl(PR_GET_NO_NEW_PRIVS): " + JNACLibrary.strerror(Native.getLastError()));
throw new UnsupportedOperationException("seccomp filter did not really succeed: prctl(PR_GET_NO_NEW_PRIVS): " +
JNACLibrary.strerror(Native.getLastError()));
}
// BPF installed to check arch, limit, then syscall. See https://www.kernel.org/doc/Documentation/prctl/seccomp_filter.txt for details.
// BPF installed to check arch, limit, then syscall.
// See https://www.kernel.org/doc/Documentation/prctl/seccomp_filter.txt for details.
SockFilter insns[] = {
/* 1 */ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, SECCOMP_DATA_ARCH_OFFSET), //
/* 2 */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arch.audit, 0, 7), // if (arch != audit) goto fail;
@ -408,7 +414,8 @@ final class Seccomp {
method = 0;
int errno1 = Native.getLastError();
if (logger.isDebugEnabled()) {
logger.debug("seccomp(SECCOMP_SET_MODE_FILTER): {}, falling back to prctl(PR_SET_SECCOMP)...", JNACLibrary.strerror(errno1));
logger.debug("seccomp(SECCOMP_SET_MODE_FILTER): {}, falling back to prctl(PR_SET_SECCOMP)...",
JNACLibrary.strerror(errno1));
}
if (linux_prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, pointer, 0, 0) != 0) {
int errno2 = Native.getLastError();
@ -419,7 +426,8 @@ final class Seccomp {
// now check that the filter was really installed, we should be in filter mode.
if (linux_prctl(PR_GET_SECCOMP, 0, 0, 0, 0) != 2) {
throw new UnsupportedOperationException("seccomp filter installation did not really succeed. seccomp(PR_GET_SECCOMP): " + JNACLibrary.strerror(Native.getLastError()));
throw new UnsupportedOperationException("seccomp filter installation did not really succeed. seccomp(PR_GET_SECCOMP): "
+ JNACLibrary.strerror(Native.getLastError()));
}
logger.debug("Linux seccomp filter installation successful, threads: [{}]", method == 1 ? "all" : "app" );

View File

@ -390,7 +390,7 @@ public final class ClusterSettings extends AbstractScopedSettings {
PluginsService.MANDATORY_SETTING,
BootstrapSettings.SECURITY_FILTER_BAD_DEFAULTS_SETTING,
BootstrapSettings.MEMORY_LOCK_SETTING,
BootstrapSettings.SECCOMP_SETTING,
BootstrapSettings.SYSTEM_CALL_FILTER_SETTING,
BootstrapSettings.CTRLHANDLER_SETTING,
IndexingMemoryController.INDEX_BUFFER_SIZE_SETTING,
IndexingMemoryController.MIN_INDEX_BUFFER_SIZE_SETTING,

View File

@ -141,7 +141,12 @@ public class XContentFactory {
/**
* Guesses the content type based on the provided char sequence.
*
* @deprecated the content type should not be guessed except for few cases where we effectively don't know the content type.
* The REST layer should move to reading the Content-Type header instead. There are other places where auto-detection may be needed.
* This method is deprecated to prevent usages of it from spreading further without specific reasons.
*/
@Deprecated
public static XContentType xContentType(CharSequence content) {
int length = content.length() < GUESS_HEADER_LENGTH ? content.length() : GUESS_HEADER_LENGTH;
if (length == 0) {
@ -174,8 +179,13 @@ public class XContentFactory {
}
/**
* Guesses the content (type) based on the provided char sequence.
* Guesses the content (type) based on the provided char sequence and returns the corresponding {@link XContent}
*
* @deprecated the content type should not be guessed except for few cases where we effectively don't know the content type.
* The REST layer should move to reading the Content-Type header instead. There are other places where auto-detection may be needed.
* This method is deprecated to prevent usages of it from spreading further without specific reasons.
*/
@Deprecated
public static XContent xContent(CharSequence content) {
XContentType type = xContentType(content);
if (type == null) {
@ -185,15 +195,24 @@ public class XContentFactory {
}
/**
* Guesses the content type based on the provided bytes.
* Guesses the content type based on the provided bytes and returns the corresponding {@link XContent}
*
* @deprecated the content type should not be guessed except for few cases where we effectively don't know the content type.
* The REST layer should move to reading the Content-Type header instead. There are other places where auto-detection may be needed.
* This method is deprecated to prevent usages of it from spreading further without specific reasons.
*/
@Deprecated
public static XContent xContent(byte[] data) {
return xContent(data, 0, data.length);
}
/**
* Guesses the content type based on the provided bytes.
* Guesses the content type based on the provided bytes and returns the corresponding {@link XContent}
*
* @deprecated guessing the content type should not be needed ideally. We should rather know the content type upfront or read it
* from headers. Till we fixed the REST layer to read the Content-Type header, that should be the only place where guessing is needed.
*/
@Deprecated
public static XContent xContent(byte[] data, int offset, int length) {
XContentType type = xContentType(data, offset, length);
if (type == null) {
@ -204,14 +223,24 @@ public class XContentFactory {
/**
* Guesses the content type based on the provided bytes.
*
* @deprecated the content type should not be guessed except for few cases where we effectively don't know the content type.
* The REST layer should move to reading the Content-Type header instead. There are other places where auto-detection may be needed.
* This method is deprecated to prevent usages of it from spreading further without specific reasons.
*/
@Deprecated
public static XContentType xContentType(byte[] data) {
return xContentType(data, 0, data.length);
}
/**
* Guesses the content type based on the provided input stream without consuming it.
*
* @deprecated the content type should not be guessed except for few cases where we effectively don't know the content type.
* The REST layer should move to reading the Content-Type header instead. There are other places where auto-detection may be needed.
* This method is deprecated to prevent usages of it from spreading further without specific reasons.
*/
@Deprecated
public static XContentType xContentType(InputStream si) throws IOException {
if (si.markSupported() == false) {
throw new IllegalArgumentException("Cannot guess the xcontent type without mark/reset support on " + si.getClass());
@ -228,11 +257,24 @@ public class XContentFactory {
/**
* Guesses the content type based on the provided bytes.
*
* @deprecated the content type should not be guessed except for few cases where we effectively don't know the content type.
* The REST layer should move to reading the Content-Type header instead. There are other places where auto-detection may be needed.
* This method is deprecated to prevent usages of it from spreading further without specific reasons.
*/
@Deprecated
public static XContentType xContentType(byte[] data, int offset, int length) {
return xContentType(new BytesArray(data, offset, length));
}
/**
* Guesses the content type based on the provided bytes and returns the corresponding {@link XContent}
*
* @deprecated the content type should not be guessed except for few cases where we effectively don't know the content type.
* The REST layer should move to reading the Content-Type header instead. There are other places where auto-detection may be needed.
* This method is deprecated to prevent usages of it from spreading further without specific reasons.
*/
@Deprecated
public static XContent xContent(BytesReference bytes) {
XContentType type = xContentType(bytes);
if (type == null) {
@ -243,7 +285,12 @@ public class XContentFactory {
/**
* Guesses the content type based on the provided bytes.
*
* @deprecated the content type should not be guessed except for few cases where we effectively don't know the content type.
* The REST layer should move to reading the Content-Type header instead. There are other places where auto-detection may be needed.
* This method is deprecated to prevent usages of it from spreading further without specific reasons.
*/
@Deprecated
public static XContentType xContentType(BytesReference bytes) {
int length = bytes.length();
if (length == 0) {

View File

@ -1,97 +0,0 @@
/*
* 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.rest.action.search;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.BytesRestResponse;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.RestBuilderListener;
import org.elasticsearch.search.SearchRequestParsers;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import java.io.IOException;
import static org.elasticsearch.rest.RestRequest.Method.GET;
import static org.elasticsearch.rest.RestRequest.Method.POST;
import static org.elasticsearch.rest.action.RestActions.buildBroadcastShardsHeader;
public class RestSuggestAction extends BaseRestHandler {
private final SearchRequestParsers searchRequestParsers;
@Inject
public RestSuggestAction(Settings settings, RestController controller,
SearchRequestParsers searchRequestParsers) {
super(settings);
this.searchRequestParsers = searchRequestParsers;
controller.registerAsDeprecatedHandler(POST, "/_suggest", this,
"[POST /_suggest] is deprecated! Use [POST /_search] instead.", deprecationLogger);
controller.registerAsDeprecatedHandler(GET, "/_suggest", this,
"[GET /_suggest] is deprecated! Use [GET /_search] instead.", deprecationLogger);
controller.registerAsDeprecatedHandler(POST, "/{index}/_suggest", this,
"[POST /{index}/_suggest] is deprecated! Use [POST /{index}/_search] instead.", deprecationLogger);
controller.registerAsDeprecatedHandler(GET, "/{index}/_suggest", this,
"[GET /{index}/_suggest] is deprecated! Use [GET /{index}/_search] instead.", deprecationLogger);
}
@Override
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
final SearchRequest searchRequest = new SearchRequest(
Strings.splitStringByCommaToArray(request.param("index")), new SearchSourceBuilder());
searchRequest.indicesOptions(IndicesOptions.fromRequest(request, searchRequest.indicesOptions()));
try (XContentParser parser = request.contentOrSourceParamParser()) {
final QueryParseContext context = new QueryParseContext(searchRequestParsers.queryParsers, parser, parseFieldMatcher);
searchRequest.source().suggest(SuggestBuilder.fromXContent(context, searchRequestParsers.suggesters));
}
searchRequest.routing(request.param("routing"));
searchRequest.preference(request.param("preference"));
return channel -> client.search(searchRequest, new RestBuilderListener<SearchResponse>(channel) {
@Override
public RestResponse buildResponse(SearchResponse response, XContentBuilder builder) throws Exception {
RestStatus restStatus = RestStatus.status(response.getSuccessfulShards(),
response.getTotalShards(), response.getShardFailures());
builder.startObject();
buildBroadcastShardsHeader(builder, request, response.getTotalShards(),
response.getSuccessfulShards(), response.getFailedShards(), response.getShardFailures());
Suggest suggest = response.getSuggest();
if (suggest != null) {
suggest.toInnerXContent(builder, request);
}
builder.endObject();
return new BytesRestResponse(restStatus, builder);
}
});
}
}

View File

@ -150,18 +150,10 @@ public class Suggest implements Iterable<Suggest.Suggestion<? extends Entry<? ex
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(NAME);
toInnerXContent(builder, params);
builder.endObject();
return builder;
}
/**
* use to write suggestion entries without <code>NAME</code> object
*/
public XContentBuilder toInnerXContent(XContentBuilder builder, Params params) throws IOException {
for (Suggestion<?> suggestion : suggestions) {
suggestion.toXContent(builder, params);
}
builder.endObject();
return builder;
}

View File

@ -409,11 +409,11 @@ public class BootstrapCheckTests extends ESTestCase {
}
public void testSystemCallFilterCheck() throws NodeValidationException {
final AtomicBoolean isSecompInstalled = new AtomicBoolean();
final AtomicBoolean isSystemCallFilterInstalled = new AtomicBoolean();
final BootstrapChecks.SystemCallFilterCheck systemCallFilterEnabledCheck = new BootstrapChecks.SystemCallFilterCheck(true) {
@Override
boolean isSeccompInstalled() {
return isSecompInstalled.get();
boolean isSystemCallFilterInstalled() {
return isSystemCallFilterInstalled.get();
}
};
@ -425,28 +425,28 @@ public class BootstrapCheckTests extends ESTestCase {
containsString("system call filters failed to install; " +
"check the logs and fix your configuration or disable system call filters at your own risk"));
isSecompInstalled.set(true);
isSystemCallFilterInstalled.set(true);
BootstrapChecks.check(true, Collections.singletonList(systemCallFilterEnabledCheck), "testSystemCallFilterCheck");
final BootstrapChecks.SystemCallFilterCheck systemCallFilterNotEnabledCheck = new BootstrapChecks.SystemCallFilterCheck(false) {
@Override
boolean isSeccompInstalled() {
return isSecompInstalled.get();
boolean isSystemCallFilterInstalled() {
return isSystemCallFilterInstalled.get();
}
};
isSecompInstalled.set(false);
isSystemCallFilterInstalled.set(false);
BootstrapChecks.check(true, Collections.singletonList(systemCallFilterNotEnabledCheck), "testSystemCallFilterCheck");
isSecompInstalled.set(true);
isSystemCallFilterInstalled.set(true);
BootstrapChecks.check(true, Collections.singletonList(systemCallFilterNotEnabledCheck), "testSystemCallFilterCheck");
}
public void testMightForkCheck() throws NodeValidationException {
final AtomicBoolean isSeccompInstalled = new AtomicBoolean();
final AtomicBoolean isSystemCallFilterInstalled = new AtomicBoolean();
final AtomicBoolean mightFork = new AtomicBoolean();
final BootstrapChecks.MightForkCheck check = new BootstrapChecks.MightForkCheck() {
@Override
boolean isSeccompInstalled() {
return isSeccompInstalled.get();
boolean isSystemCallFilterInstalled() {
return isSystemCallFilterInstalled.get();
}
@Override
@ -462,19 +462,19 @@ public class BootstrapCheckTests extends ESTestCase {
runMightForkTest(
check,
isSeccompInstalled,
isSystemCallFilterInstalled,
() -> mightFork.set(false),
() -> mightFork.set(true),
e -> assertThat(e.getMessage(), containsString("error")));
}
public void testOnErrorCheck() throws NodeValidationException {
final AtomicBoolean isSeccompInstalled = new AtomicBoolean();
final AtomicBoolean isSystemCallFilterInstalled = new AtomicBoolean();
final AtomicReference<String> onError = new AtomicReference<>();
final BootstrapChecks.MightForkCheck check = new BootstrapChecks.OnErrorCheck() {
@Override
boolean isSeccompInstalled() {
return isSeccompInstalled.get();
boolean isSystemCallFilterInstalled() {
return isSystemCallFilterInstalled.get();
}
@Override
@ -486,23 +486,23 @@ public class BootstrapCheckTests extends ESTestCase {
final String command = randomAsciiOfLength(16);
runMightForkTest(
check,
isSeccompInstalled,
isSystemCallFilterInstalled,
() -> onError.set(randomBoolean() ? "" : null),
() -> onError.set(command),
e -> assertThat(
e.getMessage(),
containsString(
"OnError [" + command + "] requires forking but is prevented by system call filters ([bootstrap.seccomp=true]);"
+ " upgrade to at least Java 8u92 and use ExitOnOutOfMemoryError")));
"OnError [" + command + "] requires forking but is prevented by system call filters " +
"([bootstrap.system_call_filter=true]); upgrade to at least Java 8u92 and use ExitOnOutOfMemoryError")));
}
public void testOnOutOfMemoryErrorCheck() throws NodeValidationException {
final AtomicBoolean isSeccompInstalled = new AtomicBoolean();
final AtomicBoolean isSystemCallFilterInstalled = new AtomicBoolean();
final AtomicReference<String> onOutOfMemoryError = new AtomicReference<>();
final BootstrapChecks.MightForkCheck check = new BootstrapChecks.OnOutOfMemoryErrorCheck() {
@Override
boolean isSeccompInstalled() {
return isSeccompInstalled.get();
boolean isSystemCallFilterInstalled() {
return isSystemCallFilterInstalled.get();
}
@Override
@ -514,28 +514,28 @@ public class BootstrapCheckTests extends ESTestCase {
final String command = randomAsciiOfLength(16);
runMightForkTest(
check,
isSeccompInstalled,
isSystemCallFilterInstalled,
() -> onOutOfMemoryError.set(randomBoolean() ? "" : null),
() -> onOutOfMemoryError.set(command),
e -> assertThat(
e.getMessage(),
containsString(
"OnOutOfMemoryError [" + command + "]"
+ " requires forking but is prevented by system call filters ([bootstrap.seccomp=true]);"
+ " requires forking but is prevented by system call filters ([bootstrap.system_call_filter=true]);"
+ " upgrade to at least Java 8u92 and use ExitOnOutOfMemoryError")));
}
private void runMightForkTest(
final BootstrapChecks.MightForkCheck check,
final AtomicBoolean isSeccompInstalled,
final AtomicBoolean isSystemCallFilterInstalled,
final Runnable disableMightFork,
final Runnable enableMightFork,
final Consumer<NodeValidationException> consumer) throws NodeValidationException {
final String methodName = Thread.currentThread().getStackTrace()[2].getMethodName();
// if seccomp is disabled, nothing should happen
isSeccompInstalled.set(false);
// if system call filter is disabled, nothing should happen
isSystemCallFilterInstalled.set(false);
if (randomBoolean()) {
disableMightFork.run();
} else {
@ -543,16 +543,15 @@ public class BootstrapCheckTests extends ESTestCase {
}
BootstrapChecks.check(true, Collections.singletonList(check), methodName);
// if seccomp is enabled, but we will not fork, nothing should
// if system call filter is enabled, but we will not fork, nothing should
// happen
isSeccompInstalled.set(true);
isSystemCallFilterInstalled.set(true);
disableMightFork.run();
BootstrapChecks.check(true, Collections.singletonList(check), methodName);
// if seccomp is enabled, and we might fork, the check should
// be enforced, regardless of bootstrap checks being enabled or
// not
isSeccompInstalled.set(true);
// if system call filter is enabled, and we might fork, the check should be enforced, regardless of bootstrap checks being enabled
// or not
isSystemCallFilterInstalled.set(true);
enableMightFork.run();
final NodeValidationException e = expectThrows(

View File

@ -27,7 +27,7 @@ public class BootstrapSettingsTests extends ESTestCase {
public void testDefaultSettings() {
assertTrue(BootstrapSettings.SECURITY_FILTER_BAD_DEFAULTS_SETTING.get(Settings.EMPTY));
assertFalse(BootstrapSettings.MEMORY_LOCK_SETTING.get(Settings.EMPTY));
assertTrue(BootstrapSettings.SECCOMP_SETTING.get(Settings.EMPTY));
assertTrue(BootstrapSettings.SYSTEM_CALL_FILTER_SETTING.get(Settings.EMPTY));
assertTrue(BootstrapSettings.CTRLHANDLER_SETTING.get(Settings.EMPTY));
}

View File

@ -25,7 +25,7 @@ import org.elasticsearch.test.ESTestCase;
import java.util.Locale;
/**
* Doesn't actually test spawning a process, as seccomp is installed before tests run and forbids it.
* Doesn't actually test spawning a process, as a system call filter is installed before tests run and forbids it.
*/
public class SpawnerTests extends ESTestCase {
@ -48,4 +48,5 @@ public class SpawnerTests extends ESTestCase {
assertEquals("windows-x86_64", Spawner.makePlatformName("Windows 8.1", "amd64"));
assertEquals("sunos-x86_64", Spawner.makePlatformName("SunOS", "amd64"));
}
}

View File

@ -1473,6 +1473,7 @@ Converts a JSON string into a structured JSON object.
| Name | Required | Default | Description
| `field` | yes | - | The field to be parsed
| `target_field` | no | `field` | The field to insert the converted structured object into
| `add_to_root` | no | false | Flag that forces the serialized json to be injected into the top level of the document. `target_field` must not be set when this option is chosen.
|======
[source,js]

View File

@ -156,7 +156,7 @@ The system call filter check ensures that if system call filters are enabled,
then they were successfully installed. To pass the system call filter check you
must either fix any configuration errors on your system that prevented system
call filters from installing (check your logs), or *at your own risk* disable
system call filters by setting `bootstrap.seccomp` to `false`.
system call filters by setting `bootstrap.system_call_filter` to `false`.
=== OnError and OnOutOfMemoryError checks

View File

@ -28,6 +28,8 @@ import org.elasticsearch.ingest.Processor;
import java.util.Map;
import static org.elasticsearch.ingest.ConfigurationUtils.newConfigurationException;
/**
* Processor that serializes a string-valued field into a
* map of maps.
@ -38,11 +40,13 @@ public final class JsonProcessor extends AbstractProcessor {
private final String field;
private final String targetField;
private final boolean addToRoot;
JsonProcessor(String tag, String field, String targetField) {
JsonProcessor(String tag, String field, String targetField, boolean addToRoot) {
super(tag);
this.field = field;
this.targetField = targetField;
this.addToRoot = addToRoot;
}
public String getField() {
@ -53,12 +57,22 @@ public final class JsonProcessor extends AbstractProcessor {
return targetField;
}
boolean isAddToRoot() {
return addToRoot;
}
@Override
public void execute(IngestDocument document) throws Exception {
String stringValue = document.getFieldValue(field, String.class);
try {
Map<String, Object> mapValue = JsonXContent.jsonXContent.createParser(stringValue).map();
document.setFieldValue(targetField, mapValue);
if (addToRoot) {
for (Map.Entry<String, Object> entry : mapValue.entrySet()) {
document.setFieldValue(entry.getKey(), entry.getValue());
}
} else {
document.setFieldValue(targetField, mapValue);
}
} catch (JsonParseException e) {
throw new IllegalArgumentException(e);
}
@ -74,8 +88,19 @@ public final class JsonProcessor extends AbstractProcessor {
public JsonProcessor create(Map<String, Processor.Factory> registry, String processorTag,
Map<String, Object> config) throws Exception {
String field = ConfigurationUtils.readStringProperty(TYPE, processorTag, config, "field");
String targetField = ConfigurationUtils.readStringProperty(TYPE, processorTag, config, "target_field", field);
return new JsonProcessor(processorTag, field, targetField);
String targetField = ConfigurationUtils.readOptionalStringProperty(TYPE, processorTag, config, "target_field");
boolean addToRoot = ConfigurationUtils.readBooleanProperty(TYPE, processorTag, config, "add_to_root", false);
if (addToRoot && targetField != null) {
throw newConfigurationException(TYPE, processorTag, "target_field",
"Cannot set a target field while also setting `add_to_root` to true");
}
if (targetField == null) {
targetField = field;
}
return new JsonProcessor(processorTag, field, targetField, addToRoot);
}
}
}

View File

@ -48,6 +48,19 @@ public class JsonProcessorFactoryTests extends ESTestCase {
assertThat(jsonProcessor.getTargetField(), equalTo(randomTargetField));
}
public void testCreateWithAddToRoot() throws Exception {
String processorTag = randomAsciiOfLength(10);
String randomField = randomAsciiOfLength(10);
Map<String, Object> config = new HashMap<>();
config.put("field", randomField);
config.put("add_to_root", true);
JsonProcessor jsonProcessor = FACTORY.create(null, processorTag, config);
assertThat(jsonProcessor.getTag(), equalTo(processorTag));
assertThat(jsonProcessor.getField(), equalTo(randomField));
assertThat(jsonProcessor.getTargetField(), equalTo(randomField));
assertTrue(jsonProcessor.isAddToRoot());
}
public void testCreateWithDefaultTarget() throws Exception {
String processorTag = randomAsciiOfLength(10);
String randomField = randomAsciiOfLength(10);
@ -66,4 +79,16 @@ public class JsonProcessorFactoryTests extends ESTestCase {
() -> FACTORY.create(null, processorTag, config));
assertThat(exception.getMessage(), equalTo("[field] required property is missing"));
}
public void testCreateWithBothTargetFieldAndAddToRoot() throws Exception {
String randomField = randomAsciiOfLength(10);
String randomTargetField = randomAsciiOfLength(5);
Map<String, Object> config = new HashMap<>();
config.put("field", randomField);
config.put("target_field", randomTargetField);
config.put("add_to_root", true);
ElasticsearchException exception = expectThrows(ElasticsearchParseException.class,
() -> FACTORY.create(null, randomAsciiOfLength(10), config));
assertThat(exception.getMessage(), equalTo("[target_field] Cannot set a target field while also setting `add_to_root` to true"));
}
}

View File

@ -39,7 +39,7 @@ public class JsonProcessorTests extends ESTestCase {
String processorTag = randomAsciiOfLength(3);
String randomField = randomAsciiOfLength(3);
String randomTargetField = randomAsciiOfLength(2);
JsonProcessor jsonProcessor = new JsonProcessor(processorTag, randomField, randomTargetField);
JsonProcessor jsonProcessor = new JsonProcessor(processorTag, randomField, randomTargetField, false);
Map<String, Object> document = new HashMap<>();
Map<String, Object> randomJsonMap = RandomDocumentPicks.randomSource(random());
@ -54,7 +54,7 @@ public class JsonProcessorTests extends ESTestCase {
}
public void testInvalidJson() {
JsonProcessor jsonProcessor = new JsonProcessor("tag", "field", "target_field");
JsonProcessor jsonProcessor = new JsonProcessor("tag", "field", "target_field", false);
Map<String, Object> document = new HashMap<>();
document.put("field", "invalid json");
IngestDocument ingestDocument = RandomDocumentPicks.randomIngestDocument(random(), document);
@ -66,11 +66,34 @@ public class JsonProcessorTests extends ESTestCase {
}
public void testFieldMissing() {
JsonProcessor jsonProcessor = new JsonProcessor("tag", "field", "target_field");
JsonProcessor jsonProcessor = new JsonProcessor("tag", "field", "target_field", false);
Map<String, Object> document = new HashMap<>();
IngestDocument ingestDocument = RandomDocumentPicks.randomIngestDocument(random(), document);
Exception exception = expectThrows(IllegalArgumentException.class, () -> jsonProcessor.execute(ingestDocument));
assertThat(exception.getMessage(), equalTo("field [field] not present as part of path [field]"));
}
@SuppressWarnings("unchecked")
public void testAddToRoot() throws Exception {
String processorTag = randomAsciiOfLength(3);
String randomTargetField = randomAsciiOfLength(2);
JsonProcessor jsonProcessor = new JsonProcessor(processorTag, "a", randomTargetField, true);
Map<String, Object> document = new HashMap<>();
String json = "{\"a\": 1, \"b\": 2}";
document.put("a", json);
document.put("c", "see");
IngestDocument ingestDocument = RandomDocumentPicks.randomIngestDocument(random(), document);
jsonProcessor.execute(ingestDocument);
Map<String, Object> expected = new HashMap<>();
expected.put("a", 1);
expected.put("b", 2);
expected.put("c", "see");
IngestDocument expectedIngestDocument = RandomDocumentPicks.randomIngestDocument(random(), expected);
assertIngestDocument(ingestDocument, expectedIngestDocument);
}
}

View File

@ -22,30 +22,30 @@ package org.elasticsearch.bootstrap;
import org.apache.lucene.util.Constants;
import org.elasticsearch.test.ESTestCase;
/** Simple tests seccomp filter is working. */
public class SeccompTests extends ESTestCase {
/** Simple tests system call filter is working. */
public class SystemCallFilterTests extends ESTestCase {
/** command to try to run in tests */
static final String EXECUTABLE = Constants.WINDOWS ? "calc" : "ls";
@Override
public void setUp() throws Exception {
super.setUp();
assumeTrue("requires seccomp filter installation", Natives.isSeccompInstalled());
assumeTrue("requires system call filter installation", Natives.isSystemCallFilterInstalled());
// otherwise security manager will block the execution, no fun
assumeTrue("cannot test with security manager enabled", System.getSecurityManager() == null);
// otherwise, since we don't have TSYNC support, rules are not applied to the test thread
// (randomizedrunner class initialization happens in its own thread, after the test thread is created)
// instead we just forcefully run it for the test thread here.
if (!JNANatives.LOCAL_SECCOMP_ALL) {
if (!JNANatives.LOCAL_SYSTEM_CALL_FILTER_ALL) {
try {
Seccomp.init(createTempDir());
SystemCallFilter.init(createTempDir());
} catch (Exception e) {
throw new RuntimeException("unable to forcefully apply seccomp to test thread", e);
throw new RuntimeException("unable to forcefully apply system call filter to test thread", e);
}
}
}
public void testNoExecution() throws Exception {
try {
Runtime.getRuntime().exec(EXECUTABLE);
@ -63,11 +63,11 @@ public class SeccompTests extends ESTestCase {
at java.lang.UNIXProcess.<init>(UNIXProcess.java:248)
at java.lang.ProcessImpl.start(ProcessImpl.java:134)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
...
...
*/
}
}
// make sure thread inherits this too (its documented that way)
public void testNoExecutionFromThread() throws Exception {
Thread t = new Thread() {

View File

@ -39,9 +39,8 @@ import java.util.concurrent.TimeUnit;
/**
* Create a simple "daemon controller", put it in the right place and check that it runs.
*
* Extends LuceneTestCase rather than ESTestCase as ESTestCase installs seccomp, and that
* prevents the Spawner class doing its job. Also needs to run in a separate JVM to other
* tests that extend ESTestCase for the same reason.
* Extends LuceneTestCase rather than ESTestCase as ESTestCase installs a system call filter, and that prevents the Spawner class doing its
* job. Also needs to run in a separate JVM to other tests that extend ESTestCase for the same reason.
*/
public class SpawnerNoBootstrapTests extends LuceneTestCase {

View File

@ -1,44 +0,0 @@
{
"suggest": {
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/master/search-suggesters.html",
"methods": ["POST"],
"url": {
"path": "/_suggest",
"paths": ["/_suggest", "/{index}/_suggest"],
"parts": {
"index": {
"type" : "list",
"description" : "A comma-separated list of index names to restrict the operation; use `_all` or empty string to perform the operation on all indices"
}
},
"params": {
"ignore_unavailable": {
"type" : "boolean",
"description" : "Whether specified concrete indices should be ignored when unavailable (missing or closed)"
},
"allow_no_indices": {
"type" : "boolean",
"description" : "Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified)"
},
"expand_wildcards": {
"type" : "enum",
"options" : ["open","closed","none","all"],
"default" : "open",
"description" : "Whether to expand wildcard expression to concrete indices that are open, closed or both."
},
"preference": {
"type" : "string",
"description" : "Specify the node or shard the operation should be performed on (default: random)"
},
"routing": {
"type" : "string",
"description" : "Specific routing value"
}
}
},
"body": {
"description" : "The request definition",
"required" : true
}
}
}

View File

@ -24,19 +24,3 @@ setup:
- match: {suggest.test_suggestion.1.options.0.text: amsterdam}
- match: {suggest.test_suggestion.2.options.0.text: meetup}
---
"Suggest API should have deprecation warning":
- skip:
features: 'warnings'
- do:
warnings:
- "[POST /_suggest] is deprecated! Use [POST /_search] instead."
suggest:
body:
test_suggestion:
text: "The Amsterdma meetpu"
term:
field: body
- match: {test_suggestion.1.options.0.text: amsterdam}
- match: {test_suggestion.2.options.0.text: meetup}

View File

@ -1,314 +0,0 @@
# This test creates one huge mapping in the setup
# Every test should use its own field to make sure it works
setup:
- do:
indices.create:
index: test
body:
mappings:
test:
"properties":
"suggest_1":
"type" : "completion"
"suggest_2":
"type" : "completion"
"suggest_3":
"type" : "completion"
"suggest_4":
"type" : "completion"
"suggest_5a":
"type" : "completion"
"suggest_5b":
"type" : "completion"
"suggest_6":
"type" : "completion"
title:
type: keyword
---
"Simple suggestion should work":
- skip:
features: 'warnings'
- do:
index:
index: test
type: test
id: 1
body:
suggest_1: "bar"
- do:
index:
index: test
type: test
id: 2
body:
suggest_1: "baz"
- do:
indices.refresh: {}
- do:
warnings:
- "[POST /_suggest] is deprecated! Use [POST /_search] instead."
suggest:
body:
result:
text: "b"
completion:
field: suggest_1
- length: { result: 1 }
- length: { result.0.options: 2 }
---
"Simple suggestion array should work":
- skip:
features: 'warnings'
- do:
index:
index: test
type: test
id: 1
body:
suggest_2: ["bar", "foo"]
- do:
indices.refresh: {}
- do:
warnings:
- "[POST /_suggest] is deprecated! Use [POST /_search] instead."
suggest:
body:
result:
text: "f"
completion:
field: suggest_2
- length: { result: 1 }
- length: { result.0.options: 1 }
- match: { result.0.options.0.text: "foo" }
- do:
warnings:
- "[POST /_suggest] is deprecated! Use [POST /_search] instead."
suggest:
body:
result:
text: "b"
completion:
field: suggest_2
- length: { result: 1 }
- length: { result.0.options: 1 }
- match: { result.0.options.0.text: "bar" }
---
"Suggestion entry should work":
- skip:
features: 'warnings'
- do:
index:
index: test
type: test
id: 1
body:
suggest_3:
input: "bar"
weight: 2
- do:
index:
index: test
type: test
id: 2
body:
suggest_3:
input: "baz"
weight: 3
- do:
indices.refresh: {}
- do:
warnings:
- "[POST /_suggest] is deprecated! Use [POST /_search] instead."
suggest:
body:
result:
text: "b"
completion:
field: suggest_3
- length: { result: 1 }
- length: { result.0.options: 2 }
- match: { result.0.options.0.text: "baz" }
- match: { result.0.options.1.text: "bar" }
---
"Suggestion entry array should work":
- skip:
features: 'warnings'
- do:
index:
index: test
type: test
id: 1
body:
suggest_4:
- input: "bar"
weight: 3
- input: "fo"
weight: 3
- do:
index:
index: test
type: test
id: 2
body:
suggest_4:
- input: "baz"
weight: 2
- input: "foo"
weight: 1
- do:
indices.refresh: {}
- do:
warnings:
- "[POST /_suggest] is deprecated! Use [POST /_search] instead."
suggest:
body:
result:
text: "b"
completion:
field: suggest_4
- length: { result: 1 }
- length: { result.0.options: 2 }
- match: { result.0.options.0.text: "bar" }
- match: { result.0.options.1.text: "baz" }
- do:
warnings:
- "[POST /_suggest] is deprecated! Use [POST /_search] instead."
suggest:
body:
result:
text: "f"
completion:
field: suggest_4
- length: { result: 1 }
- length: { result.0.options: 2 }
- match: { result.0.options.0.text: "fo" }
- match: { result.0.options.1.text: "foo" }
---
"Multiple Completion fields should work":
- skip:
features: 'warnings'
- do:
index:
index: test
type: test
id: 1
body:
suggest_5a: "bar"
suggest_5b: "baz"
- do:
indices.refresh: {}
- do:
warnings:
- "[POST /_suggest] is deprecated! Use [POST /_search] instead."
suggest:
body:
result:
text: "b"
completion:
field: suggest_5a
- length: { result: 1 }
- length: { result.0.options: 1 }
- match: { result.0.options.0.text: "bar" }
- do:
warnings:
- "[POST /_suggest] is deprecated! Use [POST /_search] instead."
suggest:
body:
result:
text: "b"
completion:
field: suggest_5b
- length: { result: 1 }
- length: { result.0.options: 1 }
- match: { result.0.options.0.text: "baz" }
---
"Suggestions with source should work":
- skip:
features: 'warnings'
- do:
index:
index: test
type: test
id: 1
body:
suggest_6:
input: "bar"
weight: 2
title: "title_bar"
count: 4
- do:
index:
index: test
type: test
id: 2
body:
suggest_6:
input: "baz"
weight: 3
title: "title_baz"
count: 3
- do:
indices.refresh: {}
- do:
warnings:
- "[POST /_suggest] is deprecated! Use [POST /_search] instead."
suggest:
body:
result:
text: "b"
completion:
field: suggest_6
- length: { result: 1 }
- length: { result.0.options: 2 }
- match: { result.0.options.0.text: "baz" }
- match: { result.0.options.0._index: "test" }
- match: { result.0.options.0._type: "test" }
- match: { result.0.options.0._source.title: "title_baz" }
- match: { result.0.options.0._source.count: 3 }
- match: { result.0.options.1.text: "bar" }
- match: { result.0.options.1._index: "test" }
- match: { result.0.options.1._type: "test" }
- match: { result.0.options.1._source.title: "title_bar" }
- match: { result.0.options.1._source.count: 4 }