Merge branch 'master' into feature/query-refactoring
This commit is contained in:
commit
af75117845
|
@ -44,7 +44,7 @@ In order to run Elasticsearch from source without building a package, you can
|
|||
run it using Maven:
|
||||
|
||||
-------------------------------------
|
||||
mvn package -Drun -DskipTests
|
||||
./run.sh
|
||||
-------------------------------------
|
||||
|
||||
=== Test case filtering.
|
||||
|
|
20
core/pom.xml
20
core/pom.xml
|
@ -438,26 +438,6 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- execution and integration tests -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
<!-- start up elasticsearch in foreground -->
|
||||
<execution>
|
||||
<id>execute</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<target if="${run}">
|
||||
<ant antfile="${elasticsearch.integ.antfile}" target="start-foreground"/>
|
||||
</target>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
|
|
|
@ -243,11 +243,16 @@ public class Version {
|
|||
public static final int V_1_6_1_ID = 1060199;
|
||||
public static final Version V_1_6_1 = new Version(V_1_6_1_ID, false, org.apache.lucene.util.Version.LUCENE_4_10_4);
|
||||
public static final int V_1_6_2_ID = 1060299;
|
||||
public static final Version V_1_6_2 = new Version(V_1_6_2_ID, true, org.apache.lucene.util.Version.LUCENE_4_10_4);
|
||||
public static final Version V_1_6_2 = new Version(V_1_6_2_ID, false, org.apache.lucene.util.Version.LUCENE_4_10_4);
|
||||
public static final int V_1_6_3_ID = 1060399;
|
||||
public static final Version V_1_6_3 = new Version(V_1_6_3_ID, true, org.apache.lucene.util.Version.LUCENE_4_10_4);
|
||||
public static final int V_1_7_0_ID = 1070099;
|
||||
public static final Version V_1_7_0 = new Version(V_1_7_0_ID, false, org.apache.lucene.util.Version.LUCENE_4_10_4);
|
||||
public static final int V_1_7_1_ID = 1070199;
|
||||
public static final Version V_1_7_1 = new Version(V_1_7_1_ID, true, org.apache.lucene.util.Version.LUCENE_4_10_4);
|
||||
public static final Version V_1_7_1 = new Version(V_1_7_1_ID, false, org.apache.lucene.util.Version.LUCENE_4_10_4);
|
||||
public static final int V_1_7_2_ID = 1070299;
|
||||
public static final Version V_1_7_2 = new Version(V_1_7_2_ID, true, org.apache.lucene.util.Version.LUCENE_4_10_4);
|
||||
|
||||
public static final int V_2_0_0_beta1_ID = 2000001;
|
||||
public static final Version V_2_0_0_beta1 = new Version(V_2_0_0_beta1_ID, true, org.apache.lucene.util.Version.LUCENE_5_2_1);
|
||||
|
||||
|
@ -265,10 +270,14 @@ public class Version {
|
|||
switch (id) {
|
||||
case V_2_0_0_beta1_ID:
|
||||
return V_2_0_0_beta1;
|
||||
case V_1_7_2_ID:
|
||||
return V_1_7_2;
|
||||
case V_1_7_1_ID:
|
||||
return V_1_7_1;
|
||||
case V_1_7_0_ID:
|
||||
return V_1_7_0;
|
||||
case V_1_6_3_ID:
|
||||
return V_1_6_3;
|
||||
case V_1_6_2_ID:
|
||||
return V_1_6_2;
|
||||
case V_1_6_1_ID:
|
||||
|
|
|
@ -155,6 +155,7 @@ import org.elasticsearch.action.suggest.SuggestAction;
|
|||
import org.elasticsearch.action.suggest.TransportSuggestAction;
|
||||
import org.elasticsearch.action.support.ActionFilter;
|
||||
import org.elasticsearch.action.support.ActionFilters;
|
||||
import org.elasticsearch.action.support.AutoCreateIndex;
|
||||
import org.elasticsearch.action.support.TransportAction;
|
||||
import org.elasticsearch.action.termvectors.*;
|
||||
import org.elasticsearch.action.termvectors.dfs.TransportDfsOnlyAction;
|
||||
|
@ -221,6 +222,7 @@ public class ActionModule extends AbstractModule {
|
|||
actionFilterMultibinder.addBinding().to(actionFilter);
|
||||
}
|
||||
bind(ActionFilters.class).asEagerSingleton();
|
||||
bind(AutoCreateIndex.class).asEagerSingleton();
|
||||
registerAction(NodesInfoAction.INSTANCE, TransportNodesInfoAction.class);
|
||||
registerAction(NodesStatsAction.INSTANCE, TransportNodesStatsAction.class);
|
||||
registerAction(NodesHotThreadsAction.INSTANCE, TransportNodesHotThreadsAction.class);
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Indicates that a request can execute in realtime (reads from the translog).
|
||||
* All {@link ActionRequest} that are realtime should implement this interface.
|
||||
*/
|
||||
public interface RealtimeRequest {
|
||||
|
||||
/**
|
||||
* @param realtime Controls whether this request should be realtime by reading from the translog. If <code>null</code>
|
||||
* is specified then whether the operation will be realtime depends on the api of the concrete request
|
||||
* subclass.
|
||||
*/
|
||||
<R extends RealtimeRequest> R realtime(Boolean realtime);
|
||||
|
||||
}
|
|
@ -74,13 +74,14 @@ public class TransportBulkAction extends HandledTransportAction<BulkRequest, Bul
|
|||
@Inject
|
||||
public TransportBulkAction(Settings settings, ThreadPool threadPool, TransportService transportService, ClusterService clusterService,
|
||||
TransportShardBulkAction shardBulkAction, TransportCreateIndexAction createIndexAction,
|
||||
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver) {
|
||||
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
|
||||
AutoCreateIndex autoCreateIndex) {
|
||||
super(settings, BulkAction.NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver, BulkRequest.class);
|
||||
this.clusterService = clusterService;
|
||||
this.shardBulkAction = shardBulkAction;
|
||||
this.createIndexAction = createIndexAction;
|
||||
|
||||
this.autoCreateIndex = new AutoCreateIndex(settings);
|
||||
this.autoCreateIndex = autoCreateIndex;
|
||||
this.allowIdGeneration = this.settings.getAsBoolean("action.bulk.action.allow_id_generation", true);
|
||||
}
|
||||
|
||||
|
|
|
@ -60,17 +60,19 @@ public class TransportDeleteAction extends TransportReplicationAction<DeleteRequ
|
|||
public TransportDeleteAction(Settings settings, TransportService transportService, ClusterService clusterService,
|
||||
IndicesService indicesService, ThreadPool threadPool, ShardStateAction shardStateAction,
|
||||
TransportCreateIndexAction createIndexAction, ActionFilters actionFilters,
|
||||
IndexNameExpressionResolver indexNameExpressionResolver, MappingUpdatedAction mappingUpdatedAction) {
|
||||
IndexNameExpressionResolver indexNameExpressionResolver, MappingUpdatedAction mappingUpdatedAction,
|
||||
AutoCreateIndex autoCreateIndex) {
|
||||
super(settings, DeleteAction.NAME, transportService, clusterService, indicesService, threadPool, shardStateAction,
|
||||
mappingUpdatedAction, actionFilters, indexNameExpressionResolver,
|
||||
DeleteRequest.class, DeleteRequest.class, ThreadPool.Names.INDEX);
|
||||
this.createIndexAction = createIndexAction;
|
||||
this.autoCreateIndex = new AutoCreateIndex(settings);
|
||||
this.autoCreateIndex = autoCreateIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecute(final DeleteRequest request, final ActionListener<DeleteResponse> listener) {
|
||||
if (autoCreateIndex.shouldAutoCreate(request.index(), clusterService.state())) {
|
||||
ClusterState state = clusterService.state();
|
||||
if (autoCreateIndex.shouldAutoCreate(request.index(), state)) {
|
||||
createIndexAction.execute(new CreateIndexRequest(request).index(request.index()).cause("auto(delete api)").masterNodeTimeout(request.timeout()), new ActionListener<CreateIndexResponse>() {
|
||||
@Override
|
||||
public void onResponse(CreateIndexResponse result) {
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.elasticsearch.action.get;
|
|||
|
||||
import org.elasticsearch.action.ActionRequest;
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.action.RealtimeRequest;
|
||||
import org.elasticsearch.action.ValidateActions;
|
||||
import org.elasticsearch.action.support.single.shard.SingleShardRequest;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
|
@ -43,7 +44,7 @@ import java.io.IOException;
|
|||
* @see org.elasticsearch.client.Requests#getRequest(String)
|
||||
* @see org.elasticsearch.client.Client#get(GetRequest)
|
||||
*/
|
||||
public class GetRequest extends SingleShardRequest<GetRequest> {
|
||||
public class GetRequest extends SingleShardRequest<GetRequest> implements RealtimeRequest {
|
||||
|
||||
private String type;
|
||||
private String id;
|
||||
|
@ -244,6 +245,7 @@ public class GetRequest extends SingleShardRequest<GetRequest> {
|
|||
return this.realtime == null ? true : this.realtime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetRequest realtime(Boolean realtime) {
|
||||
this.realtime = realtime;
|
||||
return this;
|
||||
|
|
|
@ -42,7 +42,7 @@ import java.util.Arrays;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class MultiGetRequest extends ActionRequest<MultiGetRequest> implements Iterable<MultiGetRequest.Item>, CompositeIndicesRequest {
|
||||
public class MultiGetRequest extends ActionRequest<MultiGetRequest> implements Iterable<MultiGetRequest.Item>, CompositeIndicesRequest, RealtimeRequest {
|
||||
|
||||
/**
|
||||
* A single get item.
|
||||
|
@ -319,6 +319,7 @@ public class MultiGetRequest extends ActionRequest<MultiGetRequest> implements I
|
|||
return this.realtime == null ? true : this.realtime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiGetRequest realtime(Boolean realtime) {
|
||||
this.realtime = realtime;
|
||||
return this;
|
||||
|
|
|
@ -75,11 +75,12 @@ public class TransportIndexAction extends TransportReplicationAction<IndexReques
|
|||
public TransportIndexAction(Settings settings, TransportService transportService, ClusterService clusterService,
|
||||
IndicesService indicesService, ThreadPool threadPool, ShardStateAction shardStateAction,
|
||||
TransportCreateIndexAction createIndexAction, MappingUpdatedAction mappingUpdatedAction,
|
||||
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver) {
|
||||
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
|
||||
AutoCreateIndex autoCreateIndex) {
|
||||
super(settings, IndexAction.NAME, transportService, clusterService, indicesService, threadPool, shardStateAction, mappingUpdatedAction,
|
||||
actionFilters, indexNameExpressionResolver, IndexRequest.class, IndexRequest.class, ThreadPool.Names.INDEX);
|
||||
this.createIndexAction = createIndexAction;
|
||||
this.autoCreateIndex = new AutoCreateIndex(settings);
|
||||
this.autoCreateIndex = autoCreateIndex;
|
||||
this.allowIdGeneration = settings.getAsBoolean("action.allow_id_generation", true);
|
||||
this.clusterService = clusterService;
|
||||
}
|
||||
|
@ -87,7 +88,8 @@ public class TransportIndexAction extends TransportReplicationAction<IndexReques
|
|||
@Override
|
||||
protected void doExecute(final IndexRequest request, final ActionListener<IndexResponse> listener) {
|
||||
// if we don't have a master, we don't have metadata, that's fine, let it find a master using create index API
|
||||
if (autoCreateIndex.shouldAutoCreate(request.index(), clusterService.state())) {
|
||||
ClusterState state = clusterService.state();
|
||||
if (autoCreateIndex.shouldAutoCreate(request.index(), state)) {
|
||||
CreateIndexRequest createIndexRequest = new CreateIndexRequest(request);
|
||||
createIndexRequest.index(request.index());
|
||||
createIndexRequest.mapping(request.type());
|
||||
|
|
|
@ -115,7 +115,10 @@ public abstract class TransportSearchTypeAction extends TransportAction<SearchRe
|
|||
|
||||
clusterState.blocks().globalBlockedRaiseException(ClusterBlockLevel.READ);
|
||||
|
||||
String[] concreteIndices = indexNameExpressionResolver.concreteIndices(clusterState, request.indicesOptions(), request.indices());
|
||||
// TODO: I think startTime() should become part of ActionRequest and that should be used both for index name
|
||||
// date math expressions and $now in scripts. This way all apis will deal with now in the same way instead
|
||||
// of just for the _search api
|
||||
String[] concreteIndices = indexNameExpressionResolver.concreteIndices(clusterState, request.indicesOptions(), startTime(), request.indices());
|
||||
|
||||
for (String index : concreteIndices) {
|
||||
clusterState.blocks().indexBlockedRaiseException(ClusterBlockLevel.READ, index);
|
||||
|
|
|
@ -20,21 +20,28 @@
|
|||
package org.elasticsearch.action.support;
|
||||
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.common.Booleans;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.regex.Regex;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
|
||||
/**
|
||||
* Encapsulates the logic of whether a new index should be automatically created when
|
||||
* a write operation is about to happen in a non existing index.
|
||||
*/
|
||||
public class AutoCreateIndex {
|
||||
public final class AutoCreateIndex {
|
||||
|
||||
private final boolean needToCheck;
|
||||
private final boolean globallyDisabled;
|
||||
private final String[] matches;
|
||||
private final String[] matches2;
|
||||
private final IndexNameExpressionResolver resolver;
|
||||
|
||||
public AutoCreateIndex(Settings settings) {
|
||||
@Inject
|
||||
public AutoCreateIndex(Settings settings, IndexNameExpressionResolver resolver) {
|
||||
this.resolver = resolver;
|
||||
String value = settings.get("action.auto_create_index");
|
||||
if (value == null || Booleans.isExplicitTrue(value)) {
|
||||
needToCheck = true;
|
||||
|
@ -71,7 +78,8 @@ public class AutoCreateIndex {
|
|||
if (!needToCheck) {
|
||||
return false;
|
||||
}
|
||||
if (state.metaData().hasConcreteIndex(index)) {
|
||||
boolean exists = resolver.hasIndexOrAlias(index, state);
|
||||
if (exists) {
|
||||
return false;
|
||||
}
|
||||
if (globallyDisabled) {
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
|||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class MultiTermVectorsRequest extends ActionRequest<MultiTermVectorsRequest> implements Iterable<TermVectorsRequest>, CompositeIndicesRequest {
|
||||
public class MultiTermVectorsRequest extends ActionRequest<MultiTermVectorsRequest> implements Iterable<TermVectorsRequest>, CompositeIndicesRequest, RealtimeRequest {
|
||||
|
||||
String preference;
|
||||
List<TermVectorsRequest> requests = new ArrayList<>();
|
||||
|
@ -162,4 +162,12 @@ public class MultiTermVectorsRequest extends ActionRequest<MultiTermVectorsReque
|
|||
public int size() {
|
||||
return requests.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiTermVectorsRequest realtime(Boolean realtime) {
|
||||
for (TermVectorsRequest request : requests) {
|
||||
request.realtime(realtime);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.elasticsearch.ElasticsearchException;
|
|||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.action.DocumentRequest;
|
||||
import org.elasticsearch.action.RealtimeRequest;
|
||||
import org.elasticsearch.action.ValidateActions;
|
||||
import org.elasticsearch.action.get.MultiGetRequest;
|
||||
import org.elasticsearch.action.support.single.shard.SingleShardRequest;
|
||||
|
@ -50,7 +51,7 @@ import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
|||
* Note, the {@link #index()}, {@link #type(String)} and {@link #id(String)} are
|
||||
* required.
|
||||
*/
|
||||
public class TermVectorsRequest extends SingleShardRequest<TermVectorsRequest> implements DocumentRequest<TermVectorsRequest> {
|
||||
public class TermVectorsRequest extends SingleShardRequest<TermVectorsRequest> implements DocumentRequest<TermVectorsRequest>, RealtimeRequest {
|
||||
|
||||
private String type;
|
||||
|
||||
|
@ -405,6 +406,7 @@ public class TermVectorsRequest extends SingleShardRequest<TermVectorsRequest> i
|
|||
/**
|
||||
* Choose whether term vectors be generated real-time.
|
||||
*/
|
||||
@Override
|
||||
public TermVectorsRequest realtime(Boolean realtime) {
|
||||
this.realtime = realtime;
|
||||
return this;
|
||||
|
|
|
@ -75,14 +75,14 @@ public class TransportUpdateAction extends TransportInstanceSingleOperationActio
|
|||
public TransportUpdateAction(Settings settings, ThreadPool threadPool, ClusterService clusterService, TransportService transportService,
|
||||
TransportIndexAction indexAction, TransportDeleteAction deleteAction, TransportCreateIndexAction createIndexAction,
|
||||
UpdateHelper updateHelper, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
|
||||
IndicesService indicesService) {
|
||||
IndicesService indicesService, AutoCreateIndex autoCreateIndex) {
|
||||
super(settings, UpdateAction.NAME, threadPool, clusterService, transportService, actionFilters, indexNameExpressionResolver, UpdateRequest.class);
|
||||
this.indexAction = indexAction;
|
||||
this.deleteAction = deleteAction;
|
||||
this.createIndexAction = createIndexAction;
|
||||
this.updateHelper = updateHelper;
|
||||
this.indicesService = indicesService;
|
||||
this.autoCreateIndex = new AutoCreateIndex(settings);
|
||||
this.autoCreateIndex = autoCreateIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,31 +21,45 @@ package org.elasticsearch.cluster.metadata;
|
|||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.action.IndicesRequest;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.joda.DateMathParser;
|
||||
import org.elasticsearch.common.joda.FormatDateTimeFormatter;
|
||||
import org.elasticsearch.common.regex.Regex;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.index.Index;
|
||||
import org.elasticsearch.index.IndexNotFoundException;
|
||||
import org.elasticsearch.indices.IndexClosedException;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import static com.google.common.collect.Lists.newArrayList;
|
||||
import static com.google.common.collect.Maps.filterEntries;
|
||||
import static com.google.common.collect.Maps.newHashMap;
|
||||
|
||||
public class IndexNameExpressionResolver {
|
||||
public class IndexNameExpressionResolver extends AbstractComponent {
|
||||
|
||||
private final ImmutableList<ExpressionResolver> expressionResolvers;
|
||||
private DateMathExpressionResolver dateMathExpressionResolver;
|
||||
|
||||
@Inject
|
||||
public IndexNameExpressionResolver() {
|
||||
expressionResolvers = ImmutableList.<ExpressionResolver>of(new WildcardExpressionResolver());
|
||||
public IndexNameExpressionResolver(Settings settings) {
|
||||
super(settings);
|
||||
expressionResolvers = ImmutableList.of(
|
||||
dateMathExpressionResolver = new DateMathExpressionResolver(settings),
|
||||
new WildcardExpressionResolver()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,6 +89,24 @@ public class IndexNameExpressionResolver {
|
|||
return concreteIndices(context, indexExpressions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the provided index expression into actual concrete indices.
|
||||
*
|
||||
* @param state the cluster state containing all the data to resolve to expressions to concrete indices
|
||||
* @param options defines how the aliases or indices need to be resolved to concrete indices
|
||||
* @param startTime The start of the request where concrete indices is being invoked for
|
||||
* @param indexExpressions expressions that can be resolved to alias or index names.
|
||||
* @return the resolved concrete indices based on the cluster state, indices options and index expressions
|
||||
* provided indices options in the context don't allow such a case, or if the final result of the indices resolution
|
||||
* contains no indices and the indices options in the context don't allow such a case.
|
||||
* @throws IllegalArgumentException if one of the aliases resolve to multiple indices and the provided
|
||||
* indices options in the context don't allow such a case.
|
||||
*/
|
||||
public String[] concreteIndices(ClusterState state, IndicesOptions options, long startTime, String... indexExpressions) {
|
||||
Context context = new Context(state, options, startTime);
|
||||
return concreteIndices(context, indexExpressions);
|
||||
}
|
||||
|
||||
String[] concreteIndices(Context context, String... indexExpressions) {
|
||||
if (indexExpressions == null || indexExpressions.length == 0) {
|
||||
indexExpressions = new String[]{MetaData.ALL};
|
||||
|
@ -159,21 +191,30 @@ public class IndexNameExpressionResolver {
|
|||
* that require a single index as a result. The indices resolution must in fact return a single index when
|
||||
* using this method, an {@link IllegalArgumentException} gets thrown otherwise.
|
||||
*
|
||||
* @param request request containing the index or alias to be resolved to concrete index and
|
||||
* the indices options to be used for the index resolution
|
||||
* @throws IndexNotFoundException if the resolved index or alias provided doesn't exist
|
||||
* @param state the cluster state containing all the data to resolve to expression to a concrete index
|
||||
* @param request The request that defines how the an alias or an index need to be resolved to a concrete index
|
||||
* and the expression that can be resolved to an alias or an index name.
|
||||
* @throws IllegalArgumentException if the index resolution lead to more than one index
|
||||
* @return the concrete index obtained as a result of the index resolution
|
||||
*/
|
||||
public String concreteSingleIndex(ClusterState state, IndicesRequest request) {
|
||||
String indexOrAlias = request.indices() != null && request.indices().length > 0 ? request.indices()[0] : null;
|
||||
String[] indices = concreteIndices(state, request.indicesOptions(), indexOrAlias);
|
||||
String indexExpression = request.indices() != null && request.indices().length > 0 ? request.indices()[0] : null;
|
||||
String[] indices = concreteIndices(state, request.indicesOptions(), indexExpression);
|
||||
if (indices.length != 1) {
|
||||
throw new IllegalArgumentException("unable to return a single index as the index and options provided got resolved to multiple indices");
|
||||
}
|
||||
return indices[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether the specified alias or index exists. If the alias or index contains datemath then that is resolved too.
|
||||
*/
|
||||
public boolean hasIndexOrAlias(String aliasOrIndex, ClusterState state) {
|
||||
Context context = new Context(state, IndicesOptions.lenientExpandOpen());
|
||||
String resolvedAliasOrIndex = dateMathExpressionResolver.resolveExpression(aliasOrIndex, context);
|
||||
return state.metaData().getAliasAndIndexLookup().containsKey(resolvedAliasOrIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through the list of indices and selects the effective list of filtering aliases for the
|
||||
* given index.
|
||||
|
@ -405,10 +446,18 @@ public class IndexNameExpressionResolver {
|
|||
|
||||
private final ClusterState state;
|
||||
private final IndicesOptions options;
|
||||
private final long startTime;
|
||||
|
||||
Context(ClusterState state, IndicesOptions options) {
|
||||
this.state = state;
|
||||
this.options = options;
|
||||
startTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public Context(ClusterState state, IndicesOptions options, long startTime) {
|
||||
this.state = state;
|
||||
this.options = options;
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public ClusterState getState() {
|
||||
|
@ -418,6 +467,10 @@ public class IndexNameExpressionResolver {
|
|||
public IndicesOptions getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
}
|
||||
|
||||
private interface ExpressionResolver {
|
||||
|
@ -582,4 +635,163 @@ public class IndexNameExpressionResolver {
|
|||
}
|
||||
}
|
||||
|
||||
final static class DateMathExpressionResolver implements ExpressionResolver {
|
||||
|
||||
private static final String EXPRESSION_LEFT_BOUND = "<";
|
||||
private static final String EXPRESSION_RIGHT_BOUND = ">";
|
||||
private static final char LEFT_BOUND = '{';
|
||||
private static final char RIGHT_BOUND = '}';
|
||||
private static final char ESCAPE_CHAR = '\\';
|
||||
private static final char TIME_ZONE_BOUND = '|';
|
||||
|
||||
private final DateTimeZone defaultTimeZone;
|
||||
private final String defaultDateFormatterPattern;
|
||||
private final DateTimeFormatter defaultDateFormatter;
|
||||
|
||||
public DateMathExpressionResolver(Settings settings) {
|
||||
String defaultTimeZoneId = settings.get("date_math_expression_resolver.default_time_zone", "UTC");
|
||||
this.defaultTimeZone = DateTimeZone.forID(defaultTimeZoneId);
|
||||
defaultDateFormatterPattern = settings.get("date_math_expression_resolver.default_date_format", "YYYY.MM.dd");
|
||||
this.defaultDateFormatter = DateTimeFormat.forPattern(defaultDateFormatterPattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> resolve(final Context context, List<String> expressions) {
|
||||
List<String> result = new ArrayList<>(expressions.size());
|
||||
for (String expression : expressions) {
|
||||
result.add(resolveExpression(expression, context));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String resolveExpression(String expression, final Context context) {
|
||||
if (expression.startsWith(EXPRESSION_LEFT_BOUND) == false || expression.endsWith(EXPRESSION_RIGHT_BOUND) == false) {
|
||||
return expression;
|
||||
}
|
||||
|
||||
boolean escape = false;
|
||||
boolean inDateFormat = false;
|
||||
boolean inPlaceHolder = false;
|
||||
final StringBuilder beforePlaceHolderSb = new StringBuilder();
|
||||
StringBuilder inPlaceHolderSb = new StringBuilder();
|
||||
final char[] text = expression.toCharArray();
|
||||
final int from = 1;
|
||||
final int length = text.length - 1;
|
||||
for (int i = from; i < length; i++) {
|
||||
boolean escapedChar = escape;
|
||||
if (escape) {
|
||||
escape = false;
|
||||
}
|
||||
|
||||
char c = text[i];
|
||||
if (c == ESCAPE_CHAR) {
|
||||
if (escapedChar) {
|
||||
beforePlaceHolderSb.append(c);
|
||||
escape = false;
|
||||
} else {
|
||||
escape = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (inPlaceHolder) {
|
||||
switch (c) {
|
||||
case LEFT_BOUND:
|
||||
if (inDateFormat && escapedChar) {
|
||||
inPlaceHolderSb.append(c);
|
||||
} else if (!inDateFormat) {
|
||||
inDateFormat = true;
|
||||
inPlaceHolderSb.append(c);
|
||||
} else {
|
||||
throw new ElasticsearchParseException("invalid dynamic name expression [{}]. invalid character in placeholder at position [{}]", new String(text, from, length), i);
|
||||
}
|
||||
break;
|
||||
|
||||
case RIGHT_BOUND:
|
||||
if (inDateFormat && escapedChar) {
|
||||
inPlaceHolderSb.append(c);
|
||||
} else if (inDateFormat) {
|
||||
inDateFormat = false;
|
||||
inPlaceHolderSb.append(c);
|
||||
} else {
|
||||
String inPlaceHolderString = inPlaceHolderSb.toString();
|
||||
int dateTimeFormatLeftBoundIndex = inPlaceHolderString.indexOf(LEFT_BOUND);
|
||||
String mathExpression;
|
||||
String dateFormatterPattern;
|
||||
DateTimeFormatter dateFormatter;
|
||||
final DateTimeZone timeZone;
|
||||
if (dateTimeFormatLeftBoundIndex < 0) {
|
||||
mathExpression = inPlaceHolderString;
|
||||
dateFormatterPattern = defaultDateFormatterPattern;
|
||||
dateFormatter = defaultDateFormatter;
|
||||
timeZone = defaultTimeZone;
|
||||
} else {
|
||||
if (inPlaceHolderString.lastIndexOf(RIGHT_BOUND) != inPlaceHolderString.length() - 1) {
|
||||
throw new ElasticsearchParseException("invalid dynamic name expression [{}]. missing closing `}` for date math format", inPlaceHolderString);
|
||||
}
|
||||
if (dateTimeFormatLeftBoundIndex == inPlaceHolderString.length() - 2) {
|
||||
throw new ElasticsearchParseException("invalid dynamic name expression [{}]. missing date format", inPlaceHolderString);
|
||||
}
|
||||
mathExpression = inPlaceHolderString.substring(0, dateTimeFormatLeftBoundIndex);
|
||||
String dateFormatterPatternAndTimeZoneId = inPlaceHolderString.substring(dateTimeFormatLeftBoundIndex + 1, inPlaceHolderString.length() - 1);
|
||||
int formatPatternTimeZoneSeparatorIndex = dateFormatterPatternAndTimeZoneId.indexOf(TIME_ZONE_BOUND);
|
||||
if (formatPatternTimeZoneSeparatorIndex != -1) {
|
||||
dateFormatterPattern = dateFormatterPatternAndTimeZoneId.substring(0, formatPatternTimeZoneSeparatorIndex);
|
||||
timeZone = DateTimeZone.forID(dateFormatterPatternAndTimeZoneId.substring(formatPatternTimeZoneSeparatorIndex + 1));
|
||||
} else {
|
||||
dateFormatterPattern = dateFormatterPatternAndTimeZoneId;
|
||||
timeZone = defaultTimeZone;
|
||||
}
|
||||
dateFormatter = DateTimeFormat.forPattern(dateFormatterPattern);
|
||||
}
|
||||
DateTimeFormatter parser = dateFormatter.withZone(timeZone);
|
||||
FormatDateTimeFormatter formatter = new FormatDateTimeFormatter(dateFormatterPattern, parser, Locale.ROOT);
|
||||
DateMathParser dateMathParser = new DateMathParser(formatter);
|
||||
long millis = dateMathParser.parse(mathExpression, new Callable<Long>() {
|
||||
@Override
|
||||
public Long call() throws Exception {
|
||||
return context.getStartTime();
|
||||
}
|
||||
}, false, timeZone);
|
||||
|
||||
String time = formatter.printer().print(millis);
|
||||
beforePlaceHolderSb.append(time);
|
||||
inPlaceHolderSb = new StringBuilder();
|
||||
inPlaceHolder = false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
inPlaceHolderSb.append(c);
|
||||
}
|
||||
} else {
|
||||
switch (c) {
|
||||
case LEFT_BOUND:
|
||||
if (escapedChar) {
|
||||
beforePlaceHolderSb.append(c);
|
||||
} else {
|
||||
inPlaceHolder = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case RIGHT_BOUND:
|
||||
if (!escapedChar) {
|
||||
throw new ElasticsearchParseException("invalid dynamic name expression [{}]. invalid character at position [{}]. " +
|
||||
"`{` and `}` are reserved characters and should be escaped when used as part of the index name using `\\` (e.g. `\\{text\\}`)", new String(text, from, length), i);
|
||||
}
|
||||
default:
|
||||
beforePlaceHolderSb.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inPlaceHolder) {
|
||||
throw new ElasticsearchParseException("invalid dynamic name expression [{}]. date math placeholder is open ended", new String(text, from, length));
|
||||
}
|
||||
if (beforePlaceHolderSb.length() == 0) {
|
||||
throw new ElasticsearchParseException("nothing captured");
|
||||
}
|
||||
return beforePlaceHolderSb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -250,6 +250,7 @@ public class RestActionModule extends AbstractModule {
|
|||
catActionMultibinder.addBinding().to(RestThreadPoolAction.class).asEagerSingleton();
|
||||
catActionMultibinder.addBinding().to(RestPluginsAction.class).asEagerSingleton();
|
||||
catActionMultibinder.addBinding().to(RestFielddataAction.class).asEagerSingleton();
|
||||
catActionMultibinder.addBinding().to(RestNodeAttrsAction.class).asEagerSingleton();
|
||||
// no abstract cat action
|
||||
bind(RestCatAction.class).asEagerSingleton();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.rest.action.cat;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoRequest;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
|
||||
import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsRequest;
|
||||
import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
|
||||
import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest;
|
||||
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNodes;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.Table;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.InetSocketTransportAddress;
|
||||
import org.elasticsearch.rest.*;
|
||||
import org.elasticsearch.rest.action.support.RestActionListener;
|
||||
import org.elasticsearch.rest.action.support.RestResponseListener;
|
||||
import org.elasticsearch.rest.action.support.RestTable;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||
|
||||
public class RestNodeAttrsAction extends AbstractCatAction {
|
||||
|
||||
@Inject
|
||||
public RestNodeAttrsAction(Settings settings, RestController controller, Client client) {
|
||||
super(settings, controller, client);
|
||||
controller.registerHandler(GET, "/_cat/nodeattrs", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
void documentation(StringBuilder sb) {
|
||||
sb.append("/_cat/nodeattrs\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRequest(final RestRequest request, final RestChannel channel, final Client client) {
|
||||
final ClusterStateRequest clusterStateRequest = new ClusterStateRequest();
|
||||
clusterStateRequest.clear().nodes(true);
|
||||
clusterStateRequest.local(request.paramAsBoolean("local", clusterStateRequest.local()));
|
||||
clusterStateRequest.masterNodeTimeout(request.paramAsTime("master_timeout", clusterStateRequest.masterNodeTimeout()));
|
||||
|
||||
client.admin().cluster().state(clusterStateRequest, new RestActionListener<ClusterStateResponse>(channel) {
|
||||
@Override
|
||||
public void processResponse(final ClusterStateResponse clusterStateResponse) {
|
||||
NodesInfoRequest nodesInfoRequest = new NodesInfoRequest();
|
||||
nodesInfoRequest.clear().jvm(false).os(false).process(true);
|
||||
client.admin().cluster().nodesInfo(nodesInfoRequest, new RestActionListener<NodesInfoResponse>(channel) {
|
||||
@Override
|
||||
public void processResponse(final NodesInfoResponse nodesInfoResponse) {
|
||||
NodesStatsRequest nodesStatsRequest = new NodesStatsRequest();
|
||||
nodesStatsRequest.clear().jvm(false).os(false).fs(false).indices(false).process(false);
|
||||
client.admin().cluster().nodesStats(nodesStatsRequest, new RestResponseListener<NodesStatsResponse>(channel) {
|
||||
@Override
|
||||
public RestResponse buildResponse(NodesStatsResponse nodesStatsResponse) throws Exception {
|
||||
return RestTable.buildResponse(buildTable(request, clusterStateResponse, nodesInfoResponse, nodesStatsResponse), channel);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
Table getTableWithHeader(final RestRequest request) {
|
||||
Table table = new Table();
|
||||
table.startHeaders();
|
||||
table.addCell("node", "default:true;alias:name;desc:node name");
|
||||
table.addCell("id", "default:false;alias:id,nodeId;desc:unique node id");
|
||||
table.addCell("pid", "default:false;alias:p;desc:process id");
|
||||
table.addCell("host", "alias:h;desc:host name");
|
||||
table.addCell("ip", "alias:i;desc:ip address");
|
||||
table.addCell("port", "default:false;alias:po;desc:bound transport port");
|
||||
table.addCell("attr", "default:true;alias:attr.name;desc:attribute description");
|
||||
table.addCell("value","default:true;alias:attr.value;desc:attribute value");
|
||||
table.endHeaders();
|
||||
return table;
|
||||
}
|
||||
|
||||
private Table buildTable(RestRequest req, ClusterStateResponse state, NodesInfoResponse nodesInfo, NodesStatsResponse nodesStats) {
|
||||
boolean fullId = req.paramAsBoolean("full_id", false);
|
||||
|
||||
DiscoveryNodes nodes = state.getState().nodes();
|
||||
Table table = getTableWithHeader(req);
|
||||
|
||||
for (DiscoveryNode node : nodes) {
|
||||
NodeInfo info = nodesInfo.getNodesMap().get(node.id());
|
||||
ImmutableMap<String, String> attrs = node.getAttributes();
|
||||
for(String att : attrs.keySet()) {
|
||||
table.startRow();
|
||||
table.addCell(node.name());
|
||||
table.addCell(fullId ? node.id() : Strings.substring(node.getId(), 0, 4));
|
||||
table.addCell(info == null ? null : info.getProcess().getId());
|
||||
table.addCell(node.getHostName());
|
||||
table.addCell(node.getHostAddress());
|
||||
if (node.address() instanceof InetSocketTransportAddress) {
|
||||
table.addCell(((InetSocketTransportAddress) node.address()).address().getPort());
|
||||
} else {
|
||||
table.addCell("-");
|
||||
}
|
||||
table.addCell(att);
|
||||
table.addCell(attrs.containsKey(att) ? attrs.get(att) : null);
|
||||
table.endRow();
|
||||
}
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
}
|
|
@ -694,7 +694,7 @@ public class ShardReplicationTests extends ElasticsearchTestCase {
|
|||
ThreadPool threadPool) {
|
||||
super(settings, actionName, transportService, clusterService, null, threadPool,
|
||||
new ShardStateAction(settings, clusterService, transportService, null, null), null,
|
||||
new ActionFilters(new HashSet<ActionFilter>()), new IndexNameExpressionResolver(), Request.class, Request.class, ThreadPool.Names.SAME);
|
||||
new ActionFilters(new HashSet<ActionFilter>()), new IndexNameExpressionResolver(Settings.EMPTY), Request.class, Request.class, ThreadPool.Names.SAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.elasticsearch.cluster.metadata.MetaData;
|
|||
import org.elasticsearch.cluster.routing.*;
|
||||
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.index.shard.ShardId;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
|
@ -46,7 +47,7 @@ import static org.hamcrest.Matchers.*;
|
|||
|
||||
public class ClusterHealthResponsesTests extends ElasticsearchTestCase {
|
||||
|
||||
private final IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
private final IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver(Settings.EMPTY);
|
||||
|
||||
private void assertIndexHealth(ClusterIndexHealth indexHealth, ShardCounter counter, IndexMetaData indexMetaData) {
|
||||
assertThat(indexHealth.getStatus(), equalTo(counter.status()));
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* 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.ElasticsearchParseException;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.cluster.ClusterName;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver.Context;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver.DateMathExpressionResolver;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
public class DateMathExpressionResolverTests extends ElasticsearchTestCase {
|
||||
|
||||
private final DateMathExpressionResolver expressionResolver = new DateMathExpressionResolver(Settings.EMPTY);
|
||||
private final Context context = new Context(
|
||||
ClusterState.builder(new ClusterName("_name")).build(), IndicesOptions.strictExpand()
|
||||
);
|
||||
|
||||
public void testNormal() throws Exception {
|
||||
int numIndexExpressions = randomIntBetween(1, 9);
|
||||
List<String> indexExpressions = new ArrayList<>(numIndexExpressions);
|
||||
for (int i = 0; i < numIndexExpressions; i++) {
|
||||
indexExpressions.add(randomAsciiOfLength(10));
|
||||
}
|
||||
List<String> result = expressionResolver.resolve(context, indexExpressions);
|
||||
assertThat(result.size(), equalTo(indexExpressions.size()));
|
||||
for (int i = 0; i < indexExpressions.size(); i++) {
|
||||
assertThat(result.get(i), equalTo(indexExpressions.get(i)));
|
||||
}
|
||||
}
|
||||
|
||||
public void testExpression() throws Exception {
|
||||
List<String> indexExpressions = Arrays.asList("<.marvel-{now}>", "<.watch_history-{now}>", "<logstash-{now}>");
|
||||
List<String> result = expressionResolver.resolve(context, indexExpressions);
|
||||
assertThat(result.size(), equalTo(3));
|
||||
assertThat(result.get(0), equalTo(".marvel-" + DateTimeFormat.forPattern("YYYY.MM.dd").print(new DateTime(context.getStartTime(), UTC))));
|
||||
assertThat(result.get(1), equalTo(".watch_history-" + DateTimeFormat.forPattern("YYYY.MM.dd").print(new DateTime(context.getStartTime(), UTC))));
|
||||
assertThat(result.get(2), equalTo("logstash-" + DateTimeFormat.forPattern("YYYY.MM.dd").print(new DateTime(context.getStartTime(), UTC))));
|
||||
}
|
||||
|
||||
public void testEmpty() throws Exception {
|
||||
List<String> result = expressionResolver.resolve(context, Collections.<String>emptyList());
|
||||
assertThat(result.size(), equalTo(0));
|
||||
}
|
||||
|
||||
public void testExpression_Static() throws Exception {
|
||||
List<String> result = expressionResolver.resolve(context, Arrays.asList("<.marvel-test>"));
|
||||
assertThat(result.size(), equalTo(1));
|
||||
assertThat(result.get(0), equalTo(".marvel-test"));
|
||||
}
|
||||
|
||||
public void testExpression_MultiParts() throws Exception {
|
||||
List<String> result = expressionResolver.resolve(context, Arrays.asList("<.text1-{now/d}-text2-{now/M}>"));
|
||||
assertThat(result.size(), equalTo(1));
|
||||
assertThat(result.get(0), equalTo(".text1-"
|
||||
+ DateTimeFormat.forPattern("YYYY.MM.dd").print(new DateTime(context.getStartTime(), UTC))
|
||||
+ "-text2-"
|
||||
+ DateTimeFormat.forPattern("YYYY.MM.dd").print(new DateTime(context.getStartTime(), UTC).withDayOfMonth(1))));
|
||||
}
|
||||
|
||||
public void testExpression_CustomFormat() throws Exception {
|
||||
List<String> results = expressionResolver.resolve(context, Arrays.asList("<.marvel-{now/d{YYYY.MM.dd}}>"));
|
||||
assertThat(results.size(), equalTo(1));
|
||||
assertThat(results.get(0), equalTo(".marvel-" + DateTimeFormat.forPattern("YYYY.MM.dd").print(new DateTime(context.getStartTime(), UTC))));
|
||||
}
|
||||
|
||||
public void testExpression_EscapeStatic() throws Exception {
|
||||
List<String> result = expressionResolver.resolve(context, Arrays.asList("<.mar\\{v\\}el-{now/d}>"));
|
||||
assertThat(result.size(), equalTo(1));
|
||||
assertThat(result.get(0), equalTo(".mar{v}el-" + DateTimeFormat.forPattern("YYYY.MM.dd").print(new DateTime(context.getStartTime(), UTC))));
|
||||
}
|
||||
|
||||
public void testExpression_EscapeDateFormat() throws Exception {
|
||||
List<String> result = expressionResolver.resolve(context, Arrays.asList("<.marvel-{now/d{'\\{year\\}'YYYY}}>"));
|
||||
assertThat(result.size(), equalTo(1));
|
||||
assertThat(result.get(0), equalTo(".marvel-" + DateTimeFormat.forPattern("'{year}'YYYY").print(new DateTime(context.getStartTime(), UTC))));
|
||||
}
|
||||
|
||||
public void testExpression_MixedArray() throws Exception {
|
||||
List<String> result = expressionResolver.resolve(context, Arrays.asList(
|
||||
"name1", "<.marvel-{now/d}>", "name2", "<.logstash-{now/M{YYYY.MM}}>"
|
||||
));
|
||||
assertThat(result.size(), equalTo(4));
|
||||
assertThat(result.get(0), equalTo("name1"));
|
||||
assertThat(result.get(1), equalTo(".marvel-" + DateTimeFormat.forPattern("YYYY.MM.dd").print(new DateTime(context.getStartTime(), UTC))));
|
||||
assertThat(result.get(2), equalTo("name2"));
|
||||
assertThat(result.get(3), equalTo(".logstash-" + DateTimeFormat.forPattern("YYYY.MM").print(new DateTime(context.getStartTime(), UTC).withDayOfMonth(1))));
|
||||
}
|
||||
|
||||
public void testExpression_CustomTimeZoneInSetting() throws Exception {
|
||||
DateTimeZone timeZone;
|
||||
int hoursOffset;
|
||||
int minutesOffset = 0;
|
||||
if (randomBoolean()) {
|
||||
hoursOffset = randomIntBetween(-12, 14);
|
||||
timeZone = DateTimeZone.forOffsetHours(hoursOffset);
|
||||
} else {
|
||||
hoursOffset = randomIntBetween(-11, 13);
|
||||
minutesOffset = randomIntBetween(0, 59);
|
||||
timeZone = DateTimeZone.forOffsetHoursMinutes(hoursOffset, minutesOffset);
|
||||
}
|
||||
DateTime now;
|
||||
if (hoursOffset >= 0) {
|
||||
// rounding to next day 00:00
|
||||
now = DateTime.now(UTC).plusHours(hoursOffset).plusMinutes(minutesOffset).withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0);
|
||||
} else {
|
||||
// rounding to today 00:00
|
||||
now = DateTime.now(UTC).withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0);
|
||||
}
|
||||
Settings settings = Settings.builder()
|
||||
.put("date_math_expression_resolver.default_time_zone", timeZone.getID())
|
||||
.build();
|
||||
DateMathExpressionResolver expressionResolver = new DateMathExpressionResolver(settings);
|
||||
Context context = new Context(this.context.getState(), this.context.getOptions(), now.getMillis());
|
||||
List<String> results = expressionResolver.resolve(context, Arrays.asList("<.marvel-{now/d{YYYY.MM.dd}}>"));
|
||||
assertThat(results.size(), equalTo(1));
|
||||
logger.info("timezone: [{}], now [{}], name: [{}]", timeZone, now, results.get(0));
|
||||
assertThat(results.get(0), equalTo(".marvel-" + DateTimeFormat.forPattern("YYYY.MM.dd").print(now.withZone(timeZone))));
|
||||
}
|
||||
|
||||
public void testExpression_CustomTimeZoneInIndexName() throws Exception {
|
||||
DateTimeZone timeZone;
|
||||
int hoursOffset;
|
||||
int minutesOffset = 0;
|
||||
if (randomBoolean()) {
|
||||
hoursOffset = randomIntBetween(-12, 14);
|
||||
timeZone = DateTimeZone.forOffsetHours(hoursOffset);
|
||||
} else {
|
||||
hoursOffset = randomIntBetween(-11, 13);
|
||||
minutesOffset = randomIntBetween(0, 59);
|
||||
timeZone = DateTimeZone.forOffsetHoursMinutes(hoursOffset, minutesOffset);
|
||||
}
|
||||
DateTime now;
|
||||
if (hoursOffset >= 0) {
|
||||
// rounding to next day 00:00
|
||||
now = DateTime.now(UTC).plusHours(hoursOffset).plusMinutes(minutesOffset).withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0);
|
||||
} else {
|
||||
// rounding to today 00:00
|
||||
now = DateTime.now(UTC).withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0);
|
||||
}
|
||||
Context context = new Context(this.context.getState(), this.context.getOptions(), now.getMillis());
|
||||
List<String> results = expressionResolver.resolve(context, Arrays.asList("<.marvel-{now/d{YYYY.MM.dd|" + timeZone.getID() + "}}>"));
|
||||
assertThat(results.size(), equalTo(1));
|
||||
logger.info("timezone: [{}], now [{}], name: [{}]", timeZone, now, results.get(0));
|
||||
assertThat(results.get(0), equalTo(".marvel-" + DateTimeFormat.forPattern("YYYY.MM.dd").print(now.withZone(timeZone))));
|
||||
}
|
||||
|
||||
@Test(expected = ElasticsearchParseException.class)
|
||||
public void testExpression_Invalid_Unescaped() throws Exception {
|
||||
expressionResolver.resolve(context, Arrays.asList("<.mar}vel-{now/d}>"));
|
||||
}
|
||||
|
||||
@Test(expected = ElasticsearchParseException.class)
|
||||
public void testExpression_Invalid_DateMathFormat() throws Exception {
|
||||
expressionResolver.resolve(context, Arrays.asList("<.marvel-{now/d{}>"));
|
||||
}
|
||||
|
||||
@Test(expected = ElasticsearchParseException.class)
|
||||
public void testExpression_Invalid_EmptyDateMathFormat() throws Exception {
|
||||
expressionResolver.resolve(context, Arrays.asList("<.marvel-{now/d{}}>"));
|
||||
}
|
||||
|
||||
@Test(expected = ElasticsearchParseException.class)
|
||||
public void testExpression_Invalid_OpenEnded() throws Exception {
|
||||
expressionResolver.resolve(context, Arrays.asList("<.marvel-{now/d>"));
|
||||
}
|
||||
|
||||
}
|
|
@ -27,6 +27,7 @@ import org.elasticsearch.cluster.ClusterState;
|
|||
import org.elasticsearch.cluster.metadata.IndexMetaData.State;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.index.IndexNotFoundException;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.indices.IndexClosedException;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.junit.Test;
|
||||
|
@ -42,6 +43,8 @@ import static org.hamcrest.Matchers.*;
|
|||
*/
|
||||
public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
||||
|
||||
private final IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver(Settings.EMPTY);
|
||||
|
||||
@Test
|
||||
public void testIndexOptions_strict() {
|
||||
MetaData.Builder mdBuilder = MetaData.builder()
|
||||
|
@ -51,7 +54,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
.put(indexBuilder("foofoo").putAlias(AliasMetaData.builder("barbaz")));
|
||||
|
||||
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
|
||||
IndicesOptions[] indicesOptions = new IndicesOptions[]{ IndicesOptions.strictExpandOpen(), IndicesOptions.strictExpand()};
|
||||
for (IndicesOptions options : indicesOptions) {
|
||||
|
@ -141,7 +143,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
.put(indexBuilder("foofoo-closed").state(IndexMetaData.State.CLOSE))
|
||||
.put(indexBuilder("foofoo").putAlias(AliasMetaData.builder("barbaz")));
|
||||
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
|
||||
IndicesOptions lenientExpand = IndicesOptions.fromOptions(true, true, true, true);
|
||||
IndicesOptions[] indicesOptions = new IndicesOptions[]{ IndicesOptions.lenientExpandOpen(), lenientExpand};
|
||||
|
@ -210,7 +211,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
.put(indexBuilder("foofoo-closed").state(IndexMetaData.State.CLOSE))
|
||||
.put(indexBuilder("foofoo").putAlias(AliasMetaData.builder("barbaz")));
|
||||
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
|
||||
IndicesOptions expandOpen = IndicesOptions.fromOptions(true, false, true, false);
|
||||
IndicesOptions expand = IndicesOptions.fromOptions(true, false, true, true);
|
||||
|
@ -260,7 +260,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
.put(indexBuilder("bar"))
|
||||
.put(indexBuilder("foobar").putAlias(AliasMetaData.builder("barbaz")));
|
||||
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
|
||||
// Only closed
|
||||
IndicesOptions options = IndicesOptions.fromOptions(false, true, false, true);
|
||||
|
@ -333,7 +332,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
.put(indexBuilder("foofoo-closed").state(IndexMetaData.State.CLOSE))
|
||||
.put(indexBuilder("foofoo").putAlias(AliasMetaData.builder("barbaz")));
|
||||
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
|
||||
//ignore unavailable and allow no indices
|
||||
{
|
||||
|
@ -428,7 +426,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
.put(indexBuilder("foofoo-closed").state(IndexMetaData.State.CLOSE))
|
||||
.put(indexBuilder("foofoo").putAlias(AliasMetaData.builder("barbaz")));
|
||||
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
|
||||
//error on both unavailable and no indices + every alias needs to expand to a single index
|
||||
|
||||
|
@ -482,7 +479,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
@Test
|
||||
public void testIndexOptions_emptyCluster() {
|
||||
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(MetaData.builder().build()).build();
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
|
||||
IndicesOptions options = IndicesOptions.strictExpandOpen();
|
||||
IndexNameExpressionResolver.Context context = new IndexNameExpressionResolver.Context(state, options);
|
||||
|
@ -532,7 +528,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
.put(indexBuilder("testXXX"))
|
||||
.put(indexBuilder("kuku"));
|
||||
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
IndexNameExpressionResolver.Context context = new IndexNameExpressionResolver.Context(state, IndicesOptions.strictExpandOpen());
|
||||
|
||||
indexNameExpressionResolver.concreteIndices(context, "testZZZ");
|
||||
|
@ -544,7 +539,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
.put(indexBuilder("testXXX"))
|
||||
.put(indexBuilder("kuku"));
|
||||
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
IndexNameExpressionResolver.Context context = new IndexNameExpressionResolver.Context(state, IndicesOptions.lenientExpandOpen());
|
||||
|
||||
assertThat(newHashSet(indexNameExpressionResolver.concreteIndices(context, "testXXX", "testZZZ")), equalTo(newHashSet("testXXX")));
|
||||
|
@ -556,7 +550,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
.put(indexBuilder("testXXX"))
|
||||
.put(indexBuilder("kuku"));
|
||||
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
IndexNameExpressionResolver.Context context = new IndexNameExpressionResolver.Context(state, IndicesOptions.strictExpandOpen());
|
||||
|
||||
assertThat(newHashSet(indexNameExpressionResolver.concreteIndices(context, "testMo", "testMahdy")), equalTo(newHashSet("testXXX")));
|
||||
|
@ -568,9 +561,7 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
.put(indexBuilder("testXXX"))
|
||||
.put(indexBuilder("kuku"));
|
||||
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
IndexNameExpressionResolver.Context context = new IndexNameExpressionResolver.Context(state, IndicesOptions.lenientExpandOpen());
|
||||
|
||||
assertThat(newHashSet(indexNameExpressionResolver.concreteIndices(context, new String[]{})), equalTo(Sets.newHashSet("kuku", "testXXX")));
|
||||
}
|
||||
|
||||
|
@ -583,7 +574,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
.put(indexBuilder("testYYY").state(State.OPEN))
|
||||
.put(indexBuilder("testYYX").state(State.OPEN));
|
||||
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
|
||||
IndexNameExpressionResolver.Context context = new IndexNameExpressionResolver.Context(state, IndicesOptions.fromOptions(true, true, false, false));
|
||||
assertThat(newHashSet(indexNameExpressionResolver.concreteIndices(context, "testX*")), equalTo(new HashSet<String>()));
|
||||
|
@ -615,7 +605,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
|
||||
IndicesOptions indicesOptions = IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean());
|
||||
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(MetaData.builder().build()).build();
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
IndexNameExpressionResolver.Context context = new IndexNameExpressionResolver.Context(state, indicesOptions);
|
||||
|
||||
// with no indices, asking for all indices should return empty list or exception, depending on indices options
|
||||
|
@ -633,7 +622,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
.put(indexBuilder("bbb").state(State.OPEN).putAlias(AliasMetaData.builder("bbb_alias1")))
|
||||
.put(indexBuilder("ccc").state(State.CLOSE).putAlias(AliasMetaData.builder("ccc_alias1")));
|
||||
state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
|
||||
indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
context = new IndexNameExpressionResolver.Context(state, indicesOptions);
|
||||
if (indicesOptions.expandWildcardsOpen() || indicesOptions.expandWildcardsClosed() || indicesOptions.allowNoIndices()) {
|
||||
String[] concreteIndices = indexNameExpressionResolver.concreteIndices(context, allIndices);
|
||||
|
@ -676,7 +664,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
.put(indexBuilder("bbb").state(State.OPEN).putAlias(AliasMetaData.builder("bbb_alias1")))
|
||||
.put(indexBuilder("ccc").state(State.CLOSE).putAlias(AliasMetaData.builder("ccc_alias1")));
|
||||
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
IndexNameExpressionResolver.Context context = new IndexNameExpressionResolver.Context(state, indicesOptions);
|
||||
|
||||
// asking for non existing wildcard pattern should return empty list or exception
|
||||
|
@ -760,7 +747,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
//even though it does identify all indices, it's not a pattern but just an explicit list of them
|
||||
String[] concreteIndices = new String[]{"index1", "index2", "index3"};
|
||||
MetaData metaData = metaDataBuilder(concreteIndices);
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
assertThat(indexNameExpressionResolver.isPatternMatchingAllIndices(metaData, concreteIndices, concreteIndices), equalTo(false));
|
||||
}
|
||||
|
||||
|
@ -769,7 +755,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
String[] indicesOrAliases = new String[]{"*"};
|
||||
String[] concreteIndices = new String[]{"index1", "index2", "index3"};
|
||||
MetaData metaData = metaDataBuilder(concreteIndices);
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
assertThat(indexNameExpressionResolver.isPatternMatchingAllIndices(metaData, indicesOrAliases, concreteIndices), equalTo(true));
|
||||
}
|
||||
|
||||
|
@ -778,7 +763,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
String[] indicesOrAliases = new String[]{"index*"};
|
||||
String[] concreteIndices = new String[]{"index1", "index2", "index3"};
|
||||
MetaData metaData = metaDataBuilder(concreteIndices);
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
assertThat(indexNameExpressionResolver.isPatternMatchingAllIndices(metaData, indicesOrAliases, concreteIndices), equalTo(true));
|
||||
}
|
||||
|
||||
|
@ -788,7 +772,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
String[] concreteIndices = new String[]{"index1", "index2", "index3"};
|
||||
String[] allConcreteIndices = new String[]{"index1", "index2", "index3", "a", "b"};
|
||||
MetaData metaData = metaDataBuilder(allConcreteIndices);
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
assertThat(indexNameExpressionResolver.isPatternMatchingAllIndices(metaData, indicesOrAliases, concreteIndices), equalTo(false));
|
||||
}
|
||||
|
||||
|
@ -797,7 +780,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
String[] indicesOrAliases = new String[]{"-index1", "+index1"};
|
||||
String[] concreteIndices = new String[]{"index1", "index2", "index3"};
|
||||
MetaData metaData = metaDataBuilder(concreteIndices);
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
assertThat(indexNameExpressionResolver.isPatternMatchingAllIndices(metaData, indicesOrAliases, concreteIndices), equalTo(true));
|
||||
}
|
||||
|
||||
|
@ -807,7 +789,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
String[] concreteIndices = new String[]{"index2", "index3"};
|
||||
String[] allConcreteIndices = new String[]{"index1", "index2", "index3"};
|
||||
MetaData metaData = metaDataBuilder(allConcreteIndices);
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
assertThat(indexNameExpressionResolver.isPatternMatchingAllIndices(metaData, indicesOrAliases, concreteIndices), equalTo(false));
|
||||
}
|
||||
|
||||
|
@ -816,7 +797,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
String[] indicesOrAliases = new String[]{"index*", "-index1", "+index1"};
|
||||
String[] concreteIndices = new String[]{"index1", "index2", "index3"};
|
||||
MetaData metaData = metaDataBuilder(concreteIndices);
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
assertThat(indexNameExpressionResolver.isPatternMatchingAllIndices(metaData, indicesOrAliases, concreteIndices), equalTo(true));
|
||||
}
|
||||
|
||||
|
@ -826,7 +806,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
String[] concreteIndices = new String[]{"index2", "index3"};
|
||||
String[] allConcreteIndices = new String[]{"index1", "index2", "index3"};
|
||||
MetaData metaData = metaDataBuilder(allConcreteIndices);
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
assertThat(indexNameExpressionResolver.isPatternMatchingAllIndices(metaData, indicesOrAliases, concreteIndices), equalTo(false));
|
||||
}
|
||||
|
||||
|
@ -837,7 +816,6 @@ public class IndexNameExpressionResolverTests extends ElasticsearchTestCase {
|
|||
.put(indexBuilder("foo2-closed").state(IndexMetaData.State.CLOSE).putAlias(AliasMetaData.builder("foobar2-closed")))
|
||||
.put(indexBuilder("foo3").putAlias(AliasMetaData.builder("foobar2-closed")));
|
||||
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
|
||||
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver();
|
||||
|
||||
IndexNameExpressionResolver.Context context = new IndexNameExpressionResolver.Context(state, IndicesOptions.strictExpandOpenAndForbidClosed());
|
||||
try {
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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.indices;
|
||||
|
||||
import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
|
||||
import org.elasticsearch.action.delete.DeleteResponse;
|
||||
import org.elasticsearch.action.get.GetResponse;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||
import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
public class DateMathIndexExpressionsIntegrationTests extends ElasticsearchIntegrationTest {
|
||||
|
||||
public void testIndexNameDateMathExpressions() {
|
||||
DateTime now = new DateTime(DateTimeZone.UTC);
|
||||
String index1 = ".marvel-" + DateTimeFormat.forPattern("YYYY.MM.dd").print(now);
|
||||
String index2 = ".marvel-" + DateTimeFormat.forPattern("YYYY.MM.dd").print(now.minusDays(1));
|
||||
String index3 = ".marvel-" + DateTimeFormat.forPattern("YYYY.MM.dd").print(now.minusDays(2));
|
||||
createIndex(index1, index2, index3);
|
||||
|
||||
String dateMathExp1 = "<.marvel-{now/d}>";
|
||||
String dateMathExp2 = "<.marvel-{now/d-1d}>";
|
||||
String dateMathExp3 = "<.marvel-{now/d-2d}>";
|
||||
client().prepareIndex(dateMathExp1, "type", "1").setSource("{}").get();
|
||||
client().prepareIndex(dateMathExp2, "type", "2").setSource("{}").get();
|
||||
client().prepareIndex(dateMathExp3, "type", "3").setSource("{}").get();
|
||||
refresh();
|
||||
|
||||
SearchResponse searchResponse = client().prepareSearch(dateMathExp1, dateMathExp2, dateMathExp3).get();
|
||||
ElasticsearchAssertions.assertHitCount(searchResponse, 3);
|
||||
ElasticsearchAssertions.assertSearchHits(searchResponse, "1", "2", "3");
|
||||
|
||||
GetResponse getResponse = client().prepareGet(dateMathExp1, "type", "1").get();
|
||||
assertThat(getResponse.isExists(), is(true));
|
||||
assertThat(getResponse.getId(), equalTo("1"));
|
||||
|
||||
getResponse = client().prepareGet(dateMathExp2, "type", "2").get();
|
||||
assertThat(getResponse.isExists(), is(true));
|
||||
assertThat(getResponse.getId(), equalTo("2"));
|
||||
|
||||
getResponse = client().prepareGet(dateMathExp3, "type", "3").get();
|
||||
assertThat(getResponse.isExists(), is(true));
|
||||
assertThat(getResponse.getId(), equalTo("3"));
|
||||
|
||||
IndicesStatsResponse indicesStatsResponse = client().admin().indices().prepareStats(dateMathExp1, dateMathExp2, dateMathExp3).get();
|
||||
assertThat(indicesStatsResponse.getIndex(index1), notNullValue());
|
||||
assertThat(indicesStatsResponse.getIndex(index2), notNullValue());
|
||||
assertThat(indicesStatsResponse.getIndex(index3), notNullValue());
|
||||
|
||||
DeleteResponse deleteResponse = client().prepareDelete(dateMathExp1, "type", "1").get();
|
||||
assertThat(deleteResponse.isFound(), equalTo(true));
|
||||
assertThat(deleteResponse.getId(), equalTo("1"));
|
||||
|
||||
deleteResponse = client().prepareDelete(dateMathExp2, "type", "2").get();
|
||||
assertThat(deleteResponse.isFound(), equalTo(true));
|
||||
assertThat(deleteResponse.getId(), equalTo("2"));
|
||||
|
||||
deleteResponse = client().prepareDelete(dateMathExp3, "type", "3").get();
|
||||
assertThat(deleteResponse.isFound(), equalTo(true));
|
||||
assertThat(deleteResponse.getId(), equalTo("3"));
|
||||
}
|
||||
|
||||
}
|
|
@ -20,7 +20,6 @@ package org.elasticsearch.search.aggregations.metrics;
|
|||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import org.apache.lucene.util.LuceneTestCase.AwaitsFix;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.script.Script;
|
||||
|
@ -51,7 +50,6 @@ import static org.hamcrest.Matchers.sameInstance;
|
|||
/**
|
||||
*
|
||||
*/
|
||||
@AwaitsFix(bugUrl = "single test methods fail with occassional seeds (see HDRPercentilesTests.testScript_ExplicitSingleValued_WithParams for example) but only if run as a whole test class not if run as a single test method")
|
||||
public class HDRPercentileRanksTests extends AbstractNumericTests {
|
||||
|
||||
private static double[] randomPercents(long minValue, long maxValue) {
|
||||
|
@ -372,7 +370,6 @@ public class HDRPercentileRanksTests extends AbstractNumericTests {
|
|||
|
||||
@Override
|
||||
@Test
|
||||
@AwaitsFix(bugUrl="Fails with seed: B75FCDC119D90BBE, Colin to fix")
|
||||
public void testScript_SingleValued_WithParams() throws Exception {
|
||||
int sigDigits = randomSignificantDigits();
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
|
|
|
@ -20,7 +20,6 @@ package org.elasticsearch.search.aggregations.metrics;
|
|||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import org.apache.lucene.util.LuceneTestCase.AwaitsFix;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.script.Script;
|
||||
|
@ -52,7 +51,6 @@ import static org.hamcrest.Matchers.sameInstance;
|
|||
/**
|
||||
*
|
||||
*/
|
||||
@AwaitsFix(bugUrl = "single test methods fail with occassional seeds (see testScript_ExplicitSingleValued_WithParams for example) but only if run as a whole test class not if run as a single test method")
|
||||
public class HDRPercentilesTests extends AbstractNumericTests {
|
||||
|
||||
private static double[] randomPercentiles() {
|
||||
|
@ -379,7 +377,6 @@ public class HDRPercentilesTests extends AbstractNumericTests {
|
|||
|
||||
@Override
|
||||
@Test
|
||||
@AwaitsFix(bugUrl = "fails with -Dtests.seed=5BFFA768633A0A59 but only if run as a whole test class not if run as a single test method")
|
||||
public void testScript_ExplicitSingleValued_WithParams() throws Exception {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("dec", 1);
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -141,7 +141,7 @@
|
|||
<!-- TODO: doesn't belong here, but we will figure it out -->
|
||||
<target name="start-foreground" depends="stop-external-cluster">
|
||||
<delete dir="${integ.scratch}"/>
|
||||
<unzip src="${project.build.directory}/releases/${project.artifactId}-${project.version}.zip" dest="${integ.scratch}"/>
|
||||
<unzip src="${project.build.directory}/releases/elasticsearch-${project.version}.zip" dest="${integ.scratch}"/>
|
||||
<local name="home"/>
|
||||
<property name="home" location="${integ.scratch}/elasticsearch-${elasticsearch.version}"/>
|
||||
<run-script dir="${home}" script="bin/elasticsearch" spawn="false"
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
d1831874fb3c769fd126c4826e69e6b40c703ee0
|
|
@ -0,0 +1 @@
|
|||
7495feb7f71ee124bd2a7e7d83590e296d71d80e
|
|
@ -315,6 +315,8 @@
|
|||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<!-- https://github.com/elastic/elasticsearch/issues/12528 -->
|
||||
<skip>true</skip>
|
||||
<target>
|
||||
<condition property="licenses.exists">
|
||||
<available file="${basedir}/../licenses" type="dir"/>
|
||||
|
@ -336,31 +338,6 @@
|
|||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>package.rpm</name>
|
||||
<value>true</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>rpm-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-rpm</id>
|
||||
<goals>
|
||||
<goal>attached-rpm</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>sign-rpm</id>
|
||||
<activation>
|
||||
|
|
|
@ -98,6 +98,19 @@
|
|||
</configuration>
|
||||
</execution>
|
||||
<!-- execution and integration tests -->
|
||||
<!-- start up elasticsearch in foreground -->
|
||||
<execution>
|
||||
<id>execute</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<target if="${run}">
|
||||
<ant antfile="${elasticsearch.integ.antfile}" target="start-foreground"/>
|
||||
</target>
|
||||
</configuration>
|
||||
</execution>
|
||||
<!-- start up external cluster -->
|
||||
<execution>
|
||||
<id>integ-setup</id>
|
||||
|
|
|
@ -9,6 +9,7 @@ The conventions listed in this chapter can be applied throughout the REST
|
|||
API, unless otherwise specified.
|
||||
|
||||
* <<multi-index>>
|
||||
* <<date-math-index-names>>
|
||||
* <<common-options>>
|
||||
|
||||
--
|
||||
|
@ -55,6 +56,76 @@ The defaults settings for the above parameters depend on the api being used.
|
|||
NOTE: Single index APIs such as the <<docs>> and the
|
||||
<<indices-aliases,single-index `alias` APIs>> do not support multiple indices.
|
||||
|
||||
[[date-math-index-names]]
|
||||
== Date math support in index names
|
||||
|
||||
Date math index name resolution enables you to search a range of time-series indices, rather
|
||||
than searching all of your time-series indices and filtering the results or maintaining aliases.
|
||||
Limiting the number of indices that are searched reduces the load on the cluster and improves
|
||||
execution performance. For example, if you are searching for errors in your
|
||||
daily logs, you can use a date math name template to restrict the search to the past
|
||||
two days.
|
||||
|
||||
Almost all APIs that have an `index` parameter, support date math in the `index` parameter
|
||||
value.
|
||||
|
||||
A date math index name takes the following form:
|
||||
|
||||
[source,txt]
|
||||
----------------------------------------------------------------------
|
||||
<static_name{date_math_expr{date_format|time_zone}}>
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Where:
|
||||
|
||||
[horizontal]
|
||||
`static_name`:: is the static text part of the name
|
||||
`date_math_expr`:: is a dynamic date math expression that computes the date dynamically
|
||||
`date_format`:: is the optional format in which the computed date should be rendered. Defaults to `YYYY.MM.dd`.
|
||||
`time_zone`:: is the optional time zone . Defaults to `utc`.
|
||||
|
||||
You must enclose date math index name expressions within angle brackets. For example:
|
||||
|
||||
[source,js]
|
||||
----------------------------------------------------------------------
|
||||
curl -XGET 'localhost:9200/<logstash-{now/d-2d}>/_search' {
|
||||
"query" : {
|
||||
...
|
||||
}
|
||||
}
|
||||
----------------------------------------------------------------------
|
||||
|
||||
The following example shows different forms of date math index names and the final index names
|
||||
they resolve to given the current time is 22rd March 2024 noon utc.
|
||||
|
||||
[options="header"]
|
||||
|======
|
||||
| Expression |Resolves to
|
||||
| `<logstash-{now/d}>` | `logstash-2024.03.22`
|
||||
| `<logstash-{now/M}>` | `logstash-2024.03.01`
|
||||
| `<logstash-{now/M{YYYY.MM}}>` | `logstash-2024.03`
|
||||
| `<logstash-{now/M-1M{YYYY.MM}}>` | `logstash-2024.02`
|
||||
| `<logstash-{now/d{YYYY.MM.dd\|+12:00}}` | `logstash-2024.03.23`
|
||||
|======
|
||||
|
||||
To use the characters `{` and `}` in the static part of an index name template, escape them
|
||||
with a backslash `\`, for example:
|
||||
|
||||
* `<elastic\\{ON\\}-{now/M}>` resolves to `elastic{ON}-2024.03.01`
|
||||
|
||||
The following example shows a search request that searches the Logstash indices for the past
|
||||
three days, assuming the indices use the default Logstash index name format,
|
||||
`logstash-YYYY.MM.dd`.
|
||||
|
||||
[source,js]
|
||||
----------------------------------------------------------------------
|
||||
curl -XGET 'localhost:9200/<logstash-{now/d-2d}>,<logstash-{now/d-1d}>,<logstash-{now/d}>/_search' {
|
||||
"query" : {
|
||||
...
|
||||
}
|
||||
}
|
||||
----------------------------------------------------------------------
|
||||
|
||||
[[common-options]]
|
||||
== Common options
|
||||
|
||||
|
|
|
@ -112,6 +112,8 @@ include::cat/indices.asciidoc[]
|
|||
|
||||
include::cat/master.asciidoc[]
|
||||
|
||||
include::cat/nodeattrs.asciidoc[]
|
||||
|
||||
include::cat/nodes.asciidoc[]
|
||||
|
||||
include::cat/pending_tasks.asciidoc[]
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
[[cat-nodeattrs]]
|
||||
== cat nodeattrs
|
||||
|
||||
The `nodeattrs` command shows custom node attributes.
|
||||
|
||||
["source","sh",subs="attributes,callouts"]
|
||||
--------------------------------------------------
|
||||
% curl 192.168.56.10:9200/_cat/nodeattrs
|
||||
node host ip attr value
|
||||
Black Bolt epsilon 192.168.1.8 rack rack314
|
||||
Black Bolt epsilon 192.168.1.8 azone us-east-1
|
||||
--------------------------------------------------
|
||||
|
||||
The first few columns give you basic info per node.
|
||||
|
||||
|
||||
["source","sh",subs="attributes,callouts"]
|
||||
--------------------------------------------------
|
||||
node host ip
|
||||
Black Bolt epsilon 192.168.1.8
|
||||
Black Bolt epsilon 192.168.1.8
|
||||
--------------------------------------------------
|
||||
|
||||
|
||||
The attr and value columns can give you a picture of custom node attributes.
|
||||
|
||||
[source,sh]
|
||||
--------------------------------------------------
|
||||
attr value
|
||||
rack rack314
|
||||
azone us-east-1
|
||||
--------------------------------------------------
|
||||
|
||||
[float]
|
||||
=== Columns
|
||||
|
||||
Below is an exhaustive list of the existing headers that can be
|
||||
passed to `nodes?h=` to retrieve the relevant details in ordered
|
||||
columns. If no headers are specified, then those marked to Appear
|
||||
by Default will appear. If any header is specified, then the defaults
|
||||
are not used.
|
||||
|
||||
Aliases can be used in place of the full header name for brevity.
|
||||
Columns appear in the order that they are listed below unless a
|
||||
different order is specified (e.g., `h=attr,value` versus `h=value,attr`).
|
||||
|
||||
When specifying headers, the headers are not placed in the output
|
||||
by default. To have the headers appear in the output, use verbose
|
||||
mode (`v`). The header name will match the supplied value (e.g.,
|
||||
`pid` versus `p`). For example:
|
||||
|
||||
["source","sh",subs="attributes,callouts"]
|
||||
--------------------------------------------------
|
||||
% curl 192.168.56.10:9200/_cat/nodeattrs?v&h=name,pid,attr,value
|
||||
name pid attr value
|
||||
Black Bolt 28000 rack rack314
|
||||
Black Bolt 28000 azone us-east-1
|
||||
--------------------------------------------------
|
||||
|
||||
[cols="<,<,<,<,<",options="header",subs="normal"]
|
||||
|=======================================================================
|
||||
|Header |Alias |Appear by Default |Description |Example
|
||||
|`node`|`name`|Yes|Name of the node|Black Bolt
|
||||
|`id` |`nodeId` |No |Unique node ID |k0zy
|
||||
|`pid` |`p` |No |Process ID |13061
|
||||
|`host` |`h` |Yes |Host name |n1
|
||||
|`ip` |`i` |Yes |IP address |127.0.1.1
|
||||
|`port` |`po` |No |Bound transport port |9300
|
||||
|`attr` | `attr.name` | Yes | Attribute name | rack
|
||||
|`value` | `attr.value` | Yes | Attribute value | rack123
|
||||
|=======================================================================
|
9
pom.xml
9
pom.xml
|
@ -397,7 +397,7 @@
|
|||
<dependency>
|
||||
<groupId>org.hdrhistogram</groupId>
|
||||
<artifactId>HdrHistogram</artifactId>
|
||||
<version>2.1.5</version>
|
||||
<version>2.1.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
@ -587,7 +587,12 @@
|
|||
<jvmOutputAction>warn</jvmOutputAction>
|
||||
<leaveTemporary>true</leaveTemporary>
|
||||
<parallelism>${tests.jvms}</parallelism>
|
||||
<assertions enableSystemAssertions="true">
|
||||
<!-- System assertions (-esa) are disabled for now because of what looks like a
|
||||
JDK bug triggered by Groovy on JDK7. We should look at re-enabling system
|
||||
assertions when we upgrade to a new version of Groovy (currently 2.4.4) or
|
||||
require JDK8. See https://issues.apache.org/jira/browse/GROOVY-7528.
|
||||
-->
|
||||
<assertions enableSystemAssertions="false">
|
||||
<enable/>
|
||||
<disable package="${tests.assertion.disabled}"/>
|
||||
<!-- pass org.elasticsearch to run without assertions -->
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"cat.nodeattrs": {
|
||||
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-nodeattrs.html",
|
||||
"methods": ["GET"],
|
||||
"url": {
|
||||
"path": "/_cat/nodeattrs",
|
||||
"paths": ["/_cat/nodeattrs"],
|
||||
"parts": {
|
||||
},
|
||||
"params": {
|
||||
"local": {
|
||||
"type" : "boolean",
|
||||
"description" : "Return local information, do not retrieve the state from master node (default: false)"
|
||||
},
|
||||
"master_timeout": {
|
||||
"type" : "time",
|
||||
"description" : "Explicit operation timeout for connection to master node"
|
||||
},
|
||||
"h": {
|
||||
"type": "list",
|
||||
"description" : "Comma-separated list of column names to display"
|
||||
},
|
||||
"help": {
|
||||
"type": "boolean",
|
||||
"description": "Return help information",
|
||||
"default": false
|
||||
},
|
||||
"v": {
|
||||
"type": "boolean",
|
||||
"description": "Verbose mode. Display column headers",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"body": null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
"Test cat nodes attrs output":
|
||||
|
||||
- do:
|
||||
cat.nodeattrs:
|
||||
v: false
|
||||
|
||||
- match:
|
||||
$body: |
|
||||
/((\S+)\s+(\S+)\s+(\d{1,3}\.){3}\d{1,3}\s+(\S+)\s+(\S+)\s*)+/
|
||||
|
||||
- do:
|
||||
cat.nodeattrs:
|
||||
v: true
|
||||
|
||||
- match:
|
||||
$body: |
|
||||
/((\S+)\s+(\S+)\s+(\d{1,3}\.){3}\d{1,3}\s+(\S+)\s+(\S+)\s*)+/
|
||||
|
||||
- do:
|
||||
cat.nodeattrs:
|
||||
h: attr,value
|
||||
v: true
|
||||
|
||||
- match:
|
||||
$body: |
|
||||
/((\S+)\s+(\S+)\s*)+/
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# build zip package, but ensuring its from the current source
|
||||
# turn off tests and other validation to speed it up
|
||||
# TODO: can be sped up more, if shading is moved out of core/
|
||||
# TODO: this will work on windows too. feel free to make a .bat
|
||||
mvn -am -pl dev-tools,distribution/zip package -DskipTests -Drun -Pdev
|
Loading…
Reference in New Issue