Merge branch 'master' into deprecate

This commit is contained in:
Jack Conradson 2016-08-30 09:11:18 -07:00
commit c8f57df5cf
71 changed files with 2251 additions and 1228 deletions

View File

@ -248,8 +248,6 @@
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]cluster[/\\]metadata[/\\]MappingMetaData.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]cluster[/\\]metadata[/\\]MetaData.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]cluster[/\\]metadata[/\\]MetaDataCreateIndexService.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]cluster[/\\]metadata[/\\]MetaDataDeleteIndexService.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]cluster[/\\]metadata[/\\]MetaDataIndexAliasesService.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]cluster[/\\]metadata[/\\]MetaDataIndexStateService.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]cluster[/\\]metadata[/\\]MetaDataIndexTemplateService.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]cluster[/\\]metadata[/\\]MetaDataIndexUpgradeService.java" checks="LineLength" />

View File

@ -21,29 +21,22 @@ package org.elasticsearch.action.admin.indices.alias;
import org.elasticsearch.cluster.ack.ClusterStateUpdateRequest;
import org.elasticsearch.cluster.metadata.AliasAction;
import java.util.List;
/**
* Cluster state update request that allows to add or remove aliases
*/
public class IndicesAliasesClusterStateUpdateRequest extends ClusterStateUpdateRequest<IndicesAliasesClusterStateUpdateRequest> {
private final List<AliasAction> actions;
AliasAction[] actions;
public IndicesAliasesClusterStateUpdateRequest() {
public IndicesAliasesClusterStateUpdateRequest(List<AliasAction> actions) {
this.actions = actions;
}
/**
* Returns the alias actions to be performed
*/
public AliasAction[] actions() {
public List<AliasAction> actions() {
return actions;
}
/**
* Sets the alias actions to be executed
*/
public IndicesAliasesClusterStateUpdateRequest actions(AliasAction[] actions) {
this.actions = actions;
return this;
}
}

View File

@ -20,6 +20,8 @@
package org.elasticsearch.action.admin.indices.alias;
import com.carrotsearch.hppc.cursors.ObjectCursor;
import org.elasticsearch.ElasticsearchGenerationException;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.AliasesRequest;
import org.elasticsearch.action.CompositeIndicesRequest;
@ -27,30 +29,41 @@ import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.master.AcknowledgedRequest;
import org.elasticsearch.cluster.metadata.AliasAction;
import org.elasticsearch.cluster.metadata.AliasAction.Type;
import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.ParseFieldMatcherSupplier;
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.util.CollectionUtils;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;
import static org.elasticsearch.action.ValidateActions.addValidationError;
import static org.elasticsearch.cluster.metadata.AliasAction.readAliasAction;
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
import static org.elasticsearch.common.xcontent.ObjectParser.fromList;
/**
* A request to add/remove aliases for one or more indices.
*/
public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesRequest> implements CompositeIndicesRequest {
private List<AliasActions> allAliasActions = new ArrayList<>();
//indices options that require every specified index to exist, expand wildcards only to open indices and
@ -61,94 +74,317 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
}
/*
* Aliases can be added by passing multiple indices to the Request and
* deleted by passing multiple indices and aliases. They are expanded into
* distinct AliasAction instances when the request is processed. This class
* holds the AliasAction and in addition the arrays or alias names and
* indices that is later used to create the final AliasAction instances.
/**
* Request to take one or more actions on one or more indexes and alias combinations.
*/
public static class AliasActions implements AliasesRequest {
private String[] indices = Strings.EMPTY_ARRAY;
public static class AliasActions implements AliasesRequest, Writeable {
public enum Type {
ADD((byte) 0),
REMOVE((byte) 1),
REMOVE_INDEX((byte) 2);
private final byte value;
Type(byte value) {
this.value = value;
}
public byte value() {
return value;
}
public static Type fromValue(byte value) {
switch (value) {
case 0: return ADD;
case 1: return REMOVE;
case 2: return REMOVE_INDEX;
default: throw new IllegalArgumentException("No type for action [" + value + "]");
}
}
}
/**
* Build a new {@link AliasAction} to add aliases.
*/
public static AliasActions add() {
return new AliasActions(AliasActions.Type.ADD);
}
/**
* Build a new {@link AliasAction} to remove aliases.
*/
public static AliasActions remove() {
return new AliasActions(AliasActions.Type.REMOVE);
}
/**
* Build a new {@link AliasAction} to remove aliases.
*/
public static AliasActions removeIndex() {
return new AliasActions(AliasActions.Type.REMOVE_INDEX);
}
private static ObjectParser<AliasActions, ParseFieldMatcherSupplier> parser(String name, Supplier<AliasActions> supplier) {
ObjectParser<AliasActions, ParseFieldMatcherSupplier> parser = new ObjectParser<>(name, supplier);
parser.declareString((action, index) -> {
if (action.indices() != null) {
throw new IllegalArgumentException("Only one of [index] and [indices] is supported");
}
action.index(index);
}, new ParseField("index"));
parser.declareStringArray(fromList(String.class, (action, indices) -> {
if (action.indices() != null) {
throw new IllegalArgumentException("Only one of [index] and [indices] is supported");
}
action.indices(indices);
}), new ParseField("indices"));
parser.declareString((action, alias) -> {
if (action.aliases() != null && action.aliases().length != 0) {
throw new IllegalArgumentException("Only one of [alias] and [aliases] is supported");
}
action.alias(alias);
}, new ParseField("alias"));
parser.declareStringArray(fromList(String.class, (action, aliases) -> {
if (action.aliases() != null && action.aliases().length != 0) {
throw new IllegalArgumentException("Only one of [alias] and [aliases] is supported");
}
action.aliases(aliases);
}), new ParseField("aliases"));
return parser;
}
private static final ObjectParser<AliasActions, ParseFieldMatcherSupplier> ADD_PARSER = parser("add", AliasActions::add);
static {
ADD_PARSER.declareObject(AliasActions::filter, (parser, m) -> {
try {
return parser.mapOrdered();
} catch (IOException e) {
throw new ParsingException(parser.getTokenLocation(), "Problems parsing [filter]", e);
}
}, new ParseField("filter"));
// Since we need to support numbers AND strings here we have to use ValueType.INT.
ADD_PARSER.declareField(AliasActions::routing, p -> p.text(), new ParseField("routing"), ValueType.INT);
ADD_PARSER.declareField(AliasActions::indexRouting, p -> p.text(), new ParseField("index_routing"), ValueType.INT);
ADD_PARSER.declareField(AliasActions::searchRouting, p -> p.text(), new ParseField("search_routing"), ValueType.INT);
}
private static final ObjectParser<AliasActions, ParseFieldMatcherSupplier> REMOVE_PARSER = parser("remove", AliasActions::remove);
private static final ObjectParser<AliasActions, ParseFieldMatcherSupplier> REMOVE_INDEX_PARSER = parser("remove_index",
AliasActions::removeIndex);
/**
* Parser for any one {@link AliasAction}.
*/
public static final ConstructingObjectParser<AliasActions, ParseFieldMatcherSupplier> PARSER = new ConstructingObjectParser<>(
"alias_action", a -> {
// Take the first action and complain if there are more than one actions
AliasActions action = null;
for (Object o : a) {
if (o != null) {
if (action == null) {
action = (AliasActions) o;
} else {
throw new IllegalArgumentException("Too many operations declared in on opeation entry");
}
}
}
return action;
});
static {
PARSER.declareObject(optionalConstructorArg(), ADD_PARSER, new ParseField("add"));
PARSER.declareObject(optionalConstructorArg(), REMOVE_PARSER, new ParseField("remove"));
PARSER.declareObject(optionalConstructorArg(), REMOVE_INDEX_PARSER, new ParseField("remove_index"));
}
private final AliasActions.Type type;
private String[] indices;
private String[] aliases = Strings.EMPTY_ARRAY;
private AliasAction aliasAction;
private String filter;
private String routing;
private String indexRouting;
private String searchRouting;
public AliasActions(AliasAction.Type type, String[] indices, String[] aliases) {
aliasAction = new AliasAction(type);
indices(indices);
aliases(aliases);
AliasActions(AliasActions.Type type) {
this.type = type;
}
public AliasActions(AliasAction.Type type, String index, String alias) {
aliasAction = new AliasAction(type);
indices(index);
aliases(alias);
/**
* Read from a stream.
*/
public AliasActions(StreamInput in) throws IOException {
type = AliasActions.Type.fromValue(in.readByte());
indices = in.readStringArray();
aliases = in.readStringArray();
filter = in.readOptionalString();
routing = in.readOptionalString();
searchRouting = in.readOptionalString();
indexRouting = in.readOptionalString();
}
AliasActions(AliasAction.Type type, String[] index, String alias) {
aliasAction = new AliasAction(type);
indices(index);
aliases(alias);
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeByte(type.value());
out.writeStringArray(indices);
out.writeStringArray(aliases);
out.writeOptionalString(filter);
out.writeOptionalString(routing);
out.writeOptionalString(searchRouting);
out.writeOptionalString(indexRouting);
}
public AliasActions(AliasAction action) {
this.aliasAction = action;
indices(action.index());
aliases(action.alias());
/**
* Validate that the action is sane. Called when the action is added to the request because actions can be invalid while being
* built.
*/
void validate() {
if (indices == null) {
throw new IllegalArgumentException("One of [index] or [indices] is required");
}
if (type != AliasActions.Type.REMOVE_INDEX && (aliases == null || aliases.length == 0)) {
throw new IllegalArgumentException("One of [alias] or [aliases] is required");
}
}
public AliasActions(Type type, String index, String[] aliases) {
aliasAction = new AliasAction(type);
indices(index);
aliases(aliases);
}
public AliasActions() {
}
public AliasActions filter(Map<String, Object> filter) {
aliasAction.filter(filter);
return this;
}
public AliasActions filter(QueryBuilder filter) {
aliasAction.filter(filter);
return this;
}
public Type actionType() {
return aliasAction.actionType();
}
public void routing(String routing) {
aliasAction.routing(routing);
}
public void searchRouting(String searchRouting) {
aliasAction.searchRouting(searchRouting);
}
public void indexRouting(String indexRouting) {
aliasAction.indexRouting(indexRouting);
}
public AliasActions filter(String filter) {
aliasAction.filter(filter);
return this;
/**
* Type of the action to perform.
*/
public AliasActions.Type actionType() {
return type;
}
@Override
public AliasActions indices(String... indices) {
if (indices == null || indices.length == 0) {
throw new IllegalArgumentException("[indices] can't be empty");
}
for (String index : indices) {
if (false == Strings.hasLength(index)) {
throw new IllegalArgumentException("[indices] can't contain empty string");
}
}
this.indices = indices;
return this;
}
/**
* Set the index this action is operating on.
*/
public AliasActions index(String index) {
if (false == Strings.hasLength(index)) {
throw new IllegalArgumentException("[index] can't be empty string");
}
this.indices = new String[] {index};
return this;
}
/**
* Aliases to use with this action.
*/
@Override
public AliasActions aliases(String... aliases) {
if (type == AliasActions.Type.REMOVE_INDEX) {
throw new IllegalArgumentException("[aliases] is unsupported for [" + type + "]");
}
if (aliases == null || aliases.length == 0) {
throw new IllegalArgumentException("[aliases] can't be empty");
}
for (String alias : aliases) {
if (false == Strings.hasLength(alias)) {
throw new IllegalArgumentException("[aliases] can't contain empty string");
}
}
this.aliases = aliases;
return this;
}
/**
* Set the alias this action is operating on.
*/
public AliasActions alias(String alias) {
if (type == AliasActions.Type.REMOVE_INDEX) {
throw new IllegalArgumentException("[alias] is unsupported for [" + type + "]");
}
if (false == Strings.hasLength(alias)) {
throw new IllegalArgumentException("[alias] can't be empty string");
}
this.aliases = new String[] {alias};
return this;
}
/**
* Set the default routing.
*/
public AliasActions routing(String routing) {
if (type != AliasActions.Type.ADD) {
throw new IllegalArgumentException("[routing] is unsupported for [" + type + "]");
}
this.routing = routing;
return this;
}
public String searchRouting() {
return searchRouting == null ? routing : searchRouting;
}
public AliasActions searchRouting(String searchRouting) {
if (type != AliasActions.Type.ADD) {
throw new IllegalArgumentException("[search_routing] is unsupported for [" + type + "]");
}
this.searchRouting = searchRouting;
return this;
}
public String indexRouting() {
return indexRouting == null ? routing : indexRouting;
}
public AliasActions indexRouting(String indexRouting) {
if (type != AliasActions.Type.ADD) {
throw new IllegalArgumentException("[index_routing] is unsupported for [" + type + "]");
}
this.indexRouting = indexRouting;
return this;
}
public String filter() {
return filter;
}
public AliasActions filter(String filter) {
if (type != AliasActions.Type.ADD) {
throw new IllegalArgumentException("[filter] is unsupported for [" + type + "]");
}
this.filter = filter;
return this;
}
public AliasActions filter(Map<String, Object> filter) {
if (filter == null || filter.isEmpty()) {
this.filter = null;
return this;
}
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.map(filter);
this.filter = builder.string();
return this;
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate [" + filter + "]", e);
}
}
public AliasActions filter(QueryBuilder filter) {
if (filter == null) {
this.filter = null;
return this;
}
try {
XContentBuilder builder = XContentFactory.jsonBuilder();
filter.toXContent(builder, ToXContent.EMPTY_PARAMS);
builder.close();
this.filter = builder.string();
return this;
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to build json for alias request", e);
}
}
@Override
public String[] aliases() {
return aliases;
@ -157,7 +393,7 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
@Override
public boolean expandAliasesWildcards() {
//remove operations support wildcards among aliases, add operations don't
return aliasAction.actionType() == Type.REMOVE;
return type == Type.REMOVE;
}
@Override
@ -170,10 +406,6 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
return INDICES_OPTIONS;
}
public AliasAction aliasAction() {
return aliasAction;
}
public String[] concreteAliases(MetaData metaData, String concreteIndex) {
if (expandAliasesWildcards()) {
//for DELETE we expand the aliases
@ -191,83 +423,48 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
return aliases;
}
}
public AliasActions readFrom(StreamInput in) throws IOException {
indices = in.readStringArray();
aliases = in.readStringArray();
aliasAction = readAliasAction(in);
return this;
@Override
public String toString() {
return "AliasActions["
+ "type=" + type
+ ",indices=" + Arrays.toString(indices)
+ ",aliases=" + Arrays.deepToString(aliases)
+ ",filter=" + filter
+ ",routing=" + routing
+ ",indexRouting=" + indexRouting
+ ",searchRouting=" + searchRouting
+ "]";
}
public void writeTo(StreamOutput out) throws IOException {
out.writeStringArray(indices);
out.writeStringArray(aliases);
this.aliasAction.writeTo(out);
// equals, and hashCode implemented for easy testing of round trip
@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != getClass()) {
return false;
}
AliasActions other = (AliasActions) obj;
return Objects.equals(type, other.type)
&& Arrays.equals(indices, other.indices)
&& Arrays.equals(aliases, other.aliases)
&& Objects.equals(filter, other.filter)
&& Objects.equals(routing, other.routing)
&& Objects.equals(indexRouting, other.indexRouting)
&& Objects.equals(searchRouting, other.searchRouting);
}
@Override
public int hashCode() {
return Objects.hash(type, indices, aliases, filter, routing, indexRouting, searchRouting);
}
}
/**
* Adds an alias to the index.
* @param alias The alias
* @param indices The indices
* Add the action to this request and validate it.
*/
public IndicesAliasesRequest addAlias(String alias, String... indices) {
addAliasAction(new AliasActions(AliasAction.Type.ADD, indices, alias));
return this;
}
public void addAliasAction(AliasActions aliasAction) {
public IndicesAliasesRequest addAliasAction(AliasActions aliasAction) {
aliasAction.validate();
allAliasActions.add(aliasAction);
}
public IndicesAliasesRequest addAliasAction(AliasAction action) {
addAliasAction(new AliasActions(action));
return this;
}
/**
* Adds an alias to the index.
* @param alias The alias
* @param filter The filter
* @param indices The indices
*/
public IndicesAliasesRequest addAlias(String alias, Map<String, Object> filter, String... indices) {
addAliasAction(new AliasActions(AliasAction.Type.ADD, indices, alias).filter(filter));
return this;
}
/**
* Adds an alias to the index.
* @param alias The alias
* @param filterBuilder The filter
* @param indices The indices
*/
public IndicesAliasesRequest addAlias(String alias, QueryBuilder filterBuilder, String... indices) {
addAliasAction(new AliasActions(AliasAction.Type.ADD, indices, alias).filter(filterBuilder));
return this;
}
/**
* Removes an alias to the index.
*
* @param indices The indices
* @param aliases The aliases
*/
public IndicesAliasesRequest removeAlias(String[] indices, String... aliases) {
addAliasAction(new AliasActions(AliasAction.Type.REMOVE, indices, aliases));
return this;
}
/**
* Removes an alias to the index.
*
* @param index The index
* @param aliases The aliases
*/
public IndicesAliasesRequest removeAlias(String index, String... aliases) {
addAliasAction(new AliasActions(AliasAction.Type.REMOVE, index, aliases));
return this;
}
@ -285,50 +482,20 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
if (allAliasActions.isEmpty()) {
return addValidationError("Must specify at least one alias action", validationException);
}
for (AliasActions aliasAction : allAliasActions) {
if (CollectionUtils.isEmpty(aliasAction.aliases)) {
validationException = addValidationError("Alias action [" + aliasAction.actionType().name().toLowerCase(Locale.ENGLISH)
+ "]: Property [alias/aliases] is either missing or null", validationException);
} else {
for (String alias : aliasAction.aliases) {
if (!Strings.hasText(alias)) {
validationException = addValidationError("Alias action [" + aliasAction.actionType().name().toLowerCase(Locale.ENGLISH)
+ "]: [alias/aliases] may not be empty string", validationException);
}
}
}
if (CollectionUtils.isEmpty(aliasAction.indices)) {
validationException = addValidationError("Alias action [" + aliasAction.actionType().name().toLowerCase(Locale.ENGLISH)
+ "]: Property [index/indices] is either missing or null", validationException);
} else {
for (String index : aliasAction.indices) {
if (!Strings.hasText(index)) {
validationException = addValidationError("Alias action [" + aliasAction.actionType().name().toLowerCase(Locale.ENGLISH)
+ "]: [index/indices] may not be empty string", validationException);
}
}
}
}
return validationException;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
int size = in.readVInt();
for (int i = 0; i < size; i++) {
allAliasActions.add(readAliasActions(in));
}
allAliasActions = in.readList(AliasActions::new);
readTimeout(in);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeVInt(allAliasActions.size());
for (AliasActions aliasAction : allAliasActions) {
aliasAction.writeTo(out);
}
out.writeList(allAliasActions);
writeTimeout(out);
}
@ -336,11 +503,6 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
return INDICES_OPTIONS;
}
private static AliasActions readAliasActions(StreamInput in) throws IOException {
AliasActions actions = new AliasActions();
return actions.readFrom(in);
}
@Override
public List<? extends IndicesRequest> subRequests() {
return allAliasActions;

View File

@ -22,15 +22,15 @@ package org.elasticsearch.action.admin.indices.alias;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.support.master.AcknowledgedRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.cluster.metadata.AliasAction;
import org.elasticsearch.index.query.QueryBuilder;
import java.util.Map;
/**
*
* Builder for request to modify many aliases at once.
*/
public class IndicesAliasesRequestBuilder extends AcknowledgedRequestBuilder<IndicesAliasesRequest, IndicesAliasesResponse, IndicesAliasesRequestBuilder> {
public class IndicesAliasesRequestBuilder
extends AcknowledgedRequestBuilder<IndicesAliasesRequest, IndicesAliasesResponse, IndicesAliasesRequestBuilder> {
public IndicesAliasesRequestBuilder(ElasticsearchClient client, IndicesAliasesAction action) {
super(client, action, new IndicesAliasesRequest());
@ -43,7 +43,7 @@ public class IndicesAliasesRequestBuilder extends AcknowledgedRequestBuilder<Ind
* @param alias The alias
*/
public IndicesAliasesRequestBuilder addAlias(String index, String alias) {
request.addAlias(alias, index);
request.addAliasAction(AliasActions.add().index(index).alias(alias));
return this;
}
@ -54,7 +54,7 @@ public class IndicesAliasesRequestBuilder extends AcknowledgedRequestBuilder<Ind
* @param alias The alias
*/
public IndicesAliasesRequestBuilder addAlias(String[] indices, String alias) {
request.addAlias(alias, indices);
request.addAliasAction(AliasActions.add().indices(indices).alias(alias));
return this;
}
@ -66,8 +66,7 @@ public class IndicesAliasesRequestBuilder extends AcknowledgedRequestBuilder<Ind
* @param filter The filter
*/
public IndicesAliasesRequestBuilder addAlias(String index, String alias, String filter) {
AliasActions action = new AliasActions(AliasAction.Type.ADD, index, alias).filter(filter);
request.addAliasAction(action);
request.addAliasAction(AliasActions.add().index(index).alias(alias).filter(filter));
return this;
}
@ -79,8 +78,7 @@ public class IndicesAliasesRequestBuilder extends AcknowledgedRequestBuilder<Ind
* @param filter The filter
*/
public IndicesAliasesRequestBuilder addAlias(String indices[], String alias, String filter) {
AliasActions action = new AliasActions(AliasAction.Type.ADD, indices, alias).filter(filter);
request.addAliasAction(action);
request.addAliasAction(AliasActions.add().indices(indices).alias(alias).filter(filter));
return this;
}
@ -92,7 +90,7 @@ public class IndicesAliasesRequestBuilder extends AcknowledgedRequestBuilder<Ind
* @param filter The filter
*/
public IndicesAliasesRequestBuilder addAlias(String[] indices, String alias, Map<String, Object> filter) {
request.addAlias(alias, filter, indices);
request.addAliasAction(AliasActions.add().indices(indices).alias(alias).filter(filter));
return this;
}
@ -104,7 +102,7 @@ public class IndicesAliasesRequestBuilder extends AcknowledgedRequestBuilder<Ind
* @param filter The filter
*/
public IndicesAliasesRequestBuilder addAlias(String index, String alias, Map<String, Object> filter) {
request.addAlias(alias, filter, index);
request.addAliasAction(AliasActions.add().index(index).alias(alias).filter(filter));
return this;
}
@ -116,7 +114,7 @@ public class IndicesAliasesRequestBuilder extends AcknowledgedRequestBuilder<Ind
* @param filterBuilder The filter
*/
public IndicesAliasesRequestBuilder addAlias(String indices[], String alias, QueryBuilder filterBuilder) {
request.addAlias(alias, filterBuilder, indices);
request.addAliasAction(AliasActions.add().indices(indices).alias(alias).filter(filterBuilder));
return this;
}
@ -128,7 +126,7 @@ public class IndicesAliasesRequestBuilder extends AcknowledgedRequestBuilder<Ind
* @param filterBuilder The filter
*/
public IndicesAliasesRequestBuilder addAlias(String index, String alias, QueryBuilder filterBuilder) {
request.addAlias(alias, filterBuilder, index);
request.addAliasAction(AliasActions.add().index(index).alias(alias).filter(filterBuilder));
return this;
}
@ -139,7 +137,7 @@ public class IndicesAliasesRequestBuilder extends AcknowledgedRequestBuilder<Ind
* @param alias The alias
*/
public IndicesAliasesRequestBuilder removeAlias(String index, String alias) {
request.removeAlias(index, alias);
request.addAliasAction(AliasActions.remove().index(index).alias(alias));
return this;
}
@ -150,7 +148,7 @@ public class IndicesAliasesRequestBuilder extends AcknowledgedRequestBuilder<Ind
* @param aliases The aliases
*/
public IndicesAliasesRequestBuilder removeAlias(String[] indices, String... aliases) {
request.removeAlias(indices, aliases);
request.addAliasAction(AliasActions.remove().indices(indices).aliases(aliases));
return this;
}
@ -161,17 +159,12 @@ public class IndicesAliasesRequestBuilder extends AcknowledgedRequestBuilder<Ind
* @param aliases The aliases
*/
public IndicesAliasesRequestBuilder removeAlias(String index, String[] aliases) {
request.removeAlias(index, aliases);
request.addAliasAction(AliasActions.remove().index(index).aliases(aliases));
return this;
}
/**
* Adds an alias action to the request.
*
* @param aliasAction The alias action
*/
public IndicesAliasesRequestBuilder addAliasAction(AliasAction aliasAction) {
request.addAliasAction(aliasAction);
public IndicesAliasesRequestBuilder removeIndex(String index) {
request.addAliasAction(AliasActions.removeIndex().index(index));
return this;
}

View File

@ -43,6 +43,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static java.util.Collections.unmodifiableList;
/**
* Add/remove aliases action
*/
@ -86,31 +88,38 @@ public class TransportIndicesAliasesAction extends TransportMasterNodeAction<Ind
//Expand the indices names
List<AliasActions> actions = request.aliasActions();
List<AliasAction> finalActions = new ArrayList<>();
boolean hasOnlyDeletesButNoneCanBeDone = true;
// Resolve all the AliasActions into AliasAction instances and gather all the aliases
Set<String> aliases = new HashSet<>();
for (AliasActions action : actions) {
//expand indices
String[] concreteIndices = indexNameExpressionResolver.concreteIndexNames(state, request.indicesOptions(), action.indices());
//collect the aliases
Collections.addAll(aliases, action.aliases());
for (String index : concreteIndices) {
for (String alias : action.concreteAliases(state.metaData(), index)) {
AliasAction finalAction = new AliasAction(action.aliasAction());
finalAction.index(index);
finalAction.alias(alias);
finalActions.add(finalAction);
//if there is only delete requests, none will be added if the types do not map to any existing type
hasOnlyDeletesButNoneCanBeDone = false;
switch (action.actionType()) {
case ADD:
for (String alias : action.concreteAliases(state.metaData(), index)) {
finalActions.add(new AliasAction.Add(index, alias, action.filter(), action.indexRouting(), action.searchRouting()));
}
break;
case REMOVE:
for (String alias : action.concreteAliases(state.metaData(), index)) {
finalActions.add(new AliasAction.Remove(index, alias));
}
break;
case REMOVE_INDEX:
finalActions.add(new AliasAction.RemoveIndex(index));
break;
default:
throw new IllegalArgumentException("Unsupported action [" + action.actionType() + "]");
}
}
}
if (hasOnlyDeletesButNoneCanBeDone && actions.size() != 0) {
if (finalActions.isEmpty() && false == actions.isEmpty()) {
throw new AliasesNotFoundException(aliases.toArray(new String[aliases.size()]));
}
request.aliasActions().clear();
IndicesAliasesClusterStateUpdateRequest updateRequest = new IndicesAliasesClusterStateUpdateRequest()
.ackTimeout(request.timeout()).masterNodeTimeout(request.masterNodeTimeout())
.actions(finalActions.toArray(new AliasAction[finalActions.size()]));
IndicesAliasesClusterStateUpdateRequest updateRequest = new IndicesAliasesClusterStateUpdateRequest(unmodifiableList(finalActions))
.ackTimeout(request.timeout()).masterNodeTimeout(request.masterNodeTimeout());
indexAliasesService.indicesAliases(updateRequest, new ActionListener<ClusterStateUpdateResponse>() {
@Override

View File

@ -47,11 +47,15 @@ import org.elasticsearch.index.shard.DocsStats;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static java.util.Collections.unmodifiableList;
/**
* Main class to swap the index pointed to by an alias, given some conditions
*/
@ -156,13 +160,12 @@ public class TransportRolloverAction extends TransportMasterNodeAction<RolloverR
static IndicesAliasesClusterStateUpdateRequest prepareRolloverAliasesUpdateRequest(String oldIndex, String newIndex,
RolloverRequest request) {
final IndicesAliasesClusterStateUpdateRequest updateRequest = new IndicesAliasesClusterStateUpdateRequest()
List<AliasAction> actions = unmodifiableList(Arrays.asList(
new AliasAction.Add(newIndex, request.getAlias(), null, null, null),
new AliasAction.Remove(oldIndex, request.getAlias())));
final IndicesAliasesClusterStateUpdateRequest updateRequest = new IndicesAliasesClusterStateUpdateRequest(actions)
.ackTimeout(request.ackTimeout())
.masterNodeTimeout(request.masterNodeTimeout());
AliasAction[] actions = new AliasAction[2];
actions[0] = new AliasAction(AliasAction.Type.ADD, newIndex, request.getAlias());
actions[1] = new AliasAction(AliasAction.Type.REMOVE, oldIndex, request.getAlias());
updateRequest.actions(actions);
return updateRequest;
}

View File

@ -19,213 +19,167 @@
package org.elasticsearch.cluster.metadata;
import org.elasticsearch.ElasticsearchGenerationException;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Streamable;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import java.io.IOException;
import java.util.Map;
import org.elasticsearch.common.Strings;
/**
*
* Individual operation to perform on the cluster state as part of an {@link IndicesAliasesRequest}.
*/
public class AliasAction implements Streamable {
public abstract class AliasAction {
private final String index;
public static enum Type {
ADD((byte) 0),
REMOVE((byte) 1);
private final byte value;
Type(byte value) {
this.value = value;
private AliasAction(String index) {
if (false == Strings.hasText(index)) {
throw new IllegalArgumentException("[index] is required");
}
public byte value() {
return value;
}
public static Type fromValue(byte value) {
if (value == 0) {
return ADD;
} else if (value == 1) {
return REMOVE;
} else {
throw new IllegalArgumentException("No type for action [" + value + "]");
}
}
}
private Type actionType;
private String index;
private String alias;
@Nullable
private String filter;
@Nullable
private String indexRouting;
@Nullable
private String searchRouting;
private AliasAction() {
}
public AliasAction(AliasAction other) {
this.actionType = other.actionType;
this.index = other.index;
this.alias = other.alias;
this.filter = other.filter;
this.indexRouting = other.indexRouting;
this.searchRouting = other.searchRouting;
}
public AliasAction(Type actionType) {
this.actionType = actionType;
}
public AliasAction(Type actionType, String index, String alias) {
this.actionType = actionType;
this.index = index;
this.alias = alias;
}
public AliasAction(Type actionType, String index, String alias, String filter) {
this.actionType = actionType;
this.index = index;
this.alias = alias;
this.filter = filter;
}
public Type actionType() {
return actionType;
}
public AliasAction index(String index) {
this.index = index;
return this;
}
public String index() {
/**
* Get the index on which the operation should act.
*/
public String getIndex() {
return index;
}
public AliasAction alias(String alias) {
this.alias = alias;
return this;
/**
* Should this action remove the index? Actions that return true from this will never execute
* {@link #apply(NewAliasValidator, MetaData.Builder, IndexMetaData)}.
*/
abstract boolean removeIndex();
/**
* Apply the action.
*
* @param aliasValidator call to validate a new alias before adding it to the builder
* @param metadata metadata builder for the changes made by all actions as part of this request
* @param index metadata for the index being changed
* @return did this action make any changes?
*/
abstract boolean apply(NewAliasValidator aliasValidator, MetaData.Builder metadata, IndexMetaData index);
/**
* Validate a new alias.
*/
@FunctionalInterface
public interface NewAliasValidator {
void validate(String alias, @Nullable String indexRouting, @Nullable String filter);
}
public String alias() {
return alias;
}
/**
* Operation to add an alias to an index.
*/
public static class Add extends AliasAction {
private final String alias;
public String filter() {
return filter;
}
@Nullable
private final String filter;
public AliasAction filter(String filter) {
this.filter = filter;
return this;
}
@Nullable
private final String indexRouting;
public AliasAction filter(Map<String, Object> filter) {
if (filter == null || filter.isEmpty()) {
this.filter = null;
return this;
@Nullable
private final String searchRouting;
/**
* Build the operation.
*/
public Add(String index, String alias, @Nullable String filter, @Nullable String indexRouting, @Nullable String searchRouting) {
super(index);
if (false == Strings.hasText(alias)) {
throw new IllegalArgumentException("[alias] is required");
}
this.alias = alias;
this.filter = filter;
this.indexRouting = indexRouting;
this.searchRouting = searchRouting;
}
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.map(filter);
this.filter = builder.string();
return this;
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate [" + filter + "]", e);
/**
* Alias to add to the index.
*/
public String getAlias() {
return alias;
}
@Override
boolean removeIndex() {
return false;
}
@Override
boolean apply(NewAliasValidator aliasValidator, MetaData.Builder metadata, IndexMetaData index) {
aliasValidator.validate(alias, indexRouting, filter);
AliasMetaData newAliasMd = AliasMetaData.newAliasMetaDataBuilder(alias).filter(filter).indexRouting(indexRouting)
.searchRouting(searchRouting).build();
// Check if this alias already exists
AliasMetaData currentAliasMd = index.getAliases().get(alias);
if (currentAliasMd != null && currentAliasMd.equals(newAliasMd)) {
// It already exists, ignore it
return false;
}
metadata.put(IndexMetaData.builder(index).putAlias(newAliasMd));
return true;
}
}
public AliasAction filter(QueryBuilder queryBuilder) {
if (queryBuilder == null) {
this.filter = null;
return this;
/**
* Operation to remove an alias from an index.
*/
public static class Remove extends AliasAction {
private final String alias;
/**
* Build the operation.
*/
public Remove(String index, String alias) {
super(index);
if (false == Strings.hasText(alias)) {
throw new IllegalArgumentException("[alias] is required");
}
this.alias = alias;
}
try {
XContentBuilder builder = XContentFactory.jsonBuilder();
queryBuilder.toXContent(builder, ToXContent.EMPTY_PARAMS);
builder.close();
this.filter = builder.string();
return this;
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to build json for alias request", e);
/**
* Alias to remove from the index.
*/
public String getAlias() {
return alias;
}
@Override
boolean removeIndex() {
return false;
}
@Override
boolean apply(NewAliasValidator aliasValidator, MetaData.Builder metadata, IndexMetaData index) {
if (false == index.getAliases().containsKey(alias)) {
return false;
}
metadata.put(IndexMetaData.builder(index).removeAlias(alias));
return true;
}
}
public AliasAction routing(String routing) {
this.indexRouting = routing;
this.searchRouting = routing;
return this;
}
/**
* Operation to remove an index. This is an "alias action" because it allows us to remove an index at the same time as we remove add an
* alias to replace it.
*/
public static class RemoveIndex extends AliasAction {
public RemoveIndex(String index) {
super(index);
}
public String indexRouting() {
return indexRouting;
}
@Override
boolean removeIndex() {
return true;
}
public AliasAction indexRouting(String indexRouting) {
this.indexRouting = indexRouting;
return this;
@Override
boolean apply(NewAliasValidator aliasValidator, MetaData.Builder metadata, IndexMetaData index) {
throw new UnsupportedOperationException();
}
}
public String searchRouting() {
return searchRouting;
}
public AliasAction searchRouting(String searchRouting) {
this.searchRouting = searchRouting;
return this;
}
public static AliasAction readAliasAction(StreamInput in) throws IOException {
AliasAction aliasAction = new AliasAction();
aliasAction.readFrom(in);
return aliasAction;
}
@Override
public void readFrom(StreamInput in) throws IOException {
actionType = Type.fromValue(in.readByte());
index = in.readOptionalString();
alias = in.readOptionalString();
filter = in.readOptionalString();
indexRouting = in.readOptionalString();
searchRouting = in.readOptionalString();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeByte(actionType.value());
out.writeOptionalString(index);
out.writeOptionalString(alias);
out.writeOptionalString(filter);
out.writeOptionalString(indexRouting);
out.writeOptionalString(searchRouting);
}
public static AliasAction newAddAliasAction(String index, String alias) {
return new AliasAction(Type.ADD, index, alias);
}
public static AliasAction newRemoveAliasAction(String index, String alias) {
return new AliasAction(Type.REMOVE, index, alias);
}
}
}

View File

@ -20,6 +20,7 @@
package org.elasticsearch.cluster.metadata;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
@ -33,6 +34,7 @@ import org.elasticsearch.indices.InvalidAliasNameException;
import java.io.IOException;
import java.util.Optional;
import java.util.function.Function;
/**
* Validator for an alias, to be used before adding an alias to the index metadata
@ -45,22 +47,13 @@ public class AliasValidator extends AbstractComponent {
super(settings);
}
/**
* Allows to validate an {@link org.elasticsearch.cluster.metadata.AliasAction} and make sure
* it's valid before it gets added to the index metadata. Doesn't validate the alias filter.
* @throws IllegalArgumentException if the alias is not valid
*/
public void validateAliasAction(AliasAction aliasAction, MetaData metaData) {
validateAlias(aliasAction.alias(), aliasAction.index(), aliasAction.indexRouting(), metaData);
}
/**
* Allows to validate an {@link org.elasticsearch.action.admin.indices.alias.Alias} and make sure
* it's valid before it gets added to the index metadata. Doesn't validate the alias filter.
* @throws IllegalArgumentException if the alias is not valid
*/
public void validateAlias(Alias alias, String index, MetaData metaData) {
validateAlias(alias.name(), index, alias.indexRouting(), metaData);
validateAlias(alias.name(), index, alias.indexRouting(), name -> metaData.index(name));
}
/**
@ -69,7 +62,7 @@ public class AliasValidator extends AbstractComponent {
* @throws IllegalArgumentException if the alias is not valid
*/
public void validateAliasMetaData(AliasMetaData aliasMetaData, String index, MetaData metaData) {
validateAlias(aliasMetaData.alias(), index, aliasMetaData.indexRouting(), metaData);
validateAlias(aliasMetaData.alias(), index, aliasMetaData.indexRouting(), name -> metaData.index(name));
}
/**
@ -90,16 +83,19 @@ public class AliasValidator extends AbstractComponent {
}
}
private void validateAlias(String alias, String index, String indexRouting, MetaData metaData) {
/**
* Validate a proposed alias.
*/
public void validateAlias(String alias, String index, @Nullable String indexRouting, Function<String, IndexMetaData> indexLookup) {
validateAliasStandalone(alias, indexRouting);
if (!Strings.hasText(index)) {
throw new IllegalArgumentException("index name is required");
}
assert metaData != null;
if (metaData.hasIndex(alias)) {
throw new InvalidAliasNameException(metaData.index(alias).getIndex(), alias, "an index exists with the same name as the alias");
IndexMetaData indexNamedSameAsAlias = indexLookup.apply(alias);
if (indexNamedSameAsAlias != null) {
throw new InvalidAliasNameException(indexNamedSameAsAlias.getIndex(), alias, "an index exists with the same name as the alias");
}
}

View File

@ -37,11 +37,11 @@ import org.elasticsearch.index.Index;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
@ -219,7 +219,7 @@ public final class IndexGraveyard implements MetaData.Custom {
/**
* Add a set of deleted indexes to the list of tombstones in the cluster state.
*/
public Builder addTombstones(final Index[] indices) {
public Builder addTombstones(final Collection<Index> indices) {
for (Index index : indices) {
addTombstone(index);
}

View File

@ -37,11 +37,13 @@ import org.elasticsearch.index.Index;
import org.elasticsearch.snapshots.SnapshotsService;
import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.toSet;
/**
*
* Deletes indices.
*/
public class MetaDataDeleteIndexService extends AbstractComponent {
@ -56,7 +58,8 @@ public class MetaDataDeleteIndexService extends AbstractComponent {
this.allocationService = allocationService;
}
public void deleteIndices(final DeleteIndexClusterStateUpdateRequest request, final ActionListener<ClusterStateUpdateResponse> listener) {
public void deleteIndices(final DeleteIndexClusterStateUpdateRequest request,
final ActionListener<ClusterStateUpdateResponse> listener) {
if (request.indices() == null || request.indices().length == 0) {
throw new IllegalArgumentException("Index name is required");
}
@ -71,37 +74,43 @@ public class MetaDataDeleteIndexService extends AbstractComponent {
@Override
public ClusterState execute(final ClusterState currentState) {
final MetaData meta = currentState.metaData();
final Index[] indices = request.indices();
final Set<IndexMetaData> metaDatas = Arrays.asList(indices).stream().map(i -> meta.getIndexSafe(i)).collect(Collectors.toSet());
// Check if index deletion conflicts with any running snapshots
SnapshotsService.checkIndexDeletion(currentState, metaDatas);
RoutingTable.Builder routingTableBuilder = RoutingTable.builder(currentState.routingTable());
MetaData.Builder metaDataBuilder = MetaData.builder(meta);
ClusterBlocks.Builder clusterBlocksBuilder = ClusterBlocks.builder().blocks(currentState.blocks());
final IndexGraveyard.Builder graveyardBuilder = IndexGraveyard.builder(metaDataBuilder.indexGraveyard());
final int previousGraveyardSize = graveyardBuilder.tombstones().size();
for (final Index index : indices) {
String indexName = index.getName();
logger.debug("[{}] deleting index", index);
routingTableBuilder.remove(indexName);
clusterBlocksBuilder.removeIndexBlocks(indexName);
metaDataBuilder.remove(indexName);
}
// add tombstones to the cluster state for each deleted index
final IndexGraveyard currentGraveyard = graveyardBuilder.addTombstones(indices).build(settings);
metaDataBuilder.indexGraveyard(currentGraveyard); // the new graveyard set on the metadata
logger.trace("{} tombstones purged from the cluster state. Previous tombstone size: {}. Current tombstone size: {}.",
graveyardBuilder.getNumPurged(), previousGraveyardSize, currentGraveyard.getTombstones().size());
MetaData newMetaData = metaDataBuilder.build();
ClusterBlocks blocks = clusterBlocksBuilder.build();
RoutingAllocation.Result routingResult = allocationService.reroute(
ClusterState.builder(currentState).routingTable(routingTableBuilder.build()).metaData(newMetaData).build(),
"deleted indices [" + indices + "]");
return ClusterState.builder(currentState).routingResult(routingResult).metaData(newMetaData).blocks(blocks).build();
return deleteIndices(currentState, Arrays.asList(request.indices()));
}
});
}
/**
* Delete some indices from the cluster state.
*/
public ClusterState deleteIndices(ClusterState currentState, Collection<Index> indices) {
final MetaData meta = currentState.metaData();
final Set<IndexMetaData> metaDatas = indices.stream().map(i -> meta.getIndexSafe(i)).collect(toSet());
// Check if index deletion conflicts with any running snapshots
SnapshotsService.checkIndexDeletion(currentState, metaDatas);
RoutingTable.Builder routingTableBuilder = RoutingTable.builder(currentState.routingTable());
MetaData.Builder metaDataBuilder = MetaData.builder(meta);
ClusterBlocks.Builder clusterBlocksBuilder = ClusterBlocks.builder().blocks(currentState.blocks());
final IndexGraveyard.Builder graveyardBuilder = IndexGraveyard.builder(metaDataBuilder.indexGraveyard());
final int previousGraveyardSize = graveyardBuilder.tombstones().size();
for (final Index index : indices) {
String indexName = index.getName();
logger.debug("[{}] deleting index", index);
routingTableBuilder.remove(indexName);
clusterBlocksBuilder.removeIndexBlocks(indexName);
metaDataBuilder.remove(indexName);
}
// add tombstones to the cluster state for each deleted index
final IndexGraveyard currentGraveyard = graveyardBuilder.addTombstones(indices).build(settings);
metaDataBuilder.indexGraveyard(currentGraveyard); // the new graveyard set on the metadata
logger.trace("{} tombstones purged from the cluster state. Previous tombstone size: {}. Current tombstone size: {}.",
graveyardBuilder.getNumPurged(), previousGraveyardSize, currentGraveyard.getTombstones().size());
MetaData newMetaData = metaDataBuilder.build();
ClusterBlocks blocks = clusterBlocksBuilder.build();
RoutingAllocation.Result routingResult = allocationService.reroute(
ClusterState.builder(currentState).routingTable(routingTableBuilder.build()).metaData(newMetaData).build(),
"deleted indices [" + indices + "]");
return ClusterState.builder(currentState).routingResult(routingResult).metaData(newMetaData).blocks(blocks).build();
}
}

View File

@ -20,11 +20,14 @@
package org.elasticsearch.cluster.metadata;
import com.carrotsearch.hppc.cursors.ObjectCursor;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesClusterStateUpdateRequest;
import org.elasticsearch.cluster.AckedClusterStateUpdateTask;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.ack.ClusterStateUpdateResponse;
import org.elasticsearch.cluster.metadata.AliasAction.NewAliasValidator;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.Priority;
import org.elasticsearch.common.Strings;
@ -38,11 +41,16 @@ import org.elasticsearch.index.NodeServicesProvider;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.indices.IndicesService;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import static java.util.Collections.emptyList;
/**
* Service responsible for submitting add and remove aliases requests
@ -56,109 +64,114 @@ public class MetaDataIndexAliasesService extends AbstractComponent {
private final AliasValidator aliasValidator;
private final NodeServicesProvider nodeServicesProvider;
private final MetaDataDeleteIndexService deleteIndexService;
@Inject
public MetaDataIndexAliasesService(Settings settings, ClusterService clusterService, IndicesService indicesService, AliasValidator aliasValidator, NodeServicesProvider nodeServicesProvider) {
public MetaDataIndexAliasesService(Settings settings, ClusterService clusterService, IndicesService indicesService,
AliasValidator aliasValidator, NodeServicesProvider nodeServicesProvider, MetaDataDeleteIndexService deleteIndexService) {
super(settings);
this.clusterService = clusterService;
this.indicesService = indicesService;
this.aliasValidator = aliasValidator;
this.nodeServicesProvider = nodeServicesProvider;
this.deleteIndexService = deleteIndexService;
}
public void indicesAliases(final IndicesAliasesClusterStateUpdateRequest request, final ActionListener<ClusterStateUpdateResponse> listener) {
clusterService.submitStateUpdateTask("index-aliases", new AckedClusterStateUpdateTask<ClusterStateUpdateResponse>(Priority.URGENT, request, listener) {
public void indicesAliases(final IndicesAliasesClusterStateUpdateRequest request,
final ActionListener<ClusterStateUpdateResponse> listener) {
clusterService.submitStateUpdateTask("index-aliases",
new AckedClusterStateUpdateTask<ClusterStateUpdateResponse>(Priority.URGENT, request, listener) {
@Override
protected ClusterStateUpdateResponse newResponse(boolean acknowledged) {
return new ClusterStateUpdateResponse(acknowledged);
}
@Override
public ClusterState execute(final ClusterState currentState) {
List<Index> indicesToClose = new ArrayList<>();
Map<String, IndexService> indices = new HashMap<>();
try {
for (AliasAction aliasAction : request.actions()) {
aliasValidator.validateAliasAction(aliasAction, currentState.metaData());
if (!currentState.metaData().hasIndex(aliasAction.index())) {
throw new IndexNotFoundException(aliasAction.index());
}
}
boolean changed = false;
MetaData.Builder builder = MetaData.builder(currentState.metaData());
for (AliasAction aliasAction : request.actions()) {
IndexMetaData indexMetaData = builder.get(aliasAction.index());
if (indexMetaData == null) {
throw new IndexNotFoundException(aliasAction.index());
}
// TODO: not copy (putAll)
IndexMetaData.Builder indexMetaDataBuilder = IndexMetaData.builder(indexMetaData);
if (aliasAction.actionType() == AliasAction.Type.ADD) {
String filter = aliasAction.filter();
if (Strings.hasLength(filter)) {
// parse the filter, in order to validate it
IndexService indexService = indices.get(indexMetaData.getIndex());
if (indexService == null) {
indexService = indicesService.indexService(indexMetaData.getIndex());
if (indexService == null) {
// temporarily create the index and add mappings so we can parse the filter
try {
indexService = indicesService.createIndex(nodeServicesProvider, indexMetaData, Collections.emptyList());
for (ObjectCursor<MappingMetaData> cursor : indexMetaData.getMappings().values()) {
MappingMetaData mappingMetaData = cursor.value;
indexService.mapperService().merge(mappingMetaData.type(), mappingMetaData.source(), MapperService.MergeReason.MAPPING_RECOVERY, false);
}
} catch (Exception e) {
logger.warn("[{}] failed to temporary create in order to apply alias action", e, indexMetaData.getIndex());
continue;
}
indicesToClose.add(indexMetaData.getIndex());
}
indices.put(indexMetaData.getIndex().getName(), indexService);
}
aliasValidator.validateAliasFilter(aliasAction.alias(), filter, indexService.newQueryShardContext());
}
AliasMetaData newAliasMd = AliasMetaData.newAliasMetaDataBuilder(
aliasAction.alias())
.filter(filter)
.indexRouting(aliasAction.indexRouting())
.searchRouting(aliasAction.searchRouting())
.build();
// Check if this alias already exists
AliasMetaData aliasMd = indexMetaData.getAliases().get(aliasAction.alias());
if (aliasMd != null && aliasMd.equals(newAliasMd)) {
// It's the same alias - ignore it
continue;
}
indexMetaDataBuilder.putAlias(newAliasMd);
} else if (aliasAction.actionType() == AliasAction.Type.REMOVE) {
if (!indexMetaData.getAliases().containsKey(aliasAction.alias())) {
// This alias doesn't exist - ignore
continue;
}
indexMetaDataBuilder.removeAlias(aliasAction.alias());
}
changed = true;
builder.put(indexMetaDataBuilder);
}
if (changed) {
ClusterState updatedState = ClusterState.builder(currentState).metaData(builder).build();
// even though changes happened, they resulted in 0 actual changes to metadata
// i.e. remove and add the same alias to the same index
if (!updatedState.metaData().equalsAliases(currentState.metaData())) {
return updatedState;
}
}
return currentState;
} finally {
for (Index index : indicesToClose) {
indicesService.removeIndex(index, "created for alias processing");
}
}
public ClusterState execute(ClusterState currentState) {
return innerExecute(currentState, request.actions());
}
});
}
ClusterState innerExecute(ClusterState currentState, Iterable<AliasAction> actions) {
List<Index> indicesToClose = new ArrayList<>();
Map<String, IndexService> indices = new HashMap<>();
try {
boolean changed = false;
// Gather all the indexes that must be removed first so:
// 1. We don't cause error when attempting to replace an index with a alias of the same name.
// 2. We don't allow removal of aliases from indexes that we're just going to delete anyway. That'd be silly.
Set<Index> indicesToDelete = new HashSet<>();
for (AliasAction action : actions) {
if (action.removeIndex()) {
IndexMetaData index = currentState.metaData().getIndices().get(action.getIndex());
if (index == null) {
throw new IndexNotFoundException(action.getIndex());
}
indicesToDelete.add(index.getIndex());
changed = true;
}
}
// Remove the indexes if there are any to remove
if (changed) {
currentState = deleteIndexService.deleteIndices(currentState, indicesToDelete);
}
MetaData.Builder metadata = MetaData.builder(currentState.metaData());
// Run the remaining alias actions
for (AliasAction action : actions) {
if (action.removeIndex()) {
// Handled above
continue;
}
IndexMetaData index = metadata.get(action.getIndex());
if (index == null) {
throw new IndexNotFoundException(action.getIndex());
}
NewAliasValidator newAliasValidator = (alias, indexRouting, filter) -> {
/* It is important that we look up the index using the metadata builder we are modifying so we can remove an
* index and replace it with an alias. */
Function<String, IndexMetaData> indexLookup = name -> metadata.get(name);
aliasValidator.validateAlias(alias, action.getIndex(), indexRouting, indexLookup);
if (Strings.hasLength(filter)) {
IndexService indexService = indices.get(index.getIndex());
if (indexService == null) {
indexService = indicesService.indexService(index.getIndex());
if (indexService == null) {
// temporarily create the index and add mappings so we can parse the filter
try {
indexService = indicesService.createIndex(nodeServicesProvider, index, emptyList());
} catch (IOException e) {
throw new ElasticsearchException("Failed to create temporary index for parsing the alias", e);
}
for (ObjectCursor<MappingMetaData> cursor : index.getMappings().values()) {
MappingMetaData mappingMetaData = cursor.value;
indexService.mapperService().merge(mappingMetaData.type(), mappingMetaData.source(),
MapperService.MergeReason.MAPPING_RECOVERY, false);
}
indicesToClose.add(index.getIndex());
}
indices.put(action.getIndex(), indexService);
}
aliasValidator.validateAliasFilter(alias, filter, indexService.newQueryShardContext());
}
};
changed |= action.apply(newAliasValidator, metadata, index);
}
if (changed) {
ClusterState updatedState = ClusterState.builder(currentState).metaData(metadata).build();
// even though changes happened, they resulted in 0 actual changes to metadata
// i.e. remove and add the same alias to the same index
if (!updatedState.metaData().equalsAliases(currentState.metaData())) {
return updatedState;
}
}
return currentState;
} finally {
for (Index index : indicesToClose) {
indicesService.removeIndex(index, "created for alias processing");
}
}
}
}

View File

@ -19,12 +19,15 @@
package org.elasticsearch.common.xcontent;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.util.Collections;
import java.util.Set;
/**
* A generic abstraction on top of handling content, inspired by JSON and pull parsing.
@ -42,27 +45,20 @@ public interface XContent {
* Creates a new generator using the provided output stream.
*/
default XContentGenerator createGenerator(OutputStream os) throws IOException {
return createGenerator(os, null, true);
return createGenerator(os, Collections.emptySet(), Collections.emptySet());
}
/**
* Creates a new generator using the provided output stream and some
* inclusive filters. Same as createGenerator(os, filters, true).
*/
default XContentGenerator createGenerator(OutputStream os, String[] filters) throws IOException {
return createGenerator(os, filters, true);
}
/**
* Creates a new generator using the provided output stream and some
* filters.
* Creates a new generator using the provided output stream and some inclusive and/or exclusive filters. When both exclusive and
* inclusive filters are provided, the underlying generator will first use exclusion filters to remove fields and then will check the
* remaining fields against the inclusive filters.
*
* @param inclusive
* If true only paths matching a filter will be included in
* output. If false no path matching a filter will be included in
* output
* @param os the output stream
* @param includes the inclusive filters: only fields and objects that match the inclusive filters will be written to the output.
* @param excludes the exclusive filters: only fields and objects that don't match the exclusive filters will be written to the output.
*/
XContentGenerator createGenerator(OutputStream os, String[] filters, boolean inclusive) throws IOException;
XContentGenerator createGenerator(OutputStream os, Set<String> includes, Set<String> excludes) throws IOException;
/**
* Creates a parser over the provided string content.
*/

View File

@ -19,21 +19,8 @@
package org.elasticsearch.common.xcontent;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Path;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.io.BytesStream;
@ -47,6 +34,21 @@ import org.joda.time.ReadableInstant;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Path;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* A utility to build XContent (ie json).
*/
@ -58,12 +60,8 @@ public final class XContentBuilder implements BytesStream, Releasable {
return new XContentBuilder(xContent, new BytesStreamOutput());
}
public static XContentBuilder builder(XContent xContent, String[] filters) throws IOException {
return new XContentBuilder(xContent, new BytesStreamOutput(), filters);
}
public static XContentBuilder builder(XContent xContent, String[] filters, boolean inclusive) throws IOException {
return new XContentBuilder(xContent, new BytesStreamOutput(), filters, inclusive);
public static XContentBuilder builder(XContent xContent, Set<String> includes, Set<String> excludes) throws IOException {
return new XContentBuilder(xContent, new BytesStreamOutput(), includes, excludes);
}
private XContentGenerator generator;
@ -77,7 +75,7 @@ public final class XContentBuilder implements BytesStream, Releasable {
* to call {@link #close()} when the builder is done with.
*/
public XContentBuilder(XContent xContent, OutputStream bos) throws IOException {
this(xContent, bos, null);
this(xContent, bos, Collections.emptySet(), Collections.emptySet());
}
/**
@ -86,20 +84,24 @@ public final class XContentBuilder implements BytesStream, Releasable {
* filter will be written to the output stream. Make sure to call
* {@link #close()} when the builder is done with.
*/
public XContentBuilder(XContent xContent, OutputStream bos, String[] filters) throws IOException {
this(xContent, bos, filters, true);
public XContentBuilder(XContent xContent, OutputStream bos, Set<String> includes) throws IOException {
this(xContent, bos, includes, Collections.emptySet());
}
/**
* Constructs a new builder using the provided xcontent, an OutputStream and
* some filters. If {@code filters} are specified and {@code inclusive} is
* true, only those values matching a filter will be written to the output
* stream. If {@code inclusive} is false, those matching will be excluded.
* Creates a new builder using the provided XContent, output stream and some inclusive and/or exclusive filters. When both exclusive and
* inclusive filters are provided, the underlying builder will first use exclusion filters to remove fields and then will check the
* remaining fields against the inclusive filters.
* <p>
* Make sure to call {@link #close()} when the builder is done with.
*
* @param os the output stream
* @param includes the inclusive filters: only fields and objects that match the inclusive filters will be written to the output.
* @param excludes the exclusive filters: only fields and objects that don't match the exclusive filters will be written to the output.
*/
public XContentBuilder(XContent xContent, OutputStream bos, String[] filters, boolean inclusive) throws IOException {
this.bos = bos;
this.generator = xContent.createGenerator(bos, filters, inclusive);
public XContentBuilder(XContent xContent, OutputStream os, Set<String> includes, Set<String> excludes) throws IOException {
this.bos = os;
this.generator = xContent.createGenerator(bos, includes, excludes);
}
public XContentType contentType() {

View File

@ -35,6 +35,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.util.Set;
/**
* A CBOR based content implementation using Jackson.
@ -70,8 +71,8 @@ public class CborXContent implements XContent {
}
@Override
public XContentGenerator createGenerator(OutputStream os, String[] filters, boolean inclusive) throws IOException {
return new CborXContentGenerator(cborFactory.createGenerator(os, JsonEncoding.UTF8), os, filters, inclusive);
public XContentGenerator createGenerator(OutputStream os, Set<String> includes, Set<String> excludes) throws IOException {
return new CborXContentGenerator(cborFactory.createGenerator(os, JsonEncoding.UTF8), os, includes, excludes);
}
@Override

View File

@ -20,23 +20,22 @@
package org.elasticsearch.common.xcontent.cbor;
import com.fasterxml.jackson.core.JsonGenerator;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContentGenerator;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Set;
/**
*
*/
public class CborXContentGenerator extends JsonXContentGenerator {
public CborXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, String... filters) {
this(jsonGenerator, os, filters, true);
public CborXContentGenerator(JsonGenerator jsonGenerator, OutputStream os) {
this(jsonGenerator, os, Collections.emptySet(), Collections.emptySet());
}
public CborXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, String[] filters, boolean inclusive) {
super(jsonGenerator, os, filters, inclusive);
public CborXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, Set<String> includes, Set<String> excludes) {
super(jsonGenerator, os, includes, excludes);
}
@Override

View File

@ -35,6 +35,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.util.Set;
/**
* A JSON based content implementation using Jackson.
@ -92,8 +93,8 @@ public class JsonXContent implements XContent {
}
@Override
public XContentGenerator createGenerator(OutputStream os, String[] filters, boolean inclusive) throws IOException {
return new JsonXContentGenerator(jsonFactory.createGenerator(os, JsonEncoding.UTF8), os, filters, inclusive);
public XContentGenerator createGenerator(OutputStream os, Set<String> includes, Set<String> excludes) throws IOException {
return new JsonXContentGenerator(jsonFactory.createGenerator(os, JsonEncoding.UTF8), os, includes, excludes);
}
@Override

View File

@ -27,10 +27,10 @@ import com.fasterxml.jackson.core.io.SerializedString;
import com.fasterxml.jackson.core.json.JsonWriteContext;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.core.util.JsonGeneratorDelegate;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.util.CollectionUtils;
import org.elasticsearch.common.xcontent.XContent;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentGenerator;
@ -43,6 +43,9 @@ import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
/**
*
@ -72,23 +75,38 @@ public class JsonXContentGenerator implements XContentGenerator {
private static final DefaultPrettyPrinter.Indenter INDENTER = new DefaultIndenter(" ", LF.getValue());
private boolean prettyPrint = false;
public JsonXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, String[] filters, boolean inclusive) {
public JsonXContentGenerator(JsonGenerator jsonGenerator, OutputStream os) {
this(jsonGenerator, os, Collections.emptySet(), Collections.emptySet());
}
public JsonXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, Set<String> includes, Set<String> excludes) {
Objects.requireNonNull(includes, "Including filters must not be null");
Objects.requireNonNull(excludes, "Excluding filters must not be null");
this.os = os;
if (jsonGenerator instanceof GeneratorBase) {
this.base = (GeneratorBase) jsonGenerator;
} else {
this.base = null;
}
if (CollectionUtils.isEmpty(filters)) {
this.generator = jsonGenerator;
this.filter = null;
} else {
this.filter = new FilteringGeneratorDelegate(jsonGenerator,
new FilterPathBasedFilter(filters, inclusive), true, true);
this.generator = this.filter;
JsonGenerator generator = jsonGenerator;
boolean hasExcludes = excludes.isEmpty() == false;
if (hasExcludes) {
generator = new FilteringGeneratorDelegate(generator, new FilterPathBasedFilter(excludes, false), true, true);
}
this.os = os;
boolean hasIncludes = includes.isEmpty() == false;
if (hasIncludes) {
generator = new FilteringGeneratorDelegate(generator, new FilterPathBasedFilter(includes, true), true, true);
}
if (hasExcludes || hasIncludes) {
this.filter = (FilteringGeneratorDelegate) generator;
} else {
this.filter = null;
}
this.generator = generator;
}
@Override
@ -122,23 +140,34 @@ public class JsonXContentGenerator implements XContentGenerator {
generator.writeEndArray();
}
protected boolean isFiltered() {
private boolean isFiltered() {
return filter != null;
}
protected boolean inRoot() {
private JsonGenerator getLowLevelGenerator() {
if (isFiltered()) {
JsonStreamContext context = filter.getFilterContext();
return ((context != null) && (context.inRoot() && context.getCurrentName() == null));
JsonGenerator delegate = filter.getDelegate();
if (delegate instanceof JsonGeneratorDelegate) {
// In case of combined inclusion and exclusion filters, we have one and only one another delegating level
delegate = ((JsonGeneratorDelegate) delegate).getDelegate();
assert delegate instanceof JsonGeneratorDelegate == false;
}
return delegate;
}
return false;
return generator;
}
private boolean inRoot() {
JsonStreamContext context = generator.getOutputContext();
return ((context != null) && (context.inRoot() && context.getCurrentName() == null));
}
@Override
public void writeStartObject() throws IOException {
if (isFiltered() && inRoot()) {
// Bypass generator to always write the root start object
filter.getDelegate().writeStartObject();
if (inRoot()) {
// Use the low level generator to write the startObject so that the root
// start object is always written even if a filtered generator is used
getLowLevelGenerator().writeStartObject();
return;
}
generator.writeStartObject();
@ -146,9 +175,10 @@ public class JsonXContentGenerator implements XContentGenerator {
@Override
public void writeEndObject() throws IOException {
if (isFiltered() && inRoot()) {
// Bypass generator to always write the root end object
filter.getDelegate().writeEndObject();
if (inRoot()) {
// Use the low level generator to write the startObject so that the root
// start object is always written even if a filtered generator is used
getLowLevelGenerator().writeEndObject();
return;
}
generator.writeEndObject();
@ -390,7 +420,8 @@ public class JsonXContentGenerator implements XContentGenerator {
}
if (writeLineFeedAtEnd) {
flush();
generator.writeRaw(LF);
// Bypass generator to always write the line feed
getLowLevelGenerator().writeRaw(LF);
}
generator.close();
}

View File

@ -35,6 +35,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.util.Set;
/**
* A Smile based content implementation using Jackson.
@ -71,8 +72,8 @@ public class SmileXContent implements XContent {
}
@Override
public XContentGenerator createGenerator(OutputStream os, String[] filters, boolean inclusive) throws IOException {
return new SmileXContentGenerator(smileFactory.createGenerator(os, JsonEncoding.UTF8), os, filters, inclusive);
public XContentGenerator createGenerator(OutputStream os, Set<String> includes, Set<String> excludes) throws IOException {
return new SmileXContentGenerator(smileFactory.createGenerator(os, JsonEncoding.UTF8), os, includes, excludes);
}
@Override

View File

@ -20,23 +20,22 @@
package org.elasticsearch.common.xcontent.smile;
import com.fasterxml.jackson.core.JsonGenerator;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContentGenerator;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Set;
/**
*
*/
public class SmileXContentGenerator extends JsonXContentGenerator {
public SmileXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, String... filters) {
this(jsonGenerator, os, filters, true);
public SmileXContentGenerator(JsonGenerator jsonGenerator, OutputStream os) {
this(jsonGenerator, os, Collections.emptySet(), Collections.emptySet());
}
public SmileXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, String[] filters, boolean inclusive) {
super(jsonGenerator, os, filters, inclusive);
public SmileXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, Set<String> includes, Set<String> excludes) {
super(jsonGenerator, os, includes, excludes);
}
@Override

View File

@ -21,10 +21,10 @@
package org.elasticsearch.common.xcontent.support.filtering;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class FilterPath {
@ -75,8 +75,8 @@ public class FilterPath {
return next;
}
public static FilterPath[] compile(String... filters) {
if (CollectionUtils.isEmpty(filters)) {
public static FilterPath[] compile(Set<String> filters) {
if (filters == null || filters.isEmpty()) {
return null;
}

View File

@ -24,6 +24,7 @@ import org.elasticsearch.common.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class FilterPathBasedFilter extends TokenFilter {
@ -53,7 +54,7 @@ public class FilterPathBasedFilter extends TokenFilter {
this.filters = filters;
}
public FilterPathBasedFilter(String[] filters, boolean inclusive) {
public FilterPathBasedFilter(Set<String> filters, boolean inclusive) {
this(FilterPath.compile(filters), inclusive);
}
@ -103,11 +104,6 @@ public class FilterPathBasedFilter extends TokenFilter {
@Override
protected boolean _includeScalar() {
for (FilterPath filter : filters) {
if (filter.matches()) {
return inclusive;
}
}
return !inclusive;
}
}

View File

@ -34,6 +34,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.util.Set;
/**
* A YAML based content implementation using Jackson.
@ -66,8 +67,8 @@ public class YamlXContent implements XContent {
}
@Override
public XContentGenerator createGenerator(OutputStream os, String[] filters, boolean inclusive) throws IOException {
return new YamlXContentGenerator(yamlFactory.createGenerator(os, JsonEncoding.UTF8), os, filters, inclusive);
public XContentGenerator createGenerator(OutputStream os, Set<String> includes, Set<String> excludes) throws IOException {
return new YamlXContentGenerator(yamlFactory.createGenerator(os, JsonEncoding.UTF8), os, includes, excludes);
}
@Override

View File

@ -20,23 +20,22 @@
package org.elasticsearch.common.xcontent.yaml;
import com.fasterxml.jackson.core.JsonGenerator;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContentGenerator;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Set;
/**
*
*/
public class YamlXContentGenerator extends JsonXContentGenerator {
public YamlXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, String... filters) {
this(jsonGenerator, os, filters, true);
public YamlXContentGenerator(JsonGenerator jsonGenerator, OutputStream os) {
this(jsonGenerator, os, Collections.emptySet(), Collections.emptySet());
}
public YamlXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, String[] filters, boolean inclusive) {
super(jsonGenerator, os, filters, inclusive);
public YamlXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, Set<String> includes, Set<String> excludes) {
super(jsonGenerator, os, includes, excludes);
}
@Override

View File

@ -166,6 +166,17 @@ public final class IngestDocument {
* @throws IllegalArgumentException if the path is null, empty or invalid.
*/
public boolean hasField(String path) {
return hasField(path, false);
}
/**
* Checks whether the document contains a value for the provided path
* @param path The path within the document in dot-notation
* @param failOutOfRange Whether to throw an IllegalArgumentException if array is accessed outside of its range
* @return true if the document contains a value for the field, false otherwise
* @throws IllegalArgumentException if the path is null, empty or invalid.
*/
public boolean hasField(String path, boolean failOutOfRange) {
FieldPath fieldPath = new FieldPath(path);
Object context = fieldPath.initialContext;
for (int i = 0; i < fieldPath.pathElements.length - 1; i++) {
@ -183,7 +194,12 @@ public final class IngestDocument {
try {
int index = Integer.parseInt(pathElement);
if (index < 0 || index >= list.size()) {
return false;
if (failOutOfRange) {
throw new IllegalArgumentException("[" + index + "] is out of bounds for array with length [" +
list.size() + "] as part of path [" + path +"]");
} else {
return false;
}
}
context = list.get(index);
} catch (NumberFormatException e) {
@ -206,7 +222,16 @@ public final class IngestDocument {
List<Object> list = (List<Object>) context;
try {
int index = Integer.parseInt(leafKey);
return index >= 0 && index < list.size();
if (index >= 0 && index < list.size()) {
return true;
} else {
if (failOutOfRange) {
throw new IllegalArgumentException("[" + index + "] is out of bounds for array with length [" +
list.size() + "] as part of path [" + path +"]");
} else {
return false;
}
}
} catch (NumberFormatException e) {
return false;
}

View File

@ -19,6 +19,7 @@
package org.elasticsearch.rest;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
@ -26,9 +27,17 @@ import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import java.io.IOException;
import java.util.Collections;
import java.util.Set;
import java.util.function.Predicate;
import static java.util.stream.Collectors.toSet;
public abstract class AbstractRestChannel implements RestChannel {
private static final Predicate<String> INCLUDE_FILTER = f -> f.charAt(0) != '-';
private static final Predicate<String> EXCLUDE_FILTER = INCLUDE_FILTER.negate();
protected final RestRequest request;
protected final boolean detailedErrorsEnabled;
@ -41,7 +50,7 @@ public abstract class AbstractRestChannel implements RestChannel {
@Override
public XContentBuilder newBuilder() throws IOException {
return newBuilder(request.hasContent() ? request.content() : null, request.hasParam("filter_path"));
return newBuilder(request.hasContent() ? request.content() : null, true);
}
@Override
@ -64,8 +73,15 @@ public abstract class AbstractRestChannel implements RestChannel {
contentType = XContentType.JSON;
}
String[] filters = useFiltering ? request.paramAsStringArrayOrEmptyIfAll("filter_path") : null;
XContentBuilder builder = new XContentBuilder(XContentFactory.xContent(contentType), bytesOutput(), filters);
Set<String> includes = Collections.emptySet();
Set<String> excludes = Collections.emptySet();
if (useFiltering) {
Set<String> filters = Strings.splitStringByCommaToSet(request.param("filter_path", null));
includes = filters.stream().filter(INCLUDE_FILTER).collect(toSet());
excludes = filters.stream().filter(EXCLUDE_FILTER).map(f -> f.substring(1)).collect(toSet());
}
XContentBuilder builder = new XContentBuilder(XContentFactory.xContent(contentType), bytesOutput(), includes, excludes);
if (request.paramAsBoolean("pretty", false)) {
builder.prettyPrint().lfAtEnd();
}

View File

@ -20,6 +20,7 @@ package org.elasticsearch.rest.action.admin.indices;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject;
@ -49,7 +50,7 @@ public class RestIndexDeleteAliasesAction extends BaseRestHandler {
final String[] aliases = Strings.splitStringByCommaToArray(request.param("name"));
IndicesAliasesRequest indicesAliasesRequest = new IndicesAliasesRequest();
indicesAliasesRequest.timeout(request.paramAsTime("timeout", indicesAliasesRequest.timeout()));
indicesAliasesRequest.removeAlias(indices, aliases);
indicesAliasesRequest.addAliasAction(AliasActions.remove().indices(indices).aliases(aliases));
indicesAliasesRequest.masterNodeTimeout(request.paramAsTime("master_timeout", indicesAliasesRequest.masterNodeTimeout()));
client.admin().indices().aliases(indicesAliasesRequest, new AcknowledgedRestListener<IndicesAliasesResponse>(channel));

View File

@ -20,9 +20,7 @@ package org.elasticsearch.rest.action.admin.indices;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.cluster.metadata.AliasAction;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
@ -103,12 +101,9 @@ public class RestIndexPutAliasAction extends BaseRestHandler {
IndicesAliasesRequest indicesAliasesRequest = new IndicesAliasesRequest();
indicesAliasesRequest.timeout(request.paramAsTime("timeout", indicesAliasesRequest.timeout()));
String[] aliases = new String[]{alias};
IndicesAliasesRequest.AliasActions aliasAction = new AliasActions(AliasAction.Type.ADD, indices, aliases);
indicesAliasesRequest.addAliasAction(aliasAction);
indicesAliasesRequest.masterNodeTimeout(request.paramAsTime("master_timeout", indicesAliasesRequest.masterNodeTimeout()));
IndicesAliasesRequest.AliasActions aliasAction = AliasActions.add().indices(indices).alias(alias);
if (routing != null) {
aliasAction.routing(routing);
}
@ -121,6 +116,7 @@ public class RestIndexPutAliasAction extends BaseRestHandler {
if (filter != null) {
aliasAction.filter(filter);
}
client.admin().indices().aliases(indicesAliasesRequest, new AcknowledgedRestListener<IndicesAliasesResponse>(channel));
indicesAliasesRequest.addAliasAction(aliasAction);
client.admin().indices().aliases(indicesAliasesRequest, new AcknowledgedRestListener<>(channel));
}
}

View File

@ -23,9 +23,12 @@ import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.cluster.metadata.AliasAction;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.ParseFieldMatcherSupplier;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.rest.BaseRestHandler;
@ -34,13 +37,17 @@ import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.action.AcknowledgedRestListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static org.elasticsearch.rest.RestRequest.Method.POST;
public class RestIndicesAliasesAction extends BaseRestHandler {
static final ObjectParser<IndicesAliasesRequest, ParseFieldMatcherSupplier> PARSER = new ObjectParser<>("aliases");
static {
PARSER.declareObjectArray((request, actions) -> {
for (AliasActions action: actions) {
request.addAliasAction(action);
}
}, AliasActions.PARSER, new ParseField("actions"));
}
@Inject
public RestIndicesAliasesAction(Settings settings, RestController controller) {
@ -52,104 +59,12 @@ public class RestIndicesAliasesAction extends BaseRestHandler {
public void handleRequest(final RestRequest request, final RestChannel channel, final NodeClient client) throws Exception {
IndicesAliasesRequest indicesAliasesRequest = new IndicesAliasesRequest();
indicesAliasesRequest.masterNodeTimeout(request.paramAsTime("master_timeout", indicesAliasesRequest.masterNodeTimeout()));
indicesAliasesRequest.timeout(request.paramAsTime("timeout", indicesAliasesRequest.timeout()));
try (XContentParser parser = XContentFactory.xContent(request.content()).createParser(request.content())) {
// {
// actions : [
// { add : { index : "test1", alias : "alias1", filter : {"user" : "kimchy"} } }
// { remove : { index : "test1", alias : "alias1" } }
// ]
// }
indicesAliasesRequest.timeout(request.paramAsTime("timeout", indicesAliasesRequest.timeout()));
XContentParser.Token token = parser.nextToken();
if (token == null) {
throw new IllegalArgumentException("No action is specified");
}
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.START_ARRAY) {
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
if (token == XContentParser.Token.FIELD_NAME) {
String action = parser.currentName();
AliasAction.Type type;
if ("add".equals(action)) {
type = AliasAction.Type.ADD;
} else if ("remove".equals(action)) {
type = AliasAction.Type.REMOVE;
} else {
throw new IllegalArgumentException("Alias action [" + action + "] not supported");
}
String[] indices = null;
String[] aliases = null;
Map<String, Object> filter = null;
String routing = null;
boolean routingSet = false;
String indexRouting = null;
boolean indexRoutingSet = false;
String searchRouting = null;
boolean searchRoutingSet = false;
String currentFieldName = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else if (token.isValue()) {
if ("index".equals(currentFieldName)) {
indices = new String[] { parser.text() };
} else if ("alias".equals(currentFieldName)) {
aliases = new String[] { parser.text() };
} else if ("routing".equals(currentFieldName)) {
routing = parser.textOrNull();
routingSet = true;
} else if ("indexRouting".equals(currentFieldName)
|| "index-routing".equals(currentFieldName) || "index_routing".equals(currentFieldName)) {
indexRouting = parser.textOrNull();
indexRoutingSet = true;
} else if ("searchRouting".equals(currentFieldName)
|| "search-routing".equals(currentFieldName) || "search_routing".equals(currentFieldName)) {
searchRouting = parser.textOrNull();
searchRoutingSet = true;
}
} else if (token == XContentParser.Token.START_ARRAY) {
if ("indices".equals(currentFieldName)) {
List<String> indexNames = new ArrayList<>();
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
String index = parser.text();
indexNames.add(index);
}
indices = indexNames.toArray(new String[indexNames.size()]);
}
if ("aliases".equals(currentFieldName)) {
List<String> aliasNames = new ArrayList<>();
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
String alias = parser.text();
aliasNames.add(alias);
}
aliases = aliasNames.toArray(new String[aliasNames.size()]);
}
} else if (token == XContentParser.Token.START_OBJECT) {
if ("filter".equals(currentFieldName)) {
filter = parser.mapOrdered();
}
}
}
if (type == AliasAction.Type.ADD) {
AliasActions aliasActions = new AliasActions(type, indices, aliases).filter(filter);
if (routingSet) {
aliasActions.routing(routing);
}
if (indexRoutingSet) {
aliasActions.indexRouting(indexRouting);
}
if (searchRoutingSet) {
aliasActions.searchRouting(searchRouting);
}
indicesAliasesRequest.addAliasAction(aliasActions);
} else if (type == AliasAction.Type.REMOVE) {
indicesAliasesRequest.removeAlias(indices, aliases);
}
}
}
}
}
PARSER.parse(parser, indicesAliasesRequest, () -> ParseFieldMatcher.STRICT);
}
if (indicesAliasesRequest.getAliasActions().isEmpty()) {
throw new IllegalArgumentException("No action specified");
}
client.admin().indices().aliases(indicesAliasesRequest, new AcknowledgedRestListener<IndicesAliasesResponse>(channel));
}

View File

@ -67,7 +67,6 @@ import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
@ -76,15 +75,12 @@ import java.util.stream.StreamSupport;
*/
public class SearchPhaseController extends AbstractComponent {
public static final Comparator<AtomicArray.Entry<? extends QuerySearchResultProvider>> QUERY_RESULT_ORDERING = new Comparator<AtomicArray.Entry<? extends QuerySearchResultProvider>>() {
@Override
public int compare(AtomicArray.Entry<? extends QuerySearchResultProvider> o1, AtomicArray.Entry<? extends QuerySearchResultProvider> o2) {
int i = o1.value.shardTarget().index().compareTo(o2.value.shardTarget().index());
if (i == 0) {
i = o1.value.shardTarget().shardId().id() - o2.value.shardTarget().shardId().id();
}
return i;
public static final Comparator<AtomicArray.Entry<? extends QuerySearchResultProvider>> QUERY_RESULT_ORDERING = (o1, o2) -> {
int i = o1.value.shardTarget().index().compareTo(o2.value.shardTarget().index());
if (i == 0) {
i = o1.value.shardTarget().shardId().id() - o2.value.shardTarget().shardId().id();
}
return i;
};
public static final ScoreDoc[] EMPTY_DOCS = new ScoreDoc[0];

View File

@ -0,0 +1,350 @@
/*
* 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.action.admin.indices.alias;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.arrayWithSize;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
public class AliasActionsTests extends ESTestCase {
public void testValidate() {
AliasActions.Type type = randomFrom(AliasActions.Type.values());
if (type == AliasActions.Type.REMOVE_INDEX) {
Exception e = expectThrows(IllegalArgumentException.class, () -> new AliasActions(type).validate());
assertEquals("One of [index] or [indices] is required", e.getMessage());
} else {
Exception e = expectThrows(IllegalArgumentException.class,
() -> new AliasActions(type).alias(randomAsciiOfLength(5)).validate());
assertEquals("One of [index] or [indices] is required", e.getMessage());
e = expectThrows(IllegalArgumentException.class, () -> new AliasActions(type).index(randomAsciiOfLength(5)).validate());
assertEquals("One of [alias] or [aliases] is required", e.getMessage());
}
}
public void testEmptyIndex() {
Exception e = expectThrows(IllegalArgumentException.class,
() -> new AliasActions(randomFrom(AliasActions.Type.values())).index(null));
assertEquals("[index] can't be empty string", e.getMessage());
e = expectThrows(IllegalArgumentException.class,
() -> new AliasActions(randomFrom(AliasActions.Type.values())).index(""));
assertEquals("[index] can't be empty string", e.getMessage());
e = expectThrows(IllegalArgumentException.class,
() -> new AliasActions(randomFrom(AliasActions.Type.values())).indices((String[]) null));
assertEquals("[indices] can't be empty", e.getMessage());
e = expectThrows(IllegalArgumentException.class,
() -> new AliasActions(randomFrom(AliasActions.Type.values())).indices(new String[0]));
assertEquals("[indices] can't be empty", e.getMessage());
e = expectThrows(IllegalArgumentException.class,
() -> new AliasActions(randomFrom(AliasActions.Type.values())).indices("test", null));
assertEquals("[indices] can't contain empty string", e.getMessage());
e = expectThrows(IllegalArgumentException.class,
() -> new AliasActions(randomFrom(AliasActions.Type.values())).indices("test", ""));
assertEquals("[indices] can't contain empty string", e.getMessage());
}
public void testEmptyAlias() {
AliasActions.Type type = randomValueOtherThan(AliasActions.Type.REMOVE_INDEX, () -> randomFrom(AliasActions.Type.values()));
Exception e = expectThrows(IllegalArgumentException.class, () -> new AliasActions(type).alias(null));
assertEquals("[alias] can't be empty string", e.getMessage());
e = expectThrows(IllegalArgumentException.class, () -> new AliasActions(type).alias(""));
assertEquals("[alias] can't be empty string", e.getMessage());
e = expectThrows(IllegalArgumentException.class, () -> new AliasActions(type).aliases((String[]) null));
assertEquals("[aliases] can't be empty", e.getMessage());
e = expectThrows(IllegalArgumentException.class, () -> new AliasActions(type).aliases(new String[0]));
assertEquals("[aliases] can't be empty", e.getMessage());
e = expectThrows(IllegalArgumentException.class, () -> new AliasActions(type).aliases("test", null));
assertEquals("[aliases] can't contain empty string", e.getMessage());
e = expectThrows(IllegalArgumentException.class, () -> new AliasActions(type).aliases("test", ""));
assertEquals("[aliases] can't contain empty string", e.getMessage());
}
public void testBadOptionsInNonIndex() {
AliasActions action = randomBoolean() ? AliasActions.remove() : AliasActions.removeIndex();
Exception e = expectThrows(IllegalArgumentException.class, () -> action.routing("test"));
assertEquals("[routing] is unsupported for [" + action.actionType() + "]", e.getMessage());
e = expectThrows(IllegalArgumentException.class, () -> action.searchRouting("test"));
assertEquals("[search_routing] is unsupported for [" + action.actionType() + "]", e.getMessage());
e = expectThrows(IllegalArgumentException.class, () -> action.indexRouting("test"));
assertEquals("[index_routing] is unsupported for [" + action.actionType() + "]", e.getMessage());
e = expectThrows(IllegalArgumentException.class, () -> action.filter("test"));
assertEquals("[filter] is unsupported for [" + action.actionType() + "]", e.getMessage());
}
public void testParseAdd() throws IOException {
String[] indices = generateRandomStringArray(10, 5, false, false);
String[] aliases = generateRandomStringArray(10, 5, false, false);
Map<String, Object> filter = randomBoolean() ? randomMap(5) : null;
Object searchRouting = randomBoolean() ? randomRouting() : null;
Object indexRouting = randomBoolean() ? randomBoolean() ? searchRouting : randomRouting() : null;
XContentBuilder b = XContentBuilder.builder(randomFrom(XContentType.values()).xContent());
b.startObject(); {
b.startObject("add"); {
if (indices.length > 1 || randomBoolean()) {
b.field("indices", indices);
} else {
b.field("index", indices[0]);
}
if (aliases.length > 1 || randomBoolean()) {
b.field("aliases", aliases);
} else {
b.field("alias", aliases[0]);
}
if (filter != null) {
b.field("filter", filter);
}
if (searchRouting != null) {
if (searchRouting.equals(indexRouting)) {
b.field("routing", searchRouting);
} else {
b.field("search_routing", searchRouting);
}
}
if (indexRouting != null && false == indexRouting.equals(searchRouting)) {
b.field("index_routing", indexRouting);
}
}
b.endObject();
}
b.endObject();
b = shuffleXContent(b, "filter");
try (XContentParser parser = XContentHelper.createParser(b.bytes())) {
AliasActions action = AliasActions.PARSER.apply(parser, () -> ParseFieldMatcher.STRICT);
assertEquals(AliasActions.Type.ADD, action.actionType());
assertThat(action.indices(), equalTo(indices));
assertThat(action.aliases(), equalTo(aliases));
if (filter == null || filter.isEmpty()) {
assertNull(action.filter());
} else {
assertEquals(XContentFactory.contentBuilder(XContentType.JSON).map(filter).string(), action.filter());
}
assertEquals(Objects.toString(searchRouting, null), action.searchRouting());
assertEquals(Objects.toString(indexRouting, null), action.indexRouting());
}
}
public void testParseAddDefaultRouting() throws IOException {
String index = randomAsciiOfLength(5);
String alias = randomAsciiOfLength(5);
Object searchRouting = randomRouting();
Object indexRouting = randomRouting();
XContentBuilder b = XContentBuilder.builder(randomFrom(XContentType.values()).xContent());
b.startObject(); {
b.startObject("add"); {
b.field("index", index);
b.field("alias", alias);
if (randomBoolean()) {
b.field("routing", searchRouting);
b.field("index_routing", indexRouting);
} else {
b.field("search_routing", searchRouting);
b.field("routing", indexRouting);
}
}
b.endObject();
}
b.endObject();
b = shuffleXContent(b);
try (XContentParser parser = XContentHelper.createParser(b.bytes())) {
AliasActions action = AliasActions.PARSER.apply(parser, () -> ParseFieldMatcher.STRICT);
assertEquals(AliasActions.Type.ADD, action.actionType());
assertThat(action.indices(), arrayContaining(index));
assertThat(action.aliases(), arrayContaining(alias));
assertEquals(searchRouting.toString(), action.searchRouting());
assertEquals(indexRouting.toString(), action.indexRouting());
}
}
public void testParseRemove() throws IOException {
String[] indices = generateRandomStringArray(10, 5, false, false);
String[] aliases = generateRandomStringArray(10, 5, false, false);
XContentBuilder b = XContentBuilder.builder(randomFrom(XContentType.values()).xContent());
b.startObject(); {
b.startObject("remove"); {
if (indices.length > 1 || randomBoolean()) {
b.field("indices", indices);
} else {
b.field("index", indices[0]);
}
if (aliases.length > 1 || randomBoolean()) {
b.field("aliases", aliases);
} else {
b.field("alias", aliases[0]);
}
}
b.endObject();
}
b.endObject();
b = shuffleXContent(b);
try (XContentParser parser = XContentHelper.createParser(b.bytes())) {
AliasActions action = AliasActions.PARSER.apply(parser, () -> ParseFieldMatcher.STRICT);
assertEquals(AliasActions.Type.REMOVE, action.actionType());
assertThat(action.indices(), equalTo(indices));
assertThat(action.aliases(), equalTo(aliases));
}
}
public void testParseRemoveIndex() throws IOException {
String[] indices = randomBoolean() ? new String[] {randomAsciiOfLength(5)} : generateRandomStringArray(10, 5, false, false);
XContentBuilder b = XContentBuilder.builder(randomFrom(XContentType.values()).xContent());
b.startObject(); {
b.startObject("remove_index"); {
if (indices.length > 1 || randomBoolean()) {
b.field("indices", indices);
} else {
b.field("index", indices[0]);
}
}
b.endObject();
}
b.endObject();
b = shuffleXContent(b);
try (XContentParser parser = XContentHelper.createParser(b.bytes())) {
AliasActions action = AliasActions.PARSER.apply(parser, () -> ParseFieldMatcher.STRICT);
assertEquals(AliasActions.Type.REMOVE_INDEX, action.actionType());
assertArrayEquals(indices, action.indices());
assertThat(action.aliases(), arrayWithSize(0));
}
}
public void testParseIndexAndIndicesThrowsError() throws IOException {
XContentBuilder b = XContentBuilder.builder(randomFrom(XContentType.values()).xContent());
b.startObject(); {
b.startObject(randomFrom("add", "remove")); {
b.field("index", randomAsciiOfLength(5));
b.field("indices", generateRandomStringArray(10, 5, false, false));
b.field("alias", randomAsciiOfLength(5));
}
b.endObject();
}
b.endObject();
try (XContentParser parser = XContentHelper.createParser(b.bytes())) {
Exception e = expectThrows(ParsingException.class, () -> AliasActions.PARSER.apply(parser, () -> ParseFieldMatcher.STRICT));
assertThat(e.getCause().getCause(), instanceOf(IllegalArgumentException.class));
assertEquals("Only one of [index] and [indices] is supported", e.getCause().getCause().getMessage());
}
}
public void testParseAliasAndAliasesThrowsError() throws IOException {
XContentBuilder b = XContentBuilder.builder(randomFrom(XContentType.values()).xContent());
b.startObject(); {
b.startObject(randomFrom("add", "remove")); {
b.field("index", randomAsciiOfLength(5));
b.field("alias", randomAsciiOfLength(5));
b.field("aliases", generateRandomStringArray(10, 5, false, false));
}
b.endObject();
}
b.endObject();
try (XContentParser parser = XContentHelper.createParser(b.bytes())) {
Exception e = expectThrows(ParsingException.class, () -> AliasActions.PARSER.apply(parser, () -> ParseFieldMatcher.STRICT));
assertThat(e.getCause().getCause(), instanceOf(IllegalArgumentException.class));
assertEquals("Only one of [alias] and [aliases] is supported", e.getCause().getCause().getMessage());
}
}
public void testRoundTrip() throws IOException {
AliasActions action = new AliasActions(randomFrom(AliasActions.Type.values()));
if (randomBoolean()) {
action.index(randomAsciiOfLength(5));
} else {
action.indices(generateRandomStringArray(5, 5, false, false));
}
if (action.actionType() != AliasActions.Type.REMOVE_INDEX) {
if (randomBoolean()) {
action.alias(randomAsciiOfLength(5));
} else {
action.aliases(generateRandomStringArray(5, 5, false, false));
}
}
if (action.actionType() == AliasActions.Type.ADD) {
if (randomBoolean()) {
action.filter(randomAsciiOfLength(10));
}
if (randomBoolean()) {
if (randomBoolean()) {
action.routing(randomAsciiOfLength(5));
} else {
action.searchRouting(randomAsciiOfLength(5));
action.indexRouting(randomAsciiOfLength(5));
}
}
}
try (BytesStreamOutput out = new BytesStreamOutput()) {
action.writeTo(out);
try (StreamInput in = out.bytes().streamInput()) {
AliasActions read = new AliasActions(in);
assertEquals(action, read);
}
}
}
private Map<String, Object> randomMap(int maxDepth) {
int members = between(0, 5);
Map<String, Object> result = new HashMap<>(members);
for (int i = 0; i < members; i++) {
Object value;
switch (between(0, 3)) {
case 0:
if (maxDepth > 0) {
value = randomMap(maxDepth - 1);
} else {
value = randomAsciiOfLength(5);
}
break;
case 1:
value = randomAsciiOfLength(5);
break;
case 2:
value = randomBoolean();
break;
case 3:
value = randomLong();
break;
default:
throw new UnsupportedOperationException();
}
result.put(randomAsciiOfLength(5), value);
}
return result;
}
private Object randomRouting() {
return randomBoolean() ? randomAsciiOfLength(5) : randomInt();
}
}

View File

@ -35,12 +35,13 @@ import org.elasticsearch.index.shard.DocsStats;
import org.elasticsearch.test.ESTestCase;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import static org.elasticsearch.action.admin.indices.rollover.TransportRolloverAction.evaluateConditions;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.hasSize;
public class TransportRolloverActionTests extends ESTestCase {
@ -97,19 +98,19 @@ public class TransportRolloverActionTests extends ESTestCase {
final IndicesAliasesClusterStateUpdateRequest updateRequest =
TransportRolloverAction.prepareRolloverAliasesUpdateRequest(sourceIndex, targetIndex, rolloverRequest);
final AliasAction[] actions = updateRequest.actions();
assertThat(actions.length, equalTo(2));
List<AliasAction> actions = updateRequest.actions();
assertThat(actions, hasSize(2));
boolean foundAdd = false;
boolean foundRemove = false;
for (AliasAction action : actions) {
if (action.actionType() == AliasAction.Type.ADD) {
if (action.getIndex().equals(targetIndex)) {
assertEquals(sourceAlias, ((AliasAction.Add) action).getAlias());
foundAdd = true;
assertThat(action.index(), equalTo(targetIndex));
assertThat(action.alias(), equalTo(sourceAlias));
} else if (action.actionType() == AliasAction.Type.REMOVE) {
} else if (action.getIndex().equals(sourceIndex)) {
assertEquals(sourceAlias, ((AliasAction.Remove) action).getAlias());
foundRemove = true;
assertThat(action.index(), equalTo(sourceIndex));
assertThat(action.alias(), equalTo(sourceAlias));
} else {
throw new AssertionError("Unknow index [" + action.getIndex() + "]");
}
}
assertTrue(foundAdd);

View File

@ -20,10 +20,8 @@
package org.elasticsearch.aliases;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder;
import org.elasticsearch.action.admin.indices.alias.exists.AliasesExistResponse;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
@ -31,7 +29,6 @@ import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.AliasAction;
import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.AliasOrIndex;
import org.elasticsearch.cluster.metadata.IndexMetaData;
@ -52,14 +49,13 @@ import org.elasticsearch.test.ESIntegTestCase;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import static org.elasticsearch.client.Requests.createIndexRequest;
import static org.elasticsearch.client.Requests.indexRequest;
import static org.elasticsearch.cluster.metadata.AliasAction.Type.ADD;
import static org.elasticsearch.cluster.metadata.AliasAction.Type.REMOVE;
import static org.elasticsearch.cluster.metadata.IndexMetaData.INDEX_METADATA_BLOCK;
import static org.elasticsearch.cluster.metadata.IndexMetaData.INDEX_READ_ONLY_BLOCK;
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_BLOCKS_METADATA;
@ -114,25 +110,15 @@ public class IndexAliasesIT extends ESIntegTestCase {
logger.info("--> creating index [test]");
createIndex("test");
ensureGreen();
//invalid filter, invalid json
IndicesAliasesRequestBuilder indicesAliasesRequestBuilder = admin().indices().prepareAliases().addAlias("test", "alias1", "abcde");
try {
indicesAliasesRequestBuilder.get();
fail("put alias should have been failed due to invalid filter");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), equalTo("failed to parse filter for alias [alias1]"));
}
Exception e = expectThrows(IllegalArgumentException.class,
() -> admin().indices().prepareAliases().addAlias("test", "alias1", "abcde").get());
assertThat(e.getMessage(), equalTo("failed to parse filter for alias [alias1]"));
//valid json , invalid filter
indicesAliasesRequestBuilder = admin().indices().prepareAliases().addAlias("test", "alias1", "{ \"test\": {} }");
try {
indicesAliasesRequestBuilder.get();
fail("put alias should have been failed due to invalid filter");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), equalTo("failed to parse filter for alias [alias1]"));
}
// valid json , invalid filter
e = expectThrows(IllegalArgumentException.class,
() -> admin().indices().prepareAliases().addAlias("test", "alias1", "{ \"test\": {} }").get());
assertThat(e.getMessage(), equalTo("failed to parse filter for alias [alias1]"));
}
public void testFilteringAliases() throws Exception {
@ -598,7 +584,7 @@ public class IndexAliasesIT extends ESIntegTestCase {
.addAlias("foobar", "foo"));
assertAcked(admin().indices().prepareAliases()
.addAliasAction(new AliasAction(ADD, "foobar", "bac").routing("bla")));
.addAliasAction(AliasActions.add().index("foobar").alias("bac").routing("bla")));
logger.info("--> getting bar and baz for index bazbar");
getResponse = admin().indices().prepareGetAliases("bar", "bac").addIndices("bazbar").get();
@ -729,224 +715,6 @@ public class IndexAliasesIT extends ESIntegTestCase {
assertThat(existsResponse.exists(), equalTo(false));
}
public void testAddAliasNullWithoutExistingIndices() {
try {
assertAcked(admin().indices().prepareAliases().addAliasAction(AliasAction.newAddAliasAction(null, "alias1")));
fail("create alias should have failed due to null index");
} catch (IllegalArgumentException e) {
assertThat("Exception text does not contain \"Alias action [add]: [index/indices] may not be empty string\"",
e.getMessage(), containsString("Alias action [add]: [index/indices] may not be empty string"));
}
}
public void testAddAliasNullWithExistingIndices() throws Exception {
logger.info("--> creating index [test]");
createIndex("test");
ensureGreen();
logger.info("--> aliasing index [null] with [empty-alias]");
try {
assertAcked(admin().indices().prepareAliases().addAlias((String) null, "empty-alias"));
fail("create alias should have failed due to null index");
} catch (IllegalArgumentException e) {
assertThat("Exception text does not contain \"Alias action [add]: [index/indices] may not be empty string\"",
e.getMessage(), containsString("Alias action [add]: [index/indices] may not be empty string"));
}
}
public void testAddAliasEmptyIndex() {
try {
admin().indices().prepareAliases().addAliasAction(AliasAction.newAddAliasAction("", "alias1")).get();
fail("Expected ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
assertThat(e.getMessage(), containsString("[index/indices] may not be empty string"));
}
try {
admin().indices().prepareAliases().addAliasAction(new AliasActions(ADD, "", "alias1")).get();
fail("Expected ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
assertThat(e.getMessage(), containsString("[index/indices] may not be empty string"));
}
}
public void testAddAliasNullAlias() {
try {
admin().indices().prepareAliases().addAliasAction(AliasAction.newAddAliasAction("index1", null)).get();
fail("Expected ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
assertThat(e.getMessage(), containsString("[alias/aliases] may not be empty string"));
}
try {
admin().indices().prepareAliases().addAliasAction(new AliasActions(ADD, "index1", (String)null)).get();
fail("Expected ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
assertThat(e.getMessage(), containsString("[alias/aliases] may not be empty string"));
}
try {
admin().indices().prepareAliases().addAliasAction(new AliasActions(ADD, "index1", (String[])null)).get();
fail("Expected ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
assertThat(e.getMessage(), containsString("[alias/aliases] is either missing or null"));
}
}
public void testAddAliasEmptyAlias() {
try {
admin().indices().prepareAliases().addAliasAction(AliasAction.newAddAliasAction("index1", "")).get();
fail("Expected ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
assertThat(e.getMessage(), containsString("[alias/aliases] may not be empty string"));
}
try {
admin().indices().prepareAliases().addAliasAction(new AliasActions(ADD, "index1", "")).get();
fail("Expected ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
assertThat(e.getMessage(), containsString("[alias/aliases] may not be empty string"));
}
}
public void testAddAliasNullAliasNullIndex() {
try {
admin().indices().prepareAliases().addAliasAction(AliasAction.newAddAliasAction(null, null)).get();
fail("Should throw " + ActionRequestValidationException.class.getSimpleName());
} catch (ActionRequestValidationException e) {
assertThat(e.validationErrors(), notNullValue());
assertThat(e.validationErrors().size(), equalTo(2));
}
try {
admin().indices().prepareAliases().addAliasAction(new AliasActions(ADD, null, (String)null)).get();
fail("Should throw " + ActionRequestValidationException.class.getSimpleName());
} catch (ActionRequestValidationException e) {
assertThat(e.validationErrors(), notNullValue());
assertThat(e.validationErrors().size(), equalTo(2));
}
}
public void testAddAliasEmptyAliasEmptyIndex() {
try {
admin().indices().prepareAliases().addAliasAction(AliasAction.newAddAliasAction("", "")).get();
fail("Should throw " + ActionRequestValidationException.class.getSimpleName());
} catch (ActionRequestValidationException e) {
assertThat(e.validationErrors(), notNullValue());
assertThat(e.validationErrors().size(), equalTo(2));
}
try {
admin().indices().prepareAliases().addAliasAction(new AliasActions(ADD, "", "")).get();
fail("Should throw " + ActionRequestValidationException.class.getSimpleName());
} catch (ActionRequestValidationException e) {
assertThat(e.validationErrors(), notNullValue());
assertThat(e.validationErrors().size(), equalTo(2));
}
}
public void testRemoveAliasNullIndex() {
try {
admin().indices().prepareAliases().addAliasAction(AliasAction.newRemoveAliasAction(null, "alias1")).get();
fail("Expected ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
assertThat(e.getMessage(), containsString("[index/indices] may not be empty string"));
}
try {
admin().indices().prepareAliases().addAliasAction(new AliasActions(REMOVE, null, "alias1")).get();
fail("Expected ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
assertThat(e.getMessage(), containsString("[index/indices] may not be empty string"));
}
}
public void testRemoveAliasEmptyIndex() {
try {
admin().indices().prepareAliases().addAliasAction(AliasAction.newRemoveAliasAction("", "alias1")).get();
fail("Expected ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
assertThat(e.getMessage(), containsString("[index/indices] may not be empty string"));
}
try {
admin().indices().prepareAliases().addAliasAction(new AliasActions(REMOVE, "", "alias1")).get();
fail("Expected ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
assertThat(e.getMessage(), containsString("[index/indices] may not be empty string"));
}
}
public void testRemoveAliasNullAlias() {
try {
admin().indices().prepareAliases().addAliasAction(AliasAction.newRemoveAliasAction("index1", null)).get();
fail("Expected ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
assertThat(e.getMessage(), containsString("[alias/aliases] may not be empty string"));
}
try {
admin().indices().prepareAliases().addAliasAction(new AliasActions(REMOVE, "index1", (String)null)).get();
fail("Expected ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
assertThat(e.getMessage(), containsString("[alias/aliases] may not be empty string"));
}
try {
admin().indices().prepareAliases().addAliasAction(new AliasActions(REMOVE, "index1", (String[])null)).get();
fail("Expected ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
assertThat(e.getMessage(), containsString("[alias/aliases] is either missing or null"));
}
}
public void testRemoveAliasEmptyAlias() {
try {
admin().indices().prepareAliases().addAliasAction(AliasAction.newRemoveAliasAction("index1", "")).get();
fail("Expected ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
assertThat(e.getMessage(), containsString("[alias/aliases] may not be empty string"));
}
try {
admin().indices().prepareAliases().addAliasAction(new AliasActions(REMOVE, "index1", "")).get();
fail("Expected ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
assertThat(e.getMessage(), containsString("[alias/aliases] may not be empty string"));
}
}
public void testRemoveAliasNullAliasNullIndex() {
try {
admin().indices().prepareAliases().addAliasAction(AliasAction.newRemoveAliasAction(null, null)).get();
fail("Should throw " + ActionRequestValidationException.class.getSimpleName());
} catch (ActionRequestValidationException e) {
assertThat(e.validationErrors(), notNullValue());
assertThat(e.validationErrors().size(), equalTo(2));
}
try {
admin().indices().prepareAliases().addAliasAction(new AliasActions(REMOVE, null, (String)null)).get();
fail("Should throw " + ActionRequestValidationException.class.getSimpleName());
} catch (ActionRequestValidationException e) {
assertThat(e.validationErrors(), notNullValue());
assertThat(e.validationErrors().size(), equalTo(2));
}
try {
admin().indices().prepareAliases().addAliasAction(new AliasActions(REMOVE, (String[])null, (String[])null)).get();
fail("Should throw " + ActionRequestValidationException.class.getSimpleName());
} catch (ActionRequestValidationException e) {
assertThat(e.validationErrors(), notNullValue());
assertThat(e.validationErrors().size(), equalTo(2));
}
}
public void testRemoveAliasEmptyAliasEmptyIndex() {
try {
admin().indices().prepareAliases().addAliasAction(AliasAction.newAddAliasAction("", "")).get();
fail("Should throw " + ActionRequestValidationException.class.getSimpleName());
} catch (ActionRequestValidationException e) {
assertThat(e.validationErrors(), notNullValue());
assertThat(e.validationErrors().size(), equalTo(2));
}
try {
admin().indices().prepareAliases().addAliasAction(new AliasActions(REMOVE, "", "")).get();
fail("Should throw " + ActionRequestValidationException.class.getSimpleName());
} catch (ActionRequestValidationException e) {
assertThat(e.validationErrors(), notNullValue());
assertThat(e.validationErrors().size(), equalTo(2));
}
}
public void testGetAllAliasesWorks() {
createIndex("index1");
createIndex("index2");
@ -1113,6 +881,13 @@ public class IndexAliasesIT extends ESIntegTestCase {
}
}
public void testRemoveIndexAndReplaceWithAlias() throws InterruptedException, ExecutionException {
assertAcked(client().admin().indices().prepareCreate("test"));
indexRandom(true, client().prepareIndex("test_2", "test", "test").setSource("test", "test"));
assertAcked(client().admin().indices().prepareAliases().addAlias("test_2", "test").removeIndex("test"));
assertHitCount(client().prepareSearch("test").get(), 1);
}
private void checkAliases() {
GetAliasesResponse getAliasesResponse = admin().indices().prepareGetAliases("alias1").get();
assertThat(getAliasesResponse.getAliases().get("test").size(), equalTo(1));

View File

@ -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.cluster.metadata;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.SnapshotsInProgress;
import org.elasticsearch.cluster.block.ClusterBlocks;
import org.elasticsearch.cluster.routing.RoutingTable;
import org.elasticsearch.cluster.routing.allocation.AllocationService;
import org.elasticsearch.cluster.routing.allocation.RoutingAllocation;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.repositories.IndexId;
import org.elasticsearch.snapshots.Snapshot;
import org.elasticsearch.snapshots.SnapshotId;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.VersionUtils;
import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class MetaDataDeleteIndexServiceTests extends ESTestCase {
private final AllocationService allocationService = mock(AllocationService.class);
private final MetaDataDeleteIndexService service = new MetaDataDeleteIndexService(Settings.EMPTY, null, allocationService);
public void testDeleteMissing() {
Index index = new Index("missing", "doesn't matter");
ClusterState state = ClusterState.builder(ClusterName.DEFAULT).build();
IndexNotFoundException e = expectThrows(IndexNotFoundException.class, () -> service.deleteIndices(state, singleton(index)));
assertEquals(index, e.getIndex());
}
public void testDeleteSnapshotting() {
String index = randomAsciiOfLength(5);
Snapshot snapshot = new Snapshot("doesn't matter", new SnapshotId("snapshot name", "snapshot uuid"));
SnapshotsInProgress snaps = new SnapshotsInProgress(new SnapshotsInProgress.Entry(snapshot, true, false,
SnapshotsInProgress.State.INIT, singletonList(new IndexId(index, "doesn't matter")),
System.currentTimeMillis(), ImmutableOpenMap.of()));
ClusterState state = ClusterState.builder(clusterState(index))
.putCustom(SnapshotsInProgress.TYPE, snaps)
.build();
Exception e = expectThrows(IllegalArgumentException.class,
() -> service.deleteIndices(state, singleton(state.metaData().getIndices().get(index).getIndex())));
assertEquals("Cannot delete indices that are being snapshotted: [[" + index + "]]. Try again after snapshot finishes "
+ "or cancel the currently running snapshot.", e.getMessage());
}
public void testDeleteUnassigned() {
// Create an unassigned index
String index = randomAsciiOfLength(5);
ClusterState before = clusterState(index);
// Mock the built reroute
when(allocationService.reroute(any(ClusterState.class), any(String.class))).then(
i -> RoutingAllocation.Result.unchanged((ClusterState) i.getArguments()[0]));
// Remove it
ClusterState after = service.deleteIndices(before, singleton(before.metaData().getIndices().get(index).getIndex()));
// It is gone
assertNull(after.metaData().getIndices().get(index));
assertNull(after.routingTable().index(index));
assertNull(after.blocks().indices().get(index));
// Make sure we actually attempted to reroute
verify(allocationService).reroute(any(ClusterState.class), any(String.class));
}
private ClusterState clusterState(String index) {
IndexMetaData indexMetaData = IndexMetaData.builder(index)
.settings(Settings.builder().put("index.version.created", VersionUtils.randomVersion(random())))
.numberOfShards(1)
.numberOfReplicas(1)
.build();
return ClusterState.builder(ClusterName.DEFAULT)
.metaData(MetaData.builder().put(indexMetaData, false))
.routingTable(RoutingTable.builder().addAsNew(indexMetaData).build())
.blocks(ClusterBlocks.builder().addBlocks(indexMetaData))
.build();
}
}

View File

@ -0,0 +1,138 @@
/*
* 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.cluster.metadata;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.VersionUtils;
import java.util.Arrays;
import java.util.Collection;
import static java.util.Collections.singletonList;
import static org.hamcrest.Matchers.contains;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyCollectionOf;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class MetaDataIndexAliasesServiceTests extends ESTestCase {
private final AliasValidator aliasValidator = new AliasValidator(Settings.EMPTY);
private final MetaDataDeleteIndexService deleteIndexService = mock(MetaDataDeleteIndexService.class);
private final MetaDataIndexAliasesService service = new MetaDataIndexAliasesService(Settings.EMPTY, null, null, aliasValidator,
null, deleteIndexService);
public MetaDataIndexAliasesServiceTests() {
// Mock any deletes so we don't need to worry about how MetaDataDeleteIndexService does its job
when(deleteIndexService.deleteIndices(any(ClusterState.class), anyCollectionOf(Index.class))).then(i -> {
ClusterState state = (ClusterState) i.getArguments()[0];
@SuppressWarnings("unchecked")
Collection<Index> indices = (Collection<Index>) i.getArguments()[1];
MetaData.Builder meta = MetaData.builder(state.metaData());
for (Index index : indices) {
assertTrue("index now found", state.metaData().hasConcreteIndex(index.getName()));
meta.remove(index.getName()); // We only think about metadata for this test. Not routing or any other fun stuff.
}
return ClusterState.builder(state).metaData(meta).build();
});
}
public void testAddAndRemove() {
// Create a state with a single index
String index = randomAsciiOfLength(5);
ClusterState before = createIndex(ClusterState.builder(ClusterName.DEFAULT).build(), index);
// Add an alias to it
ClusterState after = service.innerExecute(before, singletonList(new AliasAction.Add(index, "test", null, null, null)));
AliasOrIndex alias = after.metaData().getAliasAndIndexLookup().get("test");
assertNotNull(alias);
assertTrue(alias.isAlias());
assertThat(alias.getIndices(), contains(after.metaData().index(index)));
// Remove the alias from it while adding another one
before = after;
after = service.innerExecute(before, Arrays.asList(
new AliasAction.Remove(index, "test"),
new AliasAction.Add(index, "test_2", null, null, null)));
assertNull(after.metaData().getAliasAndIndexLookup().get("test"));
alias = after.metaData().getAliasAndIndexLookup().get("test_2");
assertNotNull(alias);
assertTrue(alias.isAlias());
assertThat(alias.getIndices(), contains(after.metaData().index(index)));
// Now just remove on its own
before = after;
after = service.innerExecute(before, singletonList(new AliasAction.Remove(index, "test_2")));
assertNull(after.metaData().getAliasAndIndexLookup().get("test"));
assertNull(after.metaData().getAliasAndIndexLookup().get("test_2"));
}
public void testSwapIndexWithAlias() {
// Create "test" and "test_2"
ClusterState before = createIndex(ClusterState.builder(ClusterName.DEFAULT).build(), "test");
before = createIndex(before, "test_2");
// Now remove "test" and add an alias to "test" to "test_2" in one go
ClusterState after = service.innerExecute(before, Arrays.asList(
new AliasAction.Add("test_2", "test", null, null, null),
new AliasAction.RemoveIndex("test")));
AliasOrIndex alias = after.metaData().getAliasAndIndexLookup().get("test");
assertNotNull(alias);
assertTrue(alias.isAlias());
assertThat(alias.getIndices(), contains(after.metaData().index("test_2")));
}
public void testAddAliasToRemovedIndex() {
// Create "test"
ClusterState before = createIndex(ClusterState.builder(ClusterName.DEFAULT).build(), "test");
// Attempt to add an alias to "test" at the same time as we remove it
IndexNotFoundException e = expectThrows(IndexNotFoundException.class, () -> service.innerExecute(before, Arrays.asList(
new AliasAction.Add("test", "alias", null, null, null),
new AliasAction.RemoveIndex("test"))));
assertEquals("test", e.getIndex().getName());
}
public void testRemoveIndexTwice() {
// Create "test"
ClusterState before = createIndex(ClusterState.builder(ClusterName.DEFAULT).build(), "test");
// Try to remove an index twice. This should just remove the index once....
ClusterState after = service.innerExecute(before, Arrays.asList(
new AliasAction.RemoveIndex("test"),
new AliasAction.RemoveIndex("test")));
assertNull(after.metaData().getAliasAndIndexLookup().get("test"));
}
private ClusterState createIndex(ClusterState state, String index) {
IndexMetaData indexMetaData = IndexMetaData.builder(index)
.settings(Settings.builder().put("index.version.created", VersionUtils.randomVersion(random())))
.numberOfShards(1)
.numberOfReplicas(1)
.build();
return ClusterState.builder(state)
.metaData(MetaData.builder(state.metaData()).put(indexMetaData, false))
.build();
}
}

View File

@ -20,7 +20,7 @@ package org.elasticsearch.cluster.shards;
import org.elasticsearch.action.admin.cluster.shards.ClusterSearchShardsGroup;
import org.elasticsearch.action.admin.cluster.shards.ClusterSearchShardsResponse;
import org.elasticsearch.cluster.metadata.AliasAction;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.common.Priority;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ESIntegTestCase;
@ -99,9 +99,9 @@ public class ClusterSearchShardsIT extends ESIntegTestCase {
client().admin().indices().prepareCreate("test2").setSettings(Settings.builder()
.put("index.number_of_shards", "4").put("index.number_of_replicas", 1)).execute().actionGet();
client().admin().indices().prepareAliases()
.addAliasAction(AliasAction.newAddAliasAction("test1", "routing_alias").routing("ABC"))
.addAliasAction(AliasAction.newAddAliasAction("test2", "routing_alias").routing("EFG"))
.execute().actionGet();
.addAliasAction(AliasActions.add().index("test1").alias("routing_alias").routing("ABC"))
.addAliasAction(AliasActions.add().index("test2").alias("routing_alias").routing("EFG"))
.get();
client().admin().cluster().prepareHealth().setWaitForEvents(Priority.LANGUID).setWaitForGreenStatus().execute().actionGet();
ClusterSearchShardsResponse response = client().admin().cluster().prepareSearchShards("routing_alias").execute().actionGet();

View File

@ -20,6 +20,7 @@
package org.elasticsearch.common.xcontent.support.filtering;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.common.xcontent.XContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
@ -28,7 +29,11 @@ import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.util.Set;
import java.util.function.Function;
import static java.util.Collections.emptySet;
import static java.util.Collections.singleton;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.nullValue;
@ -86,12 +91,16 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
return XContentBuilder.builder(getXContentType().xContent());
}
private XContentBuilder newXContentBuilder(String filter, boolean inclusive) throws IOException {
return XContentBuilder.builder(getXContentType().xContent(), new String[] { filter }, inclusive);
private XContentBuilder newXContentBuilderWithIncludes(String filter) throws IOException {
return newXContentBuilder(singleton(filter), emptySet());
}
private XContentBuilder newXContentBuilder(String[] filters, boolean inclusive) throws IOException {
return XContentBuilder.builder(getXContentType().xContent(), filters, inclusive);
private XContentBuilder newXContentBuilderWithExcludes(String filter) throws IOException {
return newXContentBuilder(emptySet(), singleton(filter));
}
private XContentBuilder newXContentBuilder(Set<String> includes, Set<String> excludes) throws IOException {
return XContentBuilder.builder(getXContentType().xContent(), includes, excludes);
}
/**
@ -173,20 +182,22 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
return builder;
}
/**
* Instanciates a new XContentBuilder with the given filters and builds a
* sample with it.
* @param inclusive
* Specifies if filters are inclusive or exclusive
*/
private XContentBuilder sample(String filter, boolean inclusive) throws IOException {
return sample(newXContentBuilder(filter, inclusive));
/** Create a new {@link XContentBuilder} and use it to build the sample using the given inclusive filter **/
private XContentBuilder sampleWithIncludes(String filter) throws IOException {
return sample(newXContentBuilderWithIncludes(filter));
}
private XContentBuilder sample(String[] filters, boolean inclusive) throws IOException {
return sample(newXContentBuilder(filters, inclusive));
/** Create a new {@link XContentBuilder} and use it to build the sample using the given exclusive filter **/
private XContentBuilder sampleWithExcludes(String filter) throws IOException {
return sample(newXContentBuilderWithExcludes(filter));
}
/** Create a new {@link XContentBuilder} and use it to build the sample using the given includes and exclusive filters **/
private XContentBuilder sampleWithFilters(Set<String> includes, Set<String> excludes) throws IOException {
return sample(newXContentBuilder(includes, excludes));
}
/** Create a new {@link XContentBuilder} and use it to build the sample **/
private XContentBuilder sample() throws IOException {
return sample(newXContentBuilder());
}
@ -195,23 +206,23 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
XContentBuilder expected = sample();
assertXContentBuilder(expected, sample());
assertXContentBuilder(expected, sample("*", true));
assertXContentBuilder(expected, sample("**", true));
assertXContentBuilder(expected, sample("xyz", false));
assertXContentBuilder(expected, sampleWithIncludes("*"));
assertXContentBuilder(expected, sampleWithIncludes("**"));
assertXContentBuilder(expected, sampleWithExcludes("xyz"));
}
public void testNoMatch() throws Exception {
XContentBuilder expected = newXContentBuilder().startObject().endObject();
assertXContentBuilder(expected, sample("xyz", true));
assertXContentBuilder(expected, sample("*", false));
assertXContentBuilder(expected, sample("**", false));
assertXContentBuilder(expected, sampleWithIncludes("xyz"));
assertXContentBuilder(expected, sampleWithExcludes("*"));
assertXContentBuilder(expected, sampleWithExcludes("**"));
}
public void testSimpleFieldInclusive() throws Exception {
XContentBuilder expected = newXContentBuilder().startObject().field("title", "My awesome book").endObject();
assertXContentBuilder(expected, sample("title", true));
assertXContentBuilder(expected, sampleWithIncludes("title"));
}
public void testSimpleFieldExclusive() throws Exception {
@ -286,10 +297,9 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endObject()
.endObject();
assertXContentBuilder(expected, sample("title", false));
assertXContentBuilder(expected, sampleWithExcludes("title"));
}
public void testSimpleFieldWithWildcardInclusive() throws Exception {
XContentBuilder expected = newXContentBuilder().startObject()
.field("price", 27.99)
@ -343,7 +353,7 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endObject()
.endObject();
assertXContentBuilder(expected, sample("pr*", true));
assertXContentBuilder(expected, sampleWithIncludes("pr*"));
}
public void testSimpleFieldWithWildcardExclusive() throws Exception {
@ -370,7 +380,7 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endArray()
.endObject();
assertXContentBuilder(expected, sample("pr*", false));
assertXContentBuilder(expected, sampleWithExcludes("pr*"));
}
public void testMultipleFieldsInclusive() throws Exception {
@ -379,7 +389,7 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.field("pages", 456)
.endObject();
assertXContentBuilder(expected, sample(new String[] { "title", "pages" }, true));
assertXContentBuilder(expected, sampleWithFilters(Sets.newHashSet("title", "pages"), emptySet()));
}
public void testMultipleFieldsExclusive() throws Exception {
@ -453,10 +463,9 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endObject()
.endObject();
assertXContentBuilder(expected, sample(new String[] { "title", "pages" }, false));
assertXContentBuilder(expected, sample(newXContentBuilder(emptySet(), Sets.newHashSet("title", "pages"))));
}
public void testSimpleArrayInclusive() throws Exception {
XContentBuilder expected = newXContentBuilder().startObject()
.startArray("tags")
@ -465,7 +474,7 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endArray()
.endObject();
assertXContentBuilder(expected, sample("tags", true));
assertXContentBuilder(expected, sampleWithIncludes("tags"));
}
public void testSimpleArrayExclusive() throws Exception {
@ -537,10 +546,9 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endObject()
.endObject();
assertXContentBuilder(expected, sample("tags", false));
assertXContentBuilder(expected, sampleWithExcludes("tags"));
}
public void testSimpleArrayOfObjectsInclusive() throws Exception {
XContentBuilder expected = newXContentBuilder().startObject()
.startArray("authors")
@ -557,9 +565,9 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endArray()
.endObject();
assertXContentBuilder(expected, sample("authors", true));
assertXContentBuilder(expected, sample("authors.*", true));
assertXContentBuilder(expected, sample("authors.*name", true));
assertXContentBuilder(expected, sampleWithIncludes("authors"));
assertXContentBuilder(expected, sampleWithIncludes("authors.*"));
assertXContentBuilder(expected, sampleWithIncludes("authors.*name"));
}
public void testSimpleArrayOfObjectsExclusive() throws Exception {
@ -623,9 +631,9 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endObject()
.endObject();
assertXContentBuilder(expected, sample("authors", false));
assertXContentBuilder(expected, sample("authors.*", false));
assertXContentBuilder(expected, sample("authors.*name", false));
assertXContentBuilder(expected, sampleWithExcludes("authors"));
assertXContentBuilder(expected, sampleWithExcludes("authors.*"));
assertXContentBuilder(expected, sampleWithExcludes("authors.*name"));
}
public void testSimpleArrayOfObjectsPropertyInclusive() throws Exception {
@ -640,8 +648,8 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endArray()
.endObject();
assertXContentBuilder(expected, sample("authors.lastname", true));
assertXContentBuilder(expected, sample("authors.l*", true));
assertXContentBuilder(expected, sampleWithIncludes("authors.lastname"));
assertXContentBuilder(expected, sampleWithIncludes("authors.l*"));
}
public void testSimpleArrayOfObjectsPropertyExclusive() throws Exception {
@ -715,8 +723,8 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endObject()
.endObject();
assertXContentBuilder(expected, sample("authors.lastname", false));
assertXContentBuilder(expected, sample("authors.l*", false));
assertXContentBuilder(expected, sampleWithExcludes("authors.lastname"));
assertXContentBuilder(expected, sampleWithExcludes("authors.l*"));
}
public void testRecurseField1Inclusive() throws Exception {
@ -768,7 +776,7 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endObject()
.endObject();
assertXContentBuilder(expected, sample("**.name", true));
assertXContentBuilder(expected, sampleWithIncludes("**.name"));
}
public void testRecurseField1Exclusive() throws Exception {
@ -831,7 +839,7 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endObject()
.endObject();
assertXContentBuilder(expected, sample("**.name", false));
assertXContentBuilder(expected, sampleWithExcludes("**.name"));
}
public void testRecurseField2Inclusive() throws Exception {
@ -875,7 +883,7 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endObject()
.endObject();
assertXContentBuilder(expected, sample("properties.**.name", true));
assertXContentBuilder(expected, sampleWithIncludes("properties.**.name"));
}
public void testRecurseField2Exclusive() throws Exception {
@ -940,10 +948,9 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endObject()
.endObject();
assertXContentBuilder(expected, sample("properties.**.name", false));
assertXContentBuilder(expected, sampleWithExcludes("properties.**.name"));
}
public void testRecurseField3Inclusive() throws Exception {
XContentBuilder expected = newXContentBuilder().startObject()
.startObject("properties")
@ -970,7 +977,7 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endObject()
.endObject();
assertXContentBuilder(expected, sample("properties.*.en.**.name", true));
assertXContentBuilder(expected, sampleWithIncludes("properties.*.en.**.name"));
}
public void testRecurseField3Exclusive() throws Exception {
@ -1040,10 +1047,9 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endObject()
.endObject();
assertXContentBuilder(expected, sample("properties.*.en.**.name", false));
assertXContentBuilder(expected, sampleWithExcludes("properties.*.en.**.name"));
}
public void testRecurseField4Inclusive() throws Exception {
XContentBuilder expected = newXContentBuilder().startObject()
.startObject("properties")
@ -1072,7 +1078,7 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endObject()
.endObject();
assertXContentBuilder(expected, sample("properties.**.distributors.name", true));
assertXContentBuilder(expected, sampleWithIncludes("properties.**.distributors.name"));
}
public void testRecurseField4Exclusive() throws Exception {
@ -1140,7 +1146,7 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
.endObject()
.endObject();
assertXContentBuilder(expected, sample("properties.**.distributors.name", false));
assertXContentBuilder(expected, sampleWithExcludes("properties.**.distributors.name"));
}
public void testRawField() throws Exception {
@ -1155,24 +1161,24 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
// Test method: rawField(String fieldName, BytesReference content)
assertXContentBuilder(expectedRawField, newXContentBuilder().startObject().field("foo", 0).rawField("raw", raw).endObject());
assertXContentBuilder(expectedRawFieldFiltered,
newXContentBuilder("f*", true).startObject().field("foo", 0).rawField("raw", raw).endObject());
newXContentBuilderWithIncludes("f*").startObject().field("foo", 0).rawField("raw", raw).endObject());
assertXContentBuilder(expectedRawFieldFiltered,
newXContentBuilder("r*", false).startObject().field("foo", 0).rawField("raw", raw).endObject());
newXContentBuilderWithExcludes("r*").startObject().field("foo", 0).rawField("raw", raw).endObject());
assertXContentBuilder(expectedRawFieldNotFiltered,
newXContentBuilder("r*", true).startObject().field("foo", 0).rawField("raw", raw).endObject());
newXContentBuilderWithIncludes("r*").startObject().field("foo", 0).rawField("raw", raw).endObject());
assertXContentBuilder(expectedRawFieldNotFiltered,
newXContentBuilder("f*", false).startObject().field("foo", 0).rawField("raw", raw).endObject());
newXContentBuilderWithExcludes("f*").startObject().field("foo", 0).rawField("raw", raw).endObject());
// Test method: rawField(String fieldName, InputStream content)
assertXContentBuilder(expectedRawField,
newXContentBuilder().startObject().field("foo", 0).rawField("raw", raw.streamInput()).endObject());
assertXContentBuilder(expectedRawFieldFiltered, newXContentBuilder("f*", true).startObject().field("foo", 0)
assertXContentBuilder(expectedRawFieldFiltered, newXContentBuilderWithIncludes("f*").startObject().field("foo", 0)
.rawField("raw", raw.streamInput()).endObject());
assertXContentBuilder(expectedRawFieldFiltered, newXContentBuilder("r*", false).startObject().field("foo", 0)
assertXContentBuilder(expectedRawFieldFiltered, newXContentBuilderWithExcludes("r*").startObject().field("foo", 0)
.rawField("raw", raw.streamInput()).endObject());
assertXContentBuilder(expectedRawFieldNotFiltered, newXContentBuilder("r*", true).startObject().field("foo", 0)
assertXContentBuilder(expectedRawFieldNotFiltered, newXContentBuilderWithIncludes("r*").startObject().field("foo", 0)
.rawField("raw", raw.streamInput()).endObject());
assertXContentBuilder(expectedRawFieldNotFiltered, newXContentBuilder("f*", false).startObject().field("foo", 0)
assertXContentBuilder(expectedRawFieldNotFiltered, newXContentBuilderWithExcludes("f*").startObject().field("foo", 0)
.rawField("raw", raw.streamInput()).endObject());
}
@ -1180,48 +1186,209 @@ public abstract class AbstractFilteringJsonGeneratorTestCase extends ESTestCase
// Test: Array of values (no filtering)
XContentBuilder expected = newXContentBuilder().startObject().startArray("tags").value("lorem").value("ipsum").value("dolor")
.endArray().endObject();
assertXContentBuilder(expected, newXContentBuilder("t*", true).startObject().startArray("tags").value("lorem").value("ipsum")
assertXContentBuilder(expected, newXContentBuilderWithIncludes("t*").startObject().startArray("tags").value("lorem").value("ipsum")
.value("dolor").endArray().endObject());
assertXContentBuilder(expected, newXContentBuilder("tags", true).startObject().startArray("tags").value("lorem").value("ipsum")
.value("dolor").endArray().endObject());
assertXContentBuilder(expected, newXContentBuilder("a", false).startObject().startArray("tags").value("lorem").value("ipsum")
assertXContentBuilder(expected, newXContentBuilderWithIncludes("tags").startObject().startArray("tags").value("lorem")
.value("ipsum").value("dolor").endArray().endObject());
assertXContentBuilder(expected, newXContentBuilderWithExcludes("a").startObject().startArray("tags").value("lorem").value("ipsum")
.value("dolor").endArray().endObject());
// Test: Array of values (with filtering)
assertXContentBuilder(newXContentBuilder().startObject().endObject(), newXContentBuilder("foo", true).startObject()
assertXContentBuilder(newXContentBuilder().startObject().endObject(), newXContentBuilderWithIncludes("foo").startObject()
.startArray("tags").value("lorem").value("ipsum").value("dolor").endArray().endObject());
assertXContentBuilder(newXContentBuilder().startObject().endObject(), newXContentBuilder("t*", false).startObject()
assertXContentBuilder(newXContentBuilder().startObject().endObject(), newXContentBuilderWithExcludes("t*").startObject()
.startArray("tags").value("lorem").value("ipsum").value("dolor").endArray().endObject());
assertXContentBuilder(newXContentBuilder().startObject().endObject(), newXContentBuilder("tags", false).startObject()
assertXContentBuilder(newXContentBuilder().startObject().endObject(), newXContentBuilderWithExcludes("tags").startObject()
.startArray("tags").value("lorem").value("ipsum").value("dolor").endArray().endObject());
// Test: Array of objects (no filtering)
expected = newXContentBuilder().startObject().startArray("tags").startObject().field("lastname", "lorem").endObject().startObject()
.field("firstname", "ipsum").endObject().endArray().endObject();
assertXContentBuilder(expected, newXContentBuilder("t*", true).startObject().startArray("tags").startObject()
assertXContentBuilder(expected, newXContentBuilderWithIncludes("t*").startObject().startArray("tags").startObject()
.field("lastname", "lorem").endObject().startObject().field("firstname", "ipsum").endObject().endArray().endObject());
assertXContentBuilder(expected, newXContentBuilder("tags", true).startObject().startArray("tags").startObject()
assertXContentBuilder(expected, newXContentBuilderWithIncludes("tags").startObject().startArray("tags").startObject()
.field("lastname", "lorem").endObject().startObject().field("firstname", "ipsum").endObject().endArray().endObject());
assertXContentBuilder(expected, newXContentBuilder("a", false).startObject().startArray("tags").startObject()
assertXContentBuilder(expected, newXContentBuilderWithExcludes("a").startObject().startArray("tags").startObject()
.field("lastname", "lorem").endObject().startObject().field("firstname", "ipsum").endObject().endArray().endObject());
// Test: Array of objects (with filtering)
assertXContentBuilder(newXContentBuilder().startObject().endObject(),
newXContentBuilder("foo", true).startObject().startArray("tags").startObject().field("lastname", "lorem").endObject()
newXContentBuilderWithIncludes("foo").startObject().startArray("tags").startObject().field("lastname", "lorem").endObject()
.startObject().field("firstname", "ipsum").endObject().endArray().endObject());
assertXContentBuilder(newXContentBuilder().startObject().endObject(),
newXContentBuilder("t*", false).startObject().startArray("tags").startObject().field("lastname", "lorem").endObject()
newXContentBuilderWithExcludes("t*").startObject().startArray("tags").startObject().field("lastname", "lorem").endObject()
.startObject().field("firstname", "ipsum").endObject().endArray().endObject());
assertXContentBuilder(newXContentBuilder().startObject().endObject(),
newXContentBuilder("tags", false).startObject().startArray("tags").startObject().field("lastname", "lorem").endObject()
newXContentBuilderWithExcludes("tags").startObject().startArray("tags").startObject().field("lastname", "lorem").endObject()
.startObject().field("firstname", "ipsum").endObject().endArray().endObject());
// Test: Array of objects (with partial filtering)
expected = newXContentBuilder().startObject().startArray("tags").startObject().field("firstname", "ipsum").endObject().endArray()
.endObject();
assertXContentBuilder(expected, newXContentBuilder("t*.firstname", true).startObject().startArray("tags").startObject()
assertXContentBuilder(expected, newXContentBuilderWithIncludes("t*.firstname").startObject().startArray("tags").startObject()
.field("lastname", "lorem").endObject().startObject().field("firstname", "ipsum").endObject().endArray().endObject());
assertXContentBuilder(expected, newXContentBuilder("t*.lastname", false).startObject().startArray("tags").startObject()
assertXContentBuilder(expected, newXContentBuilderWithExcludes("t*.lastname").startObject().startArray("tags").startObject()
.field("lastname", "lorem").endObject().startObject().field("firstname", "ipsum").endObject().endArray().endObject());
}
public void testEmptyObject() throws IOException {
final Function<XContentBuilder, XContentBuilder> build = builder -> {
try {
return builder.startObject().startObject("foo").endObject().endObject();
} catch (IOException e) {
throw new RuntimeException(e);
}
};
XContentBuilder expected = build.apply(newXContentBuilder());
assertXContentBuilder(expected, build.apply(newXContentBuilderWithIncludes("foo")));
assertXContentBuilder(expected, build.apply(newXContentBuilderWithExcludes("bar")));
assertXContentBuilder(expected, build.apply(newXContentBuilder(singleton("f*"), singleton("baz"))));
expected = newXContentBuilder().startObject().endObject();
assertXContentBuilder(expected, build.apply(newXContentBuilderWithExcludes("foo")));
assertXContentBuilder(expected, build.apply(newXContentBuilderWithIncludes("bar")));
assertXContentBuilder(expected, build.apply(newXContentBuilder(singleton("f*"), singleton("foo"))));
}
public void testSingleFieldObject() throws IOException {
final Function<XContentBuilder, XContentBuilder> build = builder -> {
try {
return builder.startObject().startObject("foo").field("bar", "test").endObject().endObject();
} catch (IOException e) {
throw new RuntimeException(e);
}
};
XContentBuilder expected = build.apply(newXContentBuilder());
assertXContentBuilder(expected, build.apply(newXContentBuilderWithIncludes("foo.bar")));
assertXContentBuilder(expected, build.apply(newXContentBuilderWithExcludes("foo.baz")));
assertXContentBuilder(expected, build.apply(newXContentBuilder(singleton("foo"), singleton("foo.baz"))));
expected = newXContentBuilder().startObject().endObject();
assertXContentBuilder(expected, build.apply(newXContentBuilderWithExcludes("foo.bar")));
assertXContentBuilder(expected, build.apply(newXContentBuilder(singleton("foo"), singleton("foo.b*"))));
}
public void testSingleFieldWithBothExcludesIncludes() throws IOException {
XContentBuilder expected = newXContentBuilder()
.startObject()
.field("pages", 456)
.field("price", 27.99)
.endObject();
assertXContentBuilder(expected, sampleWithFilters(singleton("p*"), singleton("properties")));
}
public void testObjectsInArrayWithBothExcludesIncludes() throws IOException {
Set<String> includes = Sets.newHashSet("tags", "authors");
Set<String> excludes = singleton("authors.name");
XContentBuilder expected = newXContentBuilder()
.startObject()
.startArray("tags")
.value("elasticsearch")
.value("java")
.endArray()
.startArray("authors")
.startObject()
.field("lastname", "John")
.field("firstname", "Doe")
.endObject()
.startObject()
.field("lastname", "William")
.field("firstname", "Smith")
.endObject()
.endArray()
.endObject();
assertXContentBuilder(expected, sampleWithFilters(includes, excludes));
}
public void testRecursiveObjectsInArrayWithBothExcludesIncludes() throws IOException {
Set<String> includes = Sets.newHashSet("**.language", "properties.weight");
Set<String> excludes = singleton("**.distributors");
XContentBuilder expected = newXContentBuilder()
.startObject()
.startObject("properties")
.field("weight", 0.8d)
.startObject("language")
.startObject("en")
.field("lang", "English")
.field("available", true)
.endObject()
.startObject("fr")
.field("lang", "French")
.field("available", false)
.endObject()
.endObject()
.endObject()
.endObject();
assertXContentBuilder(expected, sampleWithFilters(includes, excludes));
}
public void testRecursiveSameObjectWithBothExcludesIncludes() throws IOException {
Set<String> includes = singleton("**.distributors");
Set<String> excludes = singleton("**.distributors");
XContentBuilder expected = newXContentBuilder().startObject().endObject();
assertXContentBuilder(expected, sampleWithFilters(includes, excludes));
}
public void testRecursiveObjectsPropertiesWithBothExcludesIncludes() throws IOException {
Set<String> includes = singleton("**.en.*");
Set<String> excludes = Sets.newHashSet("**.distributors.*.name", "**.street");
XContentBuilder expected = newXContentBuilder()
.startObject()
.startObject("properties")
.startObject("language")
.startObject("en")
.field("lang", "English")
.field("available", true)
.startArray("distributors")
.startObject()
.field("name", "The Book Shop")
.startArray("addresses")
.startObject()
.field("city", "London")
.endObject()
.startObject()
.field("city", "Stornoway")
.endObject()
.endArray()
.endObject()
.startObject()
.field("name", "Sussex Books House")
.endObject()
.endArray()
.endObject()
.endObject()
.endObject()
.endObject();
assertXContentBuilder(expected, sampleWithFilters(includes, excludes));
}
public void testWithLfAtEnd() throws IOException {
final Function<XContentBuilder, XContentBuilder> build = builder -> {
try {
return builder.startObject().startObject("foo").field("bar", "baz").endObject().endObject().prettyPrint().lfAtEnd();
} catch (IOException e) {
throw new RuntimeException(e);
}
};
XContentBuilder expected = build.apply(newXContentBuilder());
assertXContentBuilder(expected, build.apply(newXContentBuilderWithIncludes("foo")));
assertXContentBuilder(expected, build.apply(newXContentBuilderWithExcludes("bar")));
assertXContentBuilder(expected, build.apply(newXContentBuilder(singleton("f*"), singleton("baz"))));
expected = newXContentBuilder().startObject().endObject().prettyPrint().lfAtEnd();
assertXContentBuilder(expected, build.apply(newXContentBuilderWithExcludes("foo")));
assertXContentBuilder(expected, build.apply(newXContentBuilderWithIncludes("bar")));
assertXContentBuilder(expected, build.apply(newXContentBuilder(singleton("f*"), singleton("foo"))));
}
}

View File

@ -25,6 +25,8 @@ import com.fasterxml.jackson.core.filter.FilteringGeneratorDelegate;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.test.ESTestCase;
import java.util.Collections;
import static org.hamcrest.Matchers.equalTo;
public class FilterPathGeneratorFilteringTests extends ESTestCase {
@ -135,7 +137,7 @@ public class FilterPathGeneratorFilteringTests extends ESTestCase {
private void assertResult(String input, String filter, boolean inclusive, String expected) throws Exception {
try (BytesStreamOutput os = new BytesStreamOutput()) {
try (FilteringGeneratorDelegate generator = new FilteringGeneratorDelegate(JSON_FACTORY.createGenerator(os),
new FilterPathBasedFilter(new String[] { filter }, inclusive), true, true)) {
new FilterPathBasedFilter(Collections.singleton(filter), inclusive), true, true)) {
try (JsonParser parser = JSON_FACTORY.createParser(replaceQuotes(input))) {
while (parser.nextToken() != null) {
generator.copyCurrentStructure(parser);

View File

@ -19,8 +19,12 @@
package org.elasticsearch.common.xcontent.support.filtering;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.test.ESTestCase;
import java.util.Set;
import static java.util.Collections.singleton;
import static org.hamcrest.Matchers.arrayWithSize;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
@ -33,7 +37,7 @@ public class FilterPathTests extends ESTestCase {
public void testSimpleFilterPath() {
final String input = "test";
FilterPath[] filterPaths = FilterPath.compile(input);
FilterPath[] filterPaths = FilterPath.compile(singleton(input));
assertNotNull(filterPaths);
assertThat(filterPaths, arrayWithSize(1));
@ -52,7 +56,7 @@ public class FilterPathTests extends ESTestCase {
public void testFilterPathWithSubField() {
final String input = "foo.bar";
FilterPath[] filterPaths = FilterPath.compile(input);
FilterPath[] filterPaths = FilterPath.compile(singleton(input));
assertNotNull(filterPaths);
assertThat(filterPaths, arrayWithSize(1));
@ -76,7 +80,7 @@ public class FilterPathTests extends ESTestCase {
public void testFilterPathWithSubFields() {
final String input = "foo.bar.quz";
FilterPath[] filterPaths = FilterPath.compile(input);
FilterPath[] filterPaths = FilterPath.compile(singleton(input));
assertNotNull(filterPaths);
assertThat(filterPaths, arrayWithSize(1));
@ -103,13 +107,13 @@ public class FilterPathTests extends ESTestCase {
}
public void testEmptyFilterPath() {
FilterPath[] filterPaths = FilterPath.compile("");
FilterPath[] filterPaths = FilterPath.compile(singleton(""));
assertNotNull(filterPaths);
assertThat(filterPaths, arrayWithSize(0));
}
public void testNullFilterPath() {
FilterPath[] filterPaths = FilterPath.compile((String) null);
FilterPath[] filterPaths = FilterPath.compile(singleton(null));
assertNotNull(filterPaths);
assertThat(filterPaths, arrayWithSize(0));
}
@ -117,7 +121,7 @@ public class FilterPathTests extends ESTestCase {
public void testFilterPathWithEscapedDots() {
String input = "w.0.0.t";
FilterPath[] filterPaths = FilterPath.compile(input);
FilterPath[] filterPaths = FilterPath.compile(singleton(input));
assertNotNull(filterPaths);
assertThat(filterPaths, arrayWithSize(1));
@ -149,7 +153,7 @@ public class FilterPathTests extends ESTestCase {
input = "w\\.0\\.0\\.t";
filterPaths = FilterPath.compile(input);
filterPaths = FilterPath.compile(singleton(input));
assertNotNull(filterPaths);
assertThat(filterPaths, arrayWithSize(1));
@ -167,7 +171,7 @@ public class FilterPathTests extends ESTestCase {
input = "w\\.0.0\\.t";
filterPaths = FilterPath.compile(input);
filterPaths = FilterPath.compile(singleton(input));
assertNotNull(filterPaths);
assertThat(filterPaths, arrayWithSize(1));
@ -188,7 +192,7 @@ public class FilterPathTests extends ESTestCase {
}
public void testSimpleWildcardFilterPath() {
FilterPath[] filterPaths = FilterPath.compile("*");
FilterPath[] filterPaths = FilterPath.compile(singleton("*"));
assertNotNull(filterPaths);
assertThat(filterPaths, arrayWithSize(1));
@ -206,7 +210,7 @@ public class FilterPathTests extends ESTestCase {
public void testWildcardInNameFilterPath() {
String input = "f*o.bar";
FilterPath[] filterPaths = FilterPath.compile(input);
FilterPath[] filterPaths = FilterPath.compile(singleton(input));
assertNotNull(filterPaths);
assertThat(filterPaths, arrayWithSize(1));
@ -232,7 +236,7 @@ public class FilterPathTests extends ESTestCase {
}
public void testDoubleWildcardFilterPath() {
FilterPath[] filterPaths = FilterPath.compile("**");
FilterPath[] filterPaths = FilterPath.compile(singleton("**"));
assertNotNull(filterPaths);
assertThat(filterPaths, arrayWithSize(1));
@ -250,7 +254,7 @@ public class FilterPathTests extends ESTestCase {
public void testStartsWithDoubleWildcardFilterPath() {
String input = "**.bar";
FilterPath[] filterPaths = FilterPath.compile(input);
FilterPath[] filterPaths = FilterPath.compile(singleton(input));
assertNotNull(filterPaths);
assertThat(filterPaths, arrayWithSize(1));
@ -274,7 +278,7 @@ public class FilterPathTests extends ESTestCase {
public void testContainsDoubleWildcardFilterPath() {
String input = "foo.**.bar";
FilterPath[] filterPaths = FilterPath.compile(input);
FilterPath[] filterPaths = FilterPath.compile(singleton(input));
assertNotNull(filterPaths);
assertThat(filterPaths, arrayWithSize(1));
@ -302,7 +306,7 @@ public class FilterPathTests extends ESTestCase {
}
public void testMultipleFilterPaths() {
String[] inputs = {"foo.**.bar.*", "test.dot\\.ted"};
Set<String> inputs = Sets.newHashSet("foo.**.bar.*", "test.dot\\.ted");
FilterPath[] filterPaths = FilterPath.compile(inputs);
assertNotNull(filterPaths);

View File

@ -18,12 +18,9 @@
*/
package org.elasticsearch.indices;
import org.apache.lucene.store.LockObtainFailedException;
import org.elasticsearch.Version;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.AliasAction;
import org.elasticsearch.cluster.metadata.IndexGraveyard;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
@ -250,14 +247,11 @@ public class IndicesServiceTests extends ESSingleNodeTestCase {
public void testDanglingIndicesWithAliasConflict() throws Exception {
final String indexName = "test-idx1";
final String alias = "test-alias";
final IndicesService indicesService = getIndicesService();
final ClusterService clusterService = getInstanceFromNode(ClusterService.class);
final IndexService test = createIndex(indexName);
createIndex(indexName);
// create the alias for the index
AliasAction action = new AliasAction(AliasAction.Type.ADD, indexName, alias);
IndicesAliasesRequest request = new IndicesAliasesRequest().addAliasAction(action);
client().admin().indices().aliases(request).actionGet();
client().admin().indices().prepareAliases().addAlias(indexName, alias).get();
final ClusterState originalState = clusterService.state();
// try to import a dangling index with the same name as the alias, it should fail
@ -276,9 +270,7 @@ public class IndicesServiceTests extends ESSingleNodeTestCase {
assertThat(clusterService.state(), equalTo(originalState));
// remove the alias
action = new AliasAction(AliasAction.Type.REMOVE, indexName, alias);
request = new IndicesAliasesRequest().addAliasAction(action);
client().admin().indices().aliases(request).actionGet();
client().admin().indices().prepareAliases().removeAlias(indexName, alias).get();
// now try importing a dangling index with the same name as the alias, it should succeed.
listener = new DanglingListener();

View File

@ -239,6 +239,15 @@ public class IngestDocumentTests extends ESTestCase {
assertFalse(ingestDocument.hasField("list.10"));
}
public void testListHasFieldIndexOutOfBounds_fail() {
assertTrue(ingestDocument.hasField("list.0", true));
assertTrue(ingestDocument.hasField("list.1", true));
Exception e = expectThrows(IllegalArgumentException.class, () -> ingestDocument.hasField("list.2", true));
assertThat(e.getMessage(), equalTo("[2] is out of bounds for array with length [2] as part of path [list.2]"));
e = expectThrows(IllegalArgumentException.class, () -> ingestDocument.hasField("list.10", true));
assertThat(e.getMessage(), equalTo("[10] is out of bounds for array with length [2] as part of path [list.10]"));
}
public void testListHasFieldIndexNotNumeric() {
assertFalse(ingestDocument.hasField("list.test"));
}

View File

@ -19,6 +19,7 @@
package org.elasticsearch.routing;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
@ -30,7 +31,6 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import static org.elasticsearch.cluster.metadata.AliasAction.newAddAliasAction;
import static org.elasticsearch.common.util.set.Sets.newHashSet;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
@ -62,14 +62,15 @@ public class AliasResolveRoutingIT extends ESIntegTestCase {
createIndex("test2");
client().admin().cluster().prepareHealth().setWaitForEvents(Priority.LANGUID).setWaitForGreenStatus().execute().actionGet();
client().admin().indices().prepareAliases().addAliasAction(newAddAliasAction("test1", "alias")).execute().actionGet();
client().admin().indices().prepareAliases().addAliasAction(newAddAliasAction("test1", "alias10").routing("0")).execute().actionGet();
client().admin().indices().prepareAliases().addAliasAction(newAddAliasAction("test1", "alias110").searchRouting("1,0")).execute().actionGet();
client().admin().indices().prepareAliases().addAliasAction(newAddAliasAction("test1", "alias12").routing("2")).execute().actionGet();
client().admin().indices().prepareAliases().addAliasAction(newAddAliasAction("test2", "alias20").routing("0")).execute().actionGet();
client().admin().indices().prepareAliases().addAliasAction(newAddAliasAction("test2", "alias21").routing("1")).execute().actionGet();
client().admin().indices().prepareAliases().addAliasAction(newAddAliasAction("test1", "alias0").routing("0")).execute().actionGet();
client().admin().indices().prepareAliases().addAliasAction(newAddAliasAction("test2", "alias0").routing("0")).execute().actionGet();
client().admin().indices().prepareAliases()
.addAliasAction(AliasActions.add().index("test1").alias("alias"))
.addAliasAction(AliasActions.add().index("test1").alias("alias10").routing("0"))
.addAliasAction(AliasActions.add().index("test1").alias("alias110").searchRouting("1,0"))
.addAliasAction(AliasActions.add().index("test1").alias("alias12").routing("2"))
.addAliasAction(AliasActions.add().index("test2").alias("alias20").routing("0"))
.addAliasAction(AliasActions.add().index("test2").alias("alias21").routing("1"))
.addAliasAction(AliasActions.add().index("test1").alias("alias0").routing("0"))
.addAliasAction(AliasActions.add().index("test2").alias("alias0").routing("0")).get();
assertThat(clusterService().state().metaData().resolveIndexRouting(null, null, "test1"), nullValue());
assertThat(clusterService().state().metaData().resolveIndexRouting(null, null, "alias"), nullValue());
@ -103,12 +104,13 @@ public class AliasResolveRoutingIT extends ESIntegTestCase {
createIndex("test2");
client().admin().cluster().prepareHealth().setWaitForEvents(Priority.LANGUID).setWaitForGreenStatus().execute().actionGet();
client().admin().indices().prepareAliases().addAliasAction(newAddAliasAction("test1", "alias")).execute().actionGet();
client().admin().indices().prepareAliases().addAliasAction(newAddAliasAction("test1", "alias10").routing("0")).execute().actionGet();
client().admin().indices().prepareAliases().addAliasAction(newAddAliasAction("test2", "alias20").routing("0")).execute().actionGet();
client().admin().indices().prepareAliases().addAliasAction(newAddAliasAction("test2", "alias21").routing("1")).execute().actionGet();
client().admin().indices().prepareAliases().addAliasAction(newAddAliasAction("test1", "alias0").routing("0")).execute().actionGet();
client().admin().indices().prepareAliases().addAliasAction(newAddAliasAction("test2", "alias0").routing("0")).execute().actionGet();
client().admin().indices().prepareAliases()
.addAliasAction(AliasActions.add().index("test1").alias("alias"))
.addAliasAction(AliasActions.add().index("test1").alias("alias10").routing("0"))
.addAliasAction(AliasActions.add().index("test2").alias("alias20").routing("0"))
.addAliasAction(AliasActions.add().index("test2").alias("alias21").routing("1"))
.addAliasAction(AliasActions.add().index("test1").alias("alias0").routing("0"))
.addAliasAction(AliasActions.add().index("test2").alias("alias0").routing("0")).get();
ClusterState state = clusterService().state();
IndexNameExpressionResolver indexNameExpressionResolver = internalCluster().getInstance(IndexNameExpressionResolver.class);

View File

@ -19,6 +19,7 @@
package org.elasticsearch.routing;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
@ -26,12 +27,11 @@ import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.test.ESIntegTestCase;
import static org.elasticsearch.cluster.metadata.AliasAction.newAddAliasAction;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.Matchers.equalTo;
/**
*
* Test aliases with routing.
*/
public class AliasRoutingIT extends ESIntegTestCase {
@ -43,7 +43,7 @@ public class AliasRoutingIT extends ESIntegTestCase {
public void testAliasCrudRouting() throws Exception {
createIndex("test");
ensureGreen();
assertAcked(admin().indices().prepareAliases().addAliasAction(newAddAliasAction("test", "alias0").routing("0")));
assertAcked(admin().indices().prepareAliases().addAliasAction(AliasActions.add().index("test").alias("alias0").routing("0")));
logger.info("--> indexing with id [1], and routing [0] using alias");
client().prepareIndex("alias0", "type1", "1").setSource("field", "value1").setRefreshPolicy(RefreshPolicy.IMMEDIATE).get();
@ -105,10 +105,10 @@ public class AliasRoutingIT extends ESIntegTestCase {
createIndex("test");
ensureGreen();
assertAcked(admin().indices().prepareAliases()
.addAliasAction(newAddAliasAction("test", "alias"))
.addAliasAction(newAddAliasAction("test", "alias0").routing("0"))
.addAliasAction(newAddAliasAction("test", "alias1").routing("1"))
.addAliasAction(newAddAliasAction("test", "alias01").searchRouting("0,1")));
.addAliasAction(AliasActions.add().index("test").alias("alias"))
.addAliasAction(AliasActions.add().index("test").alias("alias0").routing("0"))
.addAliasAction(AliasActions.add().index("test").alias("alias1").routing("1"))
.addAliasAction(AliasActions.add().index("test").alias("alias01").searchRouting("0,1")));
logger.info("--> indexing with id [1], and routing [0] using alias");
client().prepareIndex("alias0", "type1", "1").setSource("field", "value1").setRefreshPolicy(RefreshPolicy.IMMEDIATE).get();
@ -200,12 +200,12 @@ public class AliasRoutingIT extends ESIntegTestCase {
createIndex("test-b");
ensureGreen();
assertAcked(admin().indices().prepareAliases()
.addAliasAction(newAddAliasAction("test-a", "alias-a0").routing("0"))
.addAliasAction(newAddAliasAction("test-a", "alias-a1").routing("1"))
.addAliasAction(newAddAliasAction("test-b", "alias-b0").routing("0"))
.addAliasAction(newAddAliasAction("test-b", "alias-b1").routing("1"))
.addAliasAction(newAddAliasAction("test-a", "alias-ab").searchRouting("0"))
.addAliasAction(newAddAliasAction("test-b", "alias-ab").searchRouting("1")));
.addAliasAction(AliasActions.add().index("test-a").alias("alias-a0").routing("0"))
.addAliasAction(AliasActions.add().index("test-a").alias("alias-a1").routing("1"))
.addAliasAction(AliasActions.add().index("test-b").alias("alias-b0").routing("0"))
.addAliasAction(AliasActions.add().index("test-b").alias("alias-b1").routing("1"))
.addAliasAction(AliasActions.add().index("test-a").alias("alias-ab").searchRouting("0"))
.addAliasAction(AliasActions.add().index("test-b").alias("alias-ab").searchRouting("1")));
ensureGreen(); // wait for events again to make sure we got the aliases on all nodes
logger.info("--> indexing with id [1], and routing [0] using alias to test-a");
client().prepareIndex("alias-a0", "type1", "1").setSource("field", "value1").setRefreshPolicy(RefreshPolicy.IMMEDIATE).get();
@ -259,7 +259,7 @@ public class AliasRoutingIT extends ESIntegTestCase {
createIndex("index", "index_2");
ensureGreen();
assertAcked(admin().indices().prepareAliases()
.addAliasAction(newAddAliasAction("index", "index_1").routing("1")));
.addAliasAction(AliasActions.add().index("index").alias("index_1").routing("1")));
logger.info("--> indexing on index_1 which is an alias for index with routing [1]");
client().prepareIndex("index_1", "type1", "1").setSource("field", "value1").setRefreshPolicy(RefreshPolicy.IMMEDIATE).get();
@ -284,7 +284,7 @@ public class AliasRoutingIT extends ESIntegTestCase {
createIndex("index", "index_2");
ensureGreen();
assertAcked(admin().indices().prepareAliases()
.addAliasAction(newAddAliasAction("index", "index_1").routing("1")));
.addAliasAction(AliasActions.add().index("index").alias("index_1").routing("1")));
logger.info("--> indexing on index_1 which is an alias for index with routing [1]");
client().prepareIndex("index_1", "type1", "1").setSource("field", "value1").setRefreshPolicy(RefreshPolicy.IMMEDIATE).get();
@ -305,7 +305,7 @@ public class AliasRoutingIT extends ESIntegTestCase {
ensureGreen();
logger.info("--> creating alias with routing [3]");
assertAcked(admin().indices().prepareAliases()
.addAliasAction(newAddAliasAction("test", "alias").routing("3")));
.addAliasAction(AliasActions.add().index("test").alias("alias").routing("3")));
logger.info("--> indexing with id [0], and routing [3]");
client().prepareIndex("alias", "type1", "0").setSource("field", "value1").setRefreshPolicy(RefreshPolicy.IMMEDIATE).get();
@ -320,7 +320,7 @@ public class AliasRoutingIT extends ESIntegTestCase {
logger.info("--> creating alias with routing [4]");
assertAcked(admin().indices().prepareAliases()
.addAliasAction(newAddAliasAction("test", "alias").routing("4")));
.addAliasAction(AliasActions.add().index("test").alias("alias").routing("4")));
logger.info("--> verifying search with wrong routing should not find");
for (int i = 0; i < 5; i++) {
@ -330,7 +330,7 @@ public class AliasRoutingIT extends ESIntegTestCase {
logger.info("--> creating alias with search routing [3,4] and index routing 4");
assertAcked(client().admin().indices().prepareAliases()
.addAliasAction(newAddAliasAction("test", "alias").searchRouting("3,4").indexRouting("4")));
.addAliasAction(AliasActions.add().index("test").alias("alias").searchRouting("3,4").indexRouting("4")));
logger.info("--> indexing with id [1], and routing [4]");
client().prepareIndex("alias", "type1", "1").setSource("field", "value2").setRefreshPolicy(RefreshPolicy.IMMEDIATE).get();

View File

@ -38,7 +38,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import static org.elasticsearch.client.Requests.indexAliasesRequest;
import static org.elasticsearch.client.Requests.indexRequest;
import static org.elasticsearch.client.Requests.refreshRequest;
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS;
@ -108,8 +107,9 @@ public class MoreLikeThisIT extends ESIntegTestCase {
.startObject("text").field("type", "text").endObject()
.endObject().endObject().endObject()));
logger.info("Creating aliases alias release");
client().admin().indices().aliases(indexAliasesRequest().addAlias("release", termQuery("text", "release"), "test")).actionGet();
client().admin().indices().aliases(indexAliasesRequest().addAlias("beta", termQuery("text", "beta"), "test")).actionGet();
client().admin().indices().prepareAliases()
.addAlias("test", "release", termQuery("text", "release"))
.addAlias("test", "beta", termQuery("text", "beta")).get();
logger.info("Running Cluster Health");
assertThat(ensureGreen(), equalTo(ClusterHealthStatus.GREEN));
@ -155,8 +155,8 @@ public class MoreLikeThisIT extends ESIntegTestCase {
.startObject("properties")
.endObject()
.endObject().endObject().string();
client().admin().indices().prepareCreate(indexName).addMapping(typeName, mapping).execute().actionGet();
client().admin().indices().aliases(indexAliasesRequest().addAlias(aliasName, indexName)).actionGet();
client().admin().indices().prepareCreate(indexName).addMapping(typeName, mapping).get();
client().admin().indices().prepareAliases().addAlias(indexName, aliasName).get();
assertThat(ensureGreen(), equalTo(ClusterHealthStatus.GREEN));

View File

@ -90,16 +90,67 @@ http://hc.apache.org/httpcomponents-asyncclient-dev/httpasyncclient/apidocs/org/
=== Performing requests
Once the `RestClient` has been created, requests can be sent by calling one of
the available `performRequest` method variants. The ones that return the
`Response` are executed synchronously, meaning that the client will block and
wait for a response to be returned. The `performRequest` variants that return
`void` accept a `ResponseListener` as an argument and are executed
asynchronously. The provided listener will be notified upon completion or
failure. The following are the arguments accepted by the different
`performRequest` methods:
the available `performRequest` or `performRequestAsync` method variants.
The `performRequest` methods are synchronous and they return the `Response`
directly, meaning that the client will block and wait for a response to be returned.
The `performRequestAsync` variants, which return `void` and accept an extra
`ResponseListener` as an argument, are executed asynchronously. The provided
listener will be notified upon completion or failure.
[source,java]
--------------------------------------------------
// Synchronous variants
Response performRequest(String method, String endpoint,
Header... headers)
throws IOException;
Response performRequest(String method, String endpoint,
Map<String, String> params, Header... headers)
throws IOException;
Response performRequest(String method, String endpoint,
Map<String, String> params,
HttpEntity entity,
Header... headers)
throws IOException;
Response performRequest(String method, String endpoint,
Map<String, String> params,
HttpEntity entity,
HttpAsyncResponseConsumer<HttpResponse> responseConsumer,
Header... headers)
throws IOException;
// Asynchronous variants
void performRequestAsync(String method, String endpoint,
ResponseListener responseListener,
Header... headers);
void performRequestAsync(String method, String endpoint,
Map<String, String> params,
ResponseListener responseListener,
Header... headers);
void performRequestAsync(String method, String endpoint,
Map<String, String> params,
HttpEntity entity,
ResponseListener responseListener,
Header... headers);
void performRequestAsync(String method, String endpoint,
Map<String, String> params,
HttpEntity entity,
ResponseListener responseListener,
HttpAsyncResponseConsumer<HttpResponse> responseConsumer,
Header... headers);
--------------------------------------------------
==== Request Arguments
The following are the arguments accepted by the different methods:
`method`:: the http method or verb
`endpoint`:: the request path, which identifies the Elasticsearch api to
`endpoint`:: the request path, which identifies the Elasticsearch API to
call (e.g. `/_cluster/health`)
`params`:: the optional parameters to be sent as querystring parameters
`entity`:: the optional request body enclosed in an
@ -109,14 +160,14 @@ http://hc.apache.org/httpcomponents-core-ga/httpcore-nio/apidocs/org/apache/http
callback. Controls how the response body gets streamed from a non-blocking
HTTP connection on the client side. When not provided, the default
implementation is used which buffers the whole response body in heap memory
`responseListener`:: the listener to be notified upon request success or failure
whenever the async `performRequest` method variants are used
`responseListener`:: the listener to be notified upon asynchronous
request success or failure
`headers`:: optional request headers
=== Reading responses
The `Response` object, either returned by the sync `performRequest` methods or
received as an argument in `ResponseListener#onSucces(Response)`, wraps the
The `Response` object, either returned by the synchronous `performRequest` methods or
received as an argument in `ResponseListener#onSuccess(Response)`, wraps the
response object returned by the http client and exposes the following information:
`getRequestLine`:: information about the performed request
@ -129,14 +180,19 @@ https://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/org/apache/http/Ht
object
When performing a request, an exception is thrown (or received as an argument
in `ResponseListener#onSucces(Exception)` in the following scenarios:
in `ResponseListener#onFailure(Exception)` in the following scenarios:
`IOException`:: communication problem (e.g. SocketTimeoutException etc.)
`ResponseException`:: a response was returned, but its status code indicated
an error (either `4xx` or `5xx`). A `ResponseException` originates from a valid
an error (not `2xx`). A `ResponseException` originates from a valid
http response, hence it exposes its corresponding `Response` object which gives
access to the returned response.
NOTE: A `ResponseException` is **not** thrown for `HEAD` requests that return
a `404` status code because it is an expected `HEAD` response that simply
denotes that the resource is not found. All other HTTP methods (e.g., `GET`)
throw a `ResponseException` for `404` responses.
=== Example requests
@ -167,6 +223,7 @@ Response indexResponse = restClient.performRequest(
Note that the low-level client doesn't expose any helper for json marshalling
and un-marshalling. Users are free to use the library that they prefer for that
purpose.
The underlying Apache Async Http Client ships with different
https://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/org/apache/http/HttpEntity.html[`org.apache.http.HttpEntity`]
implementations that allow to provide the request body in different formats
@ -184,7 +241,7 @@ The following is a basic example of how async requests can be sent:
int numRequests = 10;
final CountDownLatch latch = new CountDownLatch(numRequests);
for (int i = 0; i < numRequests; i++) {
restClient.performRequest(
restClient.performRequestAsync(
"PUT",
"/twitter/tweet/" + i,
Collections.<String, String>emptyMap(),

View File

@ -276,6 +276,41 @@ curl 'localhost:9200/_segments?pretty&filter_path=indices.**.version'
}
--------------------------------------------------
It is also possible to exclude one or more fields by prefixing the filter with the char `-`:
[source,sh]
--------------------------------------------------
curl -XGET 'localhost:9200/_count?filter_path=-_shards'
{
"count" : 1
}
%
--------------------------------------------------
And for more control, both inclusive and exclusive filters can be combined in the same expression. In
this case, the exclusive filters will be applied first and the result will be filtered again using the
inclusive filters:
[source,sh]
--------------------------------------------------
curl -XGET 'localhost:9200/_cluster/state?filter_path=metadata.indices.*.state,-metadata.indices.logs-*'
{
"metadata" : {
"indices" : {
"index-1" : {
"state" : "open"
},
"index-3" : {
"state" : "open"
},
"index-2" : {
"state" : "open"
}
}
}
}%
--------------------------------------------------
Note that elasticsearch sometimes returns directly the raw value of a field,
like the `_source` field. If you want to filter `_source` fields, you should
consider combining the already existing `_source` parameter (see

View File

@ -48,7 +48,7 @@ will still add it, since its a list):
--------------------------------------------------
curl -XPOST 'localhost:9200/test/type1/1/_update' -d '{
"script" : {
"inline": "ctx._source.tags += params.tag",
"inline": "ctx._source.tags.add(params.tag)",
"lang": "painless",
"params" : {
"tag" : "blue"
@ -247,7 +247,7 @@ Timeout waiting for a shard to become available.
`wait_for_active_shards`::
The number of shard copies required to be active before proceeding with the update operation.
The number of shard copies required to be active before proceeding with the update operation.
See <<index-wait-for-active-shards,here>> for details.
`refresh`::

View File

@ -24,7 +24,7 @@ POST /_aliases
// CONSOLE
// TEST[s/^/PUT test1\nPUT test2\n/]
An alias can also be removed, for example:
And here is removing that same alias:
[source,js]
--------------------------------------------------
@ -109,6 +109,25 @@ indices that match this pattern are added/removed.
It is an error to index to an alias which points to more than one index.
It is also possible to swap an index with an alias in one operation:
[source,js]
--------------------------------------------------
PUT test <1>
PUT test_2 <2>
POST /_aliases
{
"actions" : [
{ "add": { "index": "test_2", "alias": "test" } },
{ "remove_index": { "index": "test" } } <3>
]
}
--------------------------------------------------
// CONSOLE
<1> An index we've added by mistake
<2> The index we should have added
<3> `remove_index` is just like <<indices-delete-index>>
[float]
[[filtered]]
=== Filtered Aliases

View File

@ -57,3 +57,10 @@ that the multi-index matching and expansion is not confused. It was previously
possible (but a really bad idea) to create indices starting with a hyphen or
plus sign. Any index already existing with these preceding characters will
continue to work normally.
==== Aliases API
The `/_aliases` API no longer supports `indexRouting` and `index-routing`, only
`index_routing`. It also no longer support `searchRouting` and `search-routing`,
only `search_routing`. These were removed because they were untested and we
prefer there to be only one (obvious) way to do things like this.

View File

@ -3,6 +3,4 @@
deprecated[5.0.0,Percolate and multi percolate APIs are deprecated and have been replaced by the new <<query-dsl-percolate-query,`percolate` query>>]
added[5.0.0,Percolate query modifications only become visible after a refresh has occurred. Previously, they became visible immediately]
added[5.0.0,For indices created on or after version 5.0.0-alpha1 the percolator automatically indexes the query terms with the percolator queries. This allows the percolator to percolate documents more quickly. It is advisable to reindex any pre 5.0.0 indices to take advantage of this new optimization]
For indices created on or after version 5.0.0-alpha1 the percolator automatically indexes the query terms with the percolator queries. This allows the percolator to percolate documents more quickly. It is advisable to reindex any pre 5.0.0 indices to take advantage of this new optimization.

View File

@ -52,20 +52,24 @@ public final class RenameProcessor extends AbstractProcessor {
@Override
public void execute(IngestDocument document) {
if (document.hasField(field) == false) {
if (document.hasField(field, true) == false) {
throw new IllegalArgumentException("field [" + field + "] doesn't exist");
}
if (document.hasField(targetField)) {
// We fail here if the target field point to an array slot that is out of range.
// If we didn't do this then we would fail if we set the value in the target_field
// and then on failure processors would not see that value we tried to rename as we already
// removed it.
if (document.hasField(targetField, true)) {
throw new IllegalArgumentException("field [" + targetField + "] already exists");
}
Object oldValue = document.getFieldValue(field, Object.class);
document.setFieldValue(targetField, oldValue);
Object value = document.getFieldValue(field, Object.class);
document.removeField(field);
try {
document.removeField(field);
document.setFieldValue(targetField, value);
} catch (Exception e) {
//remove the new field if the removal of the old one failed
document.removeField(targetField);
// setting the value back to the original field shouldn't as we just fetched it from that field:
document.setFieldValue(field, value);
throw e;
}
}

View File

@ -171,4 +171,27 @@ public class RenameProcessorTests extends ESTestCase {
assertThat(ingestDocument.getSourceAndMetadata().containsKey("new_field"), equalTo(false));
}
}
public void testRenameLeafIntoBranch() throws Exception {
Map<String, Object> source = new HashMap<>();
source.put("foo", "bar");
IngestDocument ingestDocument = new IngestDocument(source, Collections.emptyMap());
Processor processor1 = new RenameProcessor(randomAsciiOfLength(10), "foo", "foo.bar");
processor1.execute(ingestDocument);
assertThat(ingestDocument.getFieldValue("foo", Map.class), equalTo(Collections.singletonMap("bar", "bar")));
assertThat(ingestDocument.getFieldValue("foo.bar", String.class), equalTo("bar"));
Processor processor2 = new RenameProcessor(randomAsciiOfLength(10), "foo.bar", "foo.bar.baz");
processor2.execute(ingestDocument);
assertThat(ingestDocument.getFieldValue("foo", Map.class), equalTo(Collections.singletonMap("bar",
Collections.singletonMap("baz", "bar"))));
assertThat(ingestDocument.getFieldValue("foo.bar", Map.class), equalTo(Collections.singletonMap("baz", "bar")));
assertThat(ingestDocument.getFieldValue("foo.bar.baz", String.class), equalTo("bar"));
// for fun lets try to restore it (which don't allow today)
Processor processor3 = new RenameProcessor(randomAsciiOfLength(10), "foo.bar.baz", "foo");
Exception e = expectThrows(IllegalArgumentException.class, () -> processor3.execute(ingestDocument));
assertThat(e.getMessage(), equalTo("field [foo] already exists"));
}
}

View File

@ -33,13 +33,13 @@ compileTestJava.options.compilerArgs << "-Xlint:-cast,-deprecation,-rawtypes,-tr
dependencies {
// network stack
compile "io.netty:netty-buffer:4.1.4.Final"
compile "io.netty:netty-codec:4.1.4.Final"
compile "io.netty:netty-codec-http:4.1.4.Final"
compile "io.netty:netty-common:4.1.4.Final"
compile "io.netty:netty-handler:4.1.4.Final"
compile "io.netty:netty-resolver:4.1.4.Final"
compile "io.netty:netty-transport:4.1.4.Final"
compile "io.netty:netty-buffer:4.1.5.Final"
compile "io.netty:netty-codec:4.1.5.Final"
compile "io.netty:netty-codec-http:4.1.5.Final"
compile "io.netty:netty-common:4.1.5.Final"
compile "io.netty:netty-handler:4.1.5.Final"
compile "io.netty:netty-resolver:4.1.5.Final"
compile "io.netty:netty-transport:4.1.5.Final"
}
integTest {
@ -114,9 +114,9 @@ thirdPartyAudit.excludes = [
'com.ning.compress.lzf.LZFEncoder',
'com.ning.compress.lzf.util.ChunkDecoderFactory',
'com.ning.compress.lzf.util.ChunkEncoderFactory',
'javassist/ClassClassPath',
'javassist/ClassPath',
'javassist/ClassPool',
'javassist.ClassClassPath',
'javassist.ClassPath',
'javassist.ClassPool',
'javassist.CtClass',
'javassist.CtMethod',
'lzma.sdk.lzma.Encoder',
@ -127,7 +127,9 @@ thirdPartyAudit.excludes = [
'net.jpountz.xxhash.XXHashFactory',
'org.apache.logging.log4j.LogManager',
'org.apache.logging.log4j.Logger',
'org.apache.tomcat.Apr',
'org.apache.tomcat.jni.CertificateRequestedCallback',
'org.apache.tomcat.jni.CertificateRequestedCallback$KeyMaterial',
'org.apache.tomcat.jni.CertificateVerifier',
'org.apache.tomcat.jni.SessionTicketKey',
'org.eclipse.jetty.alpn.ALPN$ClientProvider',
@ -136,6 +138,8 @@ thirdPartyAudit.excludes = [
'io.netty.handler.ssl.util.OpenJdkSelfSignedCertGenerator',
'io.netty.util.internal.PlatformDependent0',
'io.netty.util.internal.PlatformDependent0$2',
'io.netty.util.internal.PlatformDependent0$3',
'io.netty.util.internal.UnsafeAtomicIntegerFieldUpdater',
'io.netty.util.internal.UnsafeAtomicLongFieldUpdater',
'io.netty.util.internal.UnsafeAtomicReferenceFieldUpdater',

View File

@ -1 +0,0 @@
5e199381c808377faeeb80e69f365246004d6f9f

View File

@ -0,0 +1 @@
b5fb6bccda4d63d4a74c9faccdf32f77ab66abc1

View File

@ -1 +0,0 @@
86fc9367492cdca25542fb037467ab853a77ff62

View File

@ -0,0 +1 @@
66bbf9324fa36467d041083f89328e2a24ec4f67

View File

@ -1 +0,0 @@
f6ef27ed46dd806dc27c1f0ed2e6bcfad12d28cc

View File

@ -0,0 +1 @@
087bda1b9ec7e3f75ca721fc87735cbedad2aa1a

View File

@ -1 +0,0 @@
e267ca463a0dc6292cf5e0528c4b59d6d5f76ff5

View File

@ -0,0 +1 @@
607f8433d8782445e72abe34e43a7e57e86a5e6c

View File

@ -1 +0,0 @@
5674b3bc1203d913da71ba98bb7d43832c7a71e7

View File

@ -0,0 +1 @@
6262900ee9487e62560030a136160df953b1cd6b

View File

@ -1 +0,0 @@
19f86688069a018cf5e45f7a9f9a02971b9e31ee

View File

@ -0,0 +1 @@
5f367bedcdc185a727fda3296b9a18014cdc22c4

View File

@ -1 +0,0 @@
6c99d2323d75d74b9571c4ddbdc411d96bf8d780

View File

@ -0,0 +1 @@
37126b370722ff9631ee13c91139aacec0a71d1d

View File

@ -17,7 +17,7 @@
* under the License.
*/
grant codeBase "${codebase.netty-transport-4.1.4.Final.jar}" {
grant codeBase "${codebase.netty-transport-4.1.5.Final.jar}" {
// Netty NioEventLoop wants to change this, because of https://bugs.openjdk.java.net/browse/JDK-6427854
// the bug says it only happened rarely, and that its fixed, but apparently it still happens rarely!
permission java.util.PropertyPermission "sun.nio.ch.bugLevel", "write";

View File

@ -82,3 +82,87 @@
- match: {test_index.aliases.test_alias1: {'index_routing': 'routing_value', 'search_routing': 'routing_value'}}
- match: {test_index.aliases.test_alias2: {'index_routing': 'routing_value', 'search_routing': 'routing_value'}}
---
"Remove alias":
- do:
indices.create:
index: test_index
- do:
indices.exists_alias:
name: test_alias1
- is_false: ''
- do:
indices.exists_alias:
name: test_alias2
- is_false: ''
- do:
indices.exists_alias:
name: test_alias3
- is_false: ''
- do:
indices.update_aliases:
body:
actions:
- add:
index: test_index
aliases: [test_alias1, test_alias2]
- do:
indices.exists_alias:
name: test_alias1
- is_true: ''
- do:
indices.exists_alias:
name: test_alias2
- is_true: ''
- do:
indices.exists_alias:
name: test_alias3
- is_false: ''
- do:
indices.update_aliases:
body:
actions:
- remove:
index: test_index
alias: test_alias1
- add:
index: test_index
alias: test_alias3
- do:
indices.exists_alias:
name: test_alias1
- is_false: ''
- do:
indices.exists_alias:
name: test_alias2
- is_true: ''
- do:
indices.exists_alias:
name: test_alias3
- is_true: ''
- do:
indices.update_aliases:
body:
actions:
- remove:
index: test_index
alias: test_alias2
- remove:
index: test_index
alias: test_alias3
- do:
indices.exists_alias:
name: test_alias1
- is_false: ''
- do:
indices.exists_alias:
name: test_alias2
- is_false: ''
- do:
indices.exists_alias:
name: test_alias3
- is_false: ''

View File

@ -0,0 +1,34 @@
---
"Remove and index and replace it with an alias":
- do:
indices.create:
index: test
- do:
indices.create:
index: test_2
- do:
indices.update_aliases:
body:
actions:
- add:
index: test_2
aliases: [test, test_write]
- remove_index:
index: test
- do:
indices.exists_alias:
name: test
- is_true: ''
- do:
indices.exists_alias:
name: test_write
- is_true: ''
- do:
indices.get_mapping:
index: test
- is_true: test_2 # the name of the index that the alias points to, would be `test` if the index were still there

View File

@ -152,3 +152,49 @@
- is_false: nodes.$master.fs.data.0.path
- is_true: nodes.$master.fs.data.0.type
- is_true: nodes.$master.fs.data.0.total_in_bytes
---
"Nodes Stats filtered using both includes and excludes filters":
- do:
cluster.state: {}
# Get master node id
- set: { master_node: master }
# Nodes Stats with "nodes" field but no JVM stats
- do:
nodes.stats:
filter_path: [ "nodes", "-nodes.*.jvm", "-nodes.*.indices" ]
- is_false: cluster_name
- is_true: nodes
- is_true: nodes.$master.name
- is_true: nodes.$master.os
- is_false: nodes.$master.indices
- is_false: nodes.$master.jvm
# Nodes Stats with "nodes.*.indices" field and sub-fields but no indices segments
- do:
nodes.stats:
filter_path: "nodes.*.indices,-nodes.*.indices.segments"
- is_false: cluster_name
- is_true: nodes
- is_false: nodes.$master.name
- is_true: nodes.$master.indices
- is_true: nodes.$master.indices.docs
- is_false: nodes.$master.indices.segments
# Nodes Stats with "nodes.*.fs.data.t*" fields but no "type" field
- do:
nodes.stats:
filter_path: "nodes.*.fs.data.t*,-**.type"
- is_false: cluster_name
- is_true: nodes
- is_false: nodes.$master.name
- is_false: nodes.$master.indices
- is_false: nodes.$master.jvm
- is_true: nodes.$master.fs.data
- is_false: nodes.$master.fs.data.0.type
- is_true: nodes.$master.fs.data.0.total_in_bytes

View File

@ -84,3 +84,64 @@
- is_true: hits.hits.1._index
- is_false: hits.hits.1._type
- is_true: hits.hits.1._id
---
"Search results filtered using both includes and excludes filters":
- do:
bulk:
refresh: true
body: |
{"index": {"_index": "index-1", "_type": "type-1", "_id": "1"}}
{"name": "First document", "properties": {"size": 123, "meta": {"foo": "bar"}}}
{"index": {"_index": "index-1", "_type": "type-1", "_id": "2"}}
{"name": "Second document", "properties": {"size": 465, "meta": {"foo": "bar", "baz": "qux"}}}
- do:
search:
filter_path: [ "-**._source.properties", "**._source" ]
body: { query: { match_all: {} } }
- is_false: took
- is_true: hits.hits.0._source
- is_true: hits.hits.0._source.name
- is_false: hits.hits.0._source.properties
- is_true: hits.hits.1._source
- is_true: hits.hits.1._source.name
- is_false: hits.hits.1._source.properties
- do:
search:
filter_path: [ "**.properties" , "-hits.hits._source.properties.meta" ]
body: { query: { match_all: {} } }
- is_false: took
- is_true: hits.hits.0._source
- is_false: hits.hits.0._source.name
- is_true: hits.hits.0._source.properties
- is_true: hits.hits.0._source.properties.size
- is_false: hits.hits.0._source.properties.meta
- is_true: hits.hits.1._source
- is_false: hits.hits.1._source.name
- is_true: hits.hits.1._source.properties
- is_true: hits.hits.1._source.properties.size
- is_false: hits.hits.1._source.properties.meta
- do:
search:
filter_path: "**._source,-**.meta.foo"
body: { query: { match_all: {} } }
- is_false: took
- is_true: hits.hits.0._source
- is_true: hits.hits.0._source.name
- is_true: hits.hits.0._source.properties
- is_true: hits.hits.0._source.properties.size
- is_false: hits.hits.0._source.properties.meta.foo
- do:
count:
filter_path: "-*"
body: { query: { match_all: {} } }
- is_false: count
- is_false: _shards