Introduce the deprecation API (elastic/x-pack-elasticsearch#1833)
Adds REST endpoint and Transport Action for retrieving breaking-changes deprecations that exist in current version. This PR is just the framework for such an API, future checks will be added to the appropriate branches. Original commit: elastic/x-pack-elasticsearch@990e3468e9
This commit is contained in:
parent
6d4be0e5d3
commit
8145b100f1
|
@ -51,6 +51,9 @@ public class XPackLicenseState {
|
|||
messages.put(XPackPlugin.LOGSTASH, new String[] {
|
||||
"Logstash specific APIs are disabled. You can continue to manage and poll stored configurations"
|
||||
});
|
||||
messages.put(XPackPlugin.DEPRECATION, new String[] {
|
||||
"Deprecation APIs are disabled"
|
||||
});
|
||||
EXPIRATION_MESSAGES = Collections.unmodifiableMap(messages);
|
||||
}
|
||||
|
||||
|
@ -432,4 +435,12 @@ public class XPackLicenseState {
|
|||
public boolean isLogstashAllowed() {
|
||||
return status.active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecation APIs are always allowed as long as there is an active license
|
||||
* @return {@code true} as long as there is a valid license
|
||||
*/
|
||||
public boolean isDeprecationAllowed() {
|
||||
return status.active;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ import org.elasticsearch.xpack.common.http.auth.HttpAuthRegistry;
|
|||
import org.elasticsearch.xpack.common.http.auth.basic.BasicAuth;
|
||||
import org.elasticsearch.xpack.common.http.auth.basic.BasicAuthFactory;
|
||||
import org.elasticsearch.xpack.common.text.TextTemplateEngine;
|
||||
import org.elasticsearch.xpack.deprecation.Deprecation;
|
||||
import org.elasticsearch.xpack.extensions.XPackExtension;
|
||||
import org.elasticsearch.xpack.extensions.XPackExtensionsService;
|
||||
import org.elasticsearch.xpack.graph.Graph;
|
||||
|
@ -148,6 +149,9 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
/** Name constant for the Logstash feature. */
|
||||
public static final String LOGSTASH = "logstash";
|
||||
|
||||
/** Name constant for the Deprecation API feature. */
|
||||
public static final String DEPRECATION = "deprecation";
|
||||
|
||||
// inside of YAML settings we still use xpack do not having handle issues with dashes
|
||||
private static final String SETTINGS_NAME = "xpack";
|
||||
|
||||
|
@ -198,6 +202,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
protected Graph graph;
|
||||
protected MachineLearning machineLearning;
|
||||
protected Logstash logstash;
|
||||
protected Deprecation deprecation;
|
||||
|
||||
public XPackPlugin(
|
||||
final Settings settings,
|
||||
|
@ -215,6 +220,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
this.graph = new Graph(settings);
|
||||
this.machineLearning = new MachineLearning(settings, env, licenseState);
|
||||
this.logstash = new Logstash(settings);
|
||||
this.deprecation = new Deprecation();
|
||||
// Check if the node is a transport client.
|
||||
if (transportClientMode == false) {
|
||||
this.extensionsService = new XPackExtensionsService(settings, resolveXPackExtensionsFile(env), getExtensions());
|
||||
|
@ -418,6 +424,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
actions.addAll(watcher.getActions());
|
||||
actions.addAll(graph.getActions());
|
||||
actions.addAll(machineLearning.getActions());
|
||||
actions.addAll(deprecation.getActions());
|
||||
return actions;
|
||||
}
|
||||
|
||||
|
@ -451,6 +458,8 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
indexNameExpressionResolver, nodesInCluster));
|
||||
handlers.addAll(machineLearning.getRestHandlers(settings, restController, clusterSettings, indexScopedSettings, settingsFilter,
|
||||
indexNameExpressionResolver, nodesInCluster));
|
||||
handlers.addAll(deprecation.getRestHandlers(settings, restController, clusterSettings, indexScopedSettings, settingsFilter,
|
||||
indexNameExpressionResolver, nodesInCluster));
|
||||
return handlers;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.deprecation;
|
||||
|
||||
|
||||
import org.elasticsearch.action.ActionRequest;
|
||||
import org.elasticsearch.action.ActionResponse;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNodes;
|
||||
import org.elasticsearch.common.settings.ClusterSettings;
|
||||
import org.elasticsearch.common.settings.IndexScopedSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.settings.SettingsFilter;
|
||||
import org.elasticsearch.plugins.ActionPlugin;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestHandler;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* The plugin class for the Deprecation API
|
||||
*/
|
||||
public class Deprecation implements ActionPlugin {
|
||||
@Override
|
||||
public List<ActionHandler<? extends ActionRequest, ? extends ActionResponse>> getActions() {
|
||||
return Collections.singletonList(new ActionHandler<>(DeprecationInfoAction.INSTANCE, DeprecationInfoAction.TransportAction.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RestHandler> getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings,
|
||||
IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter,
|
||||
IndexNameExpressionResolver indexNameExpressionResolver,
|
||||
Supplier<DiscoveryNodes> nodesInCluster) {
|
||||
|
||||
|
||||
return Collections.singletonList(new RestDeprecationInfoAction(settings, restController));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.deprecation;
|
||||
|
||||
import com.carrotsearch.hppc.cursors.ObjectCursor;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||
import org.elasticsearch.cluster.metadata.MappingMetaData;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Class containing all the cluster, node, and index deprecation checks that will be served
|
||||
* by the {@link DeprecationInfoAction}.
|
||||
*/
|
||||
public class DeprecationChecks {
|
||||
|
||||
private DeprecationChecks() {
|
||||
}
|
||||
|
||||
static List<BiFunction<List<NodeInfo>, ClusterState, DeprecationIssue>> CLUSTER_SETTINGS_CHECKS =
|
||||
Collections.unmodifiableList(Arrays.asList(
|
||||
// STUB: TODO(talevy): add checks
|
||||
));
|
||||
|
||||
static List<BiFunction<List<NodeInfo>, ClusterState, DeprecationIssue>> NODE_SETTINGS_CHECKS =
|
||||
Collections.unmodifiableList(Arrays.asList(
|
||||
// STUB: TODO(talevy): add checks
|
||||
));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static List<Function<IndexMetaData, DeprecationIssue>> INDEX_SETTINGS_CHECKS =
|
||||
Collections.unmodifiableList(Arrays.asList(
|
||||
indexMetaData -> {
|
||||
List<String> issues = new ArrayList<>();
|
||||
if (indexMetaData.getCreationVersion().onOrBefore(Version.V_5_6_0)) {
|
||||
for (ObjectCursor<MappingMetaData> mappingMetaData : indexMetaData.getMappings().values()) {
|
||||
Map<String, Object> sourceAsMap = mappingMetaData.value.sourceAsMap();
|
||||
((Map<String, Object>) sourceAsMap.getOrDefault("properties", Collections.emptyMap()))
|
||||
.forEach((key, value) -> {
|
||||
Map<String, Object> valueMap = ((Map<String, Object>) value);
|
||||
if ("boolean".equals(valueMap.get("type"))) {
|
||||
issues.add("type: " + mappingMetaData.value.type() + ", field: " + key);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return new DeprecationIssue(DeprecationIssue.Level.INFO, "Coercion of boolean fields",
|
||||
"https://www.elastic.co/guide/en/elasticsearch/reference/master/" +
|
||||
"breaking_60_mappings_changes.html#_coercion_of_boolean_fields",
|
||||
Arrays.toString(issues.toArray()));
|
||||
}
|
||||
));
|
||||
|
||||
/**
|
||||
* helper utility function to reduce repeat of running a specific {@link Set} of checks.
|
||||
*
|
||||
* @param checks The functional checks to execute using the mapper function
|
||||
* @param mapper The function that executes the lambda check with the appropriate arguments
|
||||
* @param <T> The signature of the check (BiFunction, Function, including the appropriate arguments)
|
||||
* @return The list of {@link DeprecationIssue} that were found in the cluster
|
||||
*/
|
||||
static <T> List<DeprecationIssue> filterChecks(List<T> checks, Function<T, DeprecationIssue> mapper) {
|
||||
return checks.stream().map(mapper).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,324 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.deprecation;
|
||||
|
||||
import org.elasticsearch.action.Action;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.action.ActionResponse;
|
||||
import org.elasticsearch.action.IndicesRequest;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoRequest;
|
||||
import org.elasticsearch.action.support.ActionFilters;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.action.support.master.MasterNodeReadOperationRequestBuilder;
|
||||
import org.elasticsearch.action.support.master.MasterNodeReadRequest;
|
||||
import org.elasticsearch.action.support.master.TransportMasterNodeReadAction;
|
||||
import org.elasticsearch.client.ElasticsearchClient;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.cluster.block.ClusterBlockException;
|
||||
import org.elasticsearch.cluster.block.ClusterBlockLevel;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.cluster.service.ClusterService;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.index.IndexNotFoundException;
|
||||
import org.elasticsearch.license.LicenseUtils;
|
||||
import org.elasticsearch.license.XPackLicenseState;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
import org.elasticsearch.xpack.deprecation.DeprecationIssue.Level;
|
||||
import org.elasticsearch.xpack.security.InternalClient;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||
import static org.elasticsearch.xpack.deprecation.DeprecationChecks.CLUSTER_SETTINGS_CHECKS;
|
||||
import static org.elasticsearch.xpack.deprecation.DeprecationChecks.INDEX_SETTINGS_CHECKS;
|
||||
import static org.elasticsearch.xpack.deprecation.DeprecationChecks.NODE_SETTINGS_CHECKS;
|
||||
import static org.elasticsearch.xpack.deprecation.DeprecationChecks.filterChecks;
|
||||
|
||||
public class DeprecationInfoAction extends Action<DeprecationInfoAction.Request,
|
||||
DeprecationInfoAction.Response, DeprecationInfoAction.RequestBuilder> {
|
||||
|
||||
public static final DeprecationInfoAction INSTANCE = new DeprecationInfoAction();
|
||||
public static final String NAME = "cluster:admin/xpack/deprecation/info";
|
||||
|
||||
private DeprecationInfoAction() {
|
||||
super(NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||
return new RequestBuilder(client, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response newResponse() {
|
||||
return new Response();
|
||||
}
|
||||
|
||||
public static class Response extends ActionResponse implements ToXContentObject {
|
||||
private List<DeprecationIssue> clusterSettingsIssues;
|
||||
private List<DeprecationIssue> nodeSettingsIssues;
|
||||
private Map<String, List<DeprecationIssue>> indexSettingsIssues;
|
||||
|
||||
Response() {
|
||||
}
|
||||
|
||||
public Response(List<DeprecationIssue> clusterSettingsIssues,
|
||||
List<DeprecationIssue> nodeSettingsIssues,
|
||||
Map<String, List<DeprecationIssue>> indexSettingsIssues) {
|
||||
this.clusterSettingsIssues = clusterSettingsIssues;
|
||||
this.nodeSettingsIssues = nodeSettingsIssues;
|
||||
this.indexSettingsIssues = indexSettingsIssues;
|
||||
}
|
||||
|
||||
public List<DeprecationIssue> getClusterSettingsIssues() {
|
||||
return clusterSettingsIssues;
|
||||
}
|
||||
|
||||
public List<DeprecationIssue> getNodeSettingsIssues() {
|
||||
return nodeSettingsIssues;
|
||||
}
|
||||
|
||||
public Map<String, List<DeprecationIssue>> getIndexSettingsIssues() {
|
||||
return indexSettingsIssues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
super.readFrom(in);
|
||||
clusterSettingsIssues = in.readList(DeprecationIssue::new);
|
||||
nodeSettingsIssues = in.readList(DeprecationIssue::new);
|
||||
indexSettingsIssues = in.readMapOfLists(StreamInput::readString, DeprecationIssue::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
super.writeTo(out);
|
||||
out.writeList(clusterSettingsIssues);
|
||||
out.writeList(nodeSettingsIssues);
|
||||
out.writeMapOfLists(indexSettingsIssues, StreamOutput::writeString, (o, v) -> v.writeTo(o));
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
return builder.startObject()
|
||||
.array("cluster_settings", clusterSettingsIssues.toArray())
|
||||
.array("node_settings", nodeSettingsIssues.toArray())
|
||||
.field("index_settings")
|
||||
.map(indexSettingsIssues)
|
||||
.endObject();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Response response = (Response) o;
|
||||
return Objects.equals(clusterSettingsIssues, response.clusterSettingsIssues) &&
|
||||
Objects.equals(nodeSettingsIssues, response.nodeSettingsIssues) &&
|
||||
Objects.equals(indexSettingsIssues, response.indexSettingsIssues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(clusterSettingsIssues, nodeSettingsIssues, indexSettingsIssues);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the function that does the bulk of the logic of taking the appropriate ES dependencies
|
||||
* like {@link NodeInfo}, {@link ClusterState}. Alongside these objects and the list of deprecation checks,
|
||||
* this function will run through all the checks and build out the final list of issues that exist in the
|
||||
* cluster.
|
||||
*
|
||||
* @param nodesInfo The list of {@link NodeInfo} metadata objects for retrieving node-level information
|
||||
* @param state The cluster state
|
||||
* @param indexNameExpressionResolver Used to resolve indices into their concrete names
|
||||
* @param indices The list of index expressions to evaluate using `indexNameExpressionResolver`
|
||||
* @param indicesOptions The options to use when resolving and filtering which indices to check
|
||||
* @param clusterSettingsChecks The list of cluster-level checks
|
||||
* @param nodeSettingsChecks The list of node-level checks
|
||||
* @param indexSettingsChecks The list of index-level checks that will be run across all specified
|
||||
* concrete indices
|
||||
* @return The list of deprecation issues found in the cluster
|
||||
*/
|
||||
static DeprecationInfoAction.Response from(List<NodeInfo> nodesInfo, ClusterState state,
|
||||
IndexNameExpressionResolver indexNameExpressionResolver,
|
||||
String[] indices, IndicesOptions indicesOptions,
|
||||
List<BiFunction<List<NodeInfo>, ClusterState,DeprecationIssue>>clusterSettingsChecks,
|
||||
List<BiFunction<List<NodeInfo>, ClusterState, DeprecationIssue>> nodeSettingsChecks,
|
||||
List<Function<IndexMetaData, DeprecationIssue>> indexSettingsChecks) {
|
||||
List<DeprecationIssue> clusterSettingsIssues = filterChecks(clusterSettingsChecks,
|
||||
(c) -> c.apply(nodesInfo, state));
|
||||
List<DeprecationIssue> nodeSettingsIssues = filterChecks(nodeSettingsChecks,
|
||||
(c) -> c.apply(nodesInfo, state));
|
||||
|
||||
String[] concreteIndexNames = indexNameExpressionResolver.concreteIndexNames(state, indicesOptions, indices);
|
||||
|
||||
Map<String, List<DeprecationIssue>> indexSettingsIssues = new HashMap<>();
|
||||
for (String concreteIndex : concreteIndexNames) {
|
||||
IndexMetaData indexMetaData = state.getMetaData().index(concreteIndex);
|
||||
List<DeprecationIssue> singleIndexIssues = filterChecks(indexSettingsChecks,
|
||||
c -> c.apply(indexMetaData));
|
||||
if (singleIndexIssues.size() > 0) {
|
||||
indexSettingsIssues.put(concreteIndex, singleIndexIssues);
|
||||
}
|
||||
}
|
||||
|
||||
return new DeprecationInfoAction.Response(clusterSettingsIssues, nodeSettingsIssues, indexSettingsIssues);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Request extends MasterNodeReadRequest<Request> implements IndicesRequest.Replaceable {
|
||||
|
||||
private String[] indices = Strings.EMPTY_ARRAY;
|
||||
private static final IndicesOptions INDICES_OPTIONS = IndicesOptions.fromOptions(false, true,
|
||||
true, true);
|
||||
|
||||
public Request() {
|
||||
}
|
||||
|
||||
public Request(String... indices) {
|
||||
this.indices = indices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] indices() {
|
||||
return indices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request indices(String... indices) {
|
||||
this.indices = indices;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndicesOptions indicesOptions() {
|
||||
return INDICES_OPTIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionRequestValidationException validate() {
|
||||
ActionRequestValidationException validationException = null;
|
||||
if (indices == null) {
|
||||
validationException = addValidationError("index/indices is missing", validationException);
|
||||
}
|
||||
return validationException;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
super.readFrom(in);
|
||||
indices = in.readStringArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
super.writeTo(out);
|
||||
out.writeStringArray(indices);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Request request = (Request) o;
|
||||
return Arrays.equals(indices, request.indices);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(Arrays.hashCode(indices));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class RequestBuilder extends MasterNodeReadOperationRequestBuilder<Request, Response, RequestBuilder> {
|
||||
|
||||
protected RequestBuilder(ElasticsearchClient client, DeprecationInfoAction action) {
|
||||
super(client, action, new Request());
|
||||
}
|
||||
|
||||
public RequestBuilder setIndices(String... indices) {
|
||||
request.indices(indices);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TransportAction extends TransportMasterNodeReadAction<Request, Response> {
|
||||
|
||||
private final XPackLicenseState licenseState;
|
||||
private final InternalClient client;
|
||||
private final IndexNameExpressionResolver indexNameExpressionResolver;
|
||||
|
||||
@Inject
|
||||
public TransportAction(Settings settings, TransportService transportService, ClusterService clusterService,
|
||||
ThreadPool threadPool, ActionFilters actionFilters,
|
||||
IndexNameExpressionResolver indexNameExpressionResolver,
|
||||
XPackLicenseState licenseState, InternalClient client) {
|
||||
super(settings, DeprecationInfoAction.NAME, transportService, clusterService, threadPool, actionFilters,
|
||||
indexNameExpressionResolver, Request::new);
|
||||
this.licenseState = licenseState;
|
||||
this.client = client;
|
||||
this.indexNameExpressionResolver = indexNameExpressionResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String executor() {
|
||||
return ThreadPool.Names.GENERIC;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Response newResponse() {
|
||||
return new Response();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClusterBlockException checkBlock(Request request, ClusterState state) {
|
||||
// Cluster is not affected but we look up repositories in metadata
|
||||
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void masterOperation(final Request request, ClusterState state, final ActionListener<Response> listener) {
|
||||
if (licenseState.isDeprecationAllowed()) {
|
||||
NodesInfoRequest nodesInfoRequest = new NodesInfoRequest("_local").settings(true).plugins(true);
|
||||
client.admin().cluster().nodesInfo(nodesInfoRequest, ActionListener.wrap(nodesInfoResponse -> {
|
||||
// if there's a failure, then we failed to work with the
|
||||
// _local node (guaranteed a single exception)
|
||||
if (nodesInfoResponse.hasFailures()) {
|
||||
throw nodesInfoResponse.failures().get(0);
|
||||
}
|
||||
|
||||
listener.onResponse(Response.from(nodesInfoResponse.getNodes(), state,
|
||||
indexNameExpressionResolver, request.indices(), request.indicesOptions(),
|
||||
CLUSTER_SETTINGS_CHECKS, NODE_SETTINGS_CHECKS, INDEX_SETTINGS_CHECKS));
|
||||
}, listener::onFailure));
|
||||
} else {
|
||||
listener.onFailure(LicenseUtils.newComplianceException(XPackPlugin.DEPRECATION));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.deprecation;
|
||||
|
||||
|
||||
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.Writeable;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Information about deprecated items
|
||||
*/
|
||||
public class DeprecationIssue implements Writeable, ToXContent {
|
||||
|
||||
public enum Level implements Writeable {
|
||||
NONE,
|
||||
INFO,
|
||||
WARNING,
|
||||
CRITICAL
|
||||
;
|
||||
|
||||
public static Level fromString(String value) {
|
||||
return Level.valueOf(value.toUpperCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
public static Level readFromStream(StreamInput in) throws IOException {
|
||||
int ordinal = in.readVInt();
|
||||
if (ordinal < 0 || ordinal >= values().length) {
|
||||
throw new IOException("Unknown Level ordinal [" + ordinal + "]");
|
||||
}
|
||||
return values()[ordinal];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeVInt(ordinal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
private Level level;
|
||||
private String message;
|
||||
private String url;
|
||||
private String details;
|
||||
|
||||
// pkg-private for tests
|
||||
DeprecationIssue() {
|
||||
|
||||
}
|
||||
|
||||
public DeprecationIssue(Level level, String message, String url, @Nullable String details) {
|
||||
this.level = level;
|
||||
this.message = message;
|
||||
this.url = url;
|
||||
this.details = details;
|
||||
}
|
||||
|
||||
public DeprecationIssue(StreamInput in) throws IOException {
|
||||
level = Level.readFromStream(in);
|
||||
message = in.readString();
|
||||
url = in.readString();
|
||||
details = in.readOptionalString();
|
||||
}
|
||||
|
||||
|
||||
public Level getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public String getDetails() {
|
||||
return details;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
level.writeTo(out);
|
||||
out.writeString(message);
|
||||
out.writeString(url);
|
||||
out.writeOptionalString(details);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject()
|
||||
.field("level", level)
|
||||
.field("message", message)
|
||||
.field("url", url);
|
||||
if (details != null) {
|
||||
builder.field("details", details);
|
||||
}
|
||||
return builder.endObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
DeprecationIssue that = (DeprecationIssue) o;
|
||||
return Objects.equals(level, that.level) &&
|
||||
Objects.equals(message, that.message) &&
|
||||
Objects.equals(url, that.url) &&
|
||||
Objects.equals(details, that.details);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(level, message, url, details);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.deprecation;
|
||||
|
||||
import org.elasticsearch.client.node.NodeClient;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.rest.BaseRestHandler;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.RestToXContentListener;
|
||||
import org.elasticsearch.xpack.deprecation.DeprecationInfoAction.Request;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class RestDeprecationInfoAction extends BaseRestHandler {
|
||||
public RestDeprecationInfoAction(Settings settings, RestController controller) {
|
||||
super(settings);
|
||||
controller.registerHandler(RestRequest.Method.GET, "/_xpack/migration/deprecations", this);
|
||||
controller.registerHandler(RestRequest.Method.GET, "/{index}/_xpack/migration/deprecations", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "deprecation_info_action";
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
|
||||
if (request.method().equals(RestRequest.Method.GET)) {
|
||||
return handleGet(request, client);
|
||||
} else {
|
||||
throw new IllegalArgumentException("illegal method [" + request.method() + "] for request [" + request.path() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
private RestChannelConsumer handleGet(final RestRequest request, NodeClient client) {
|
||||
Request infoRequest = new Request(Strings.splitStringByCommaToArray(request.param("index")));
|
||||
return channel -> client.execute(DeprecationInfoAction.INSTANCE, infoRequest, new RestToXContentListener<>(channel));
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
|
|||
import org.elasticsearch.test.SecurityIntegTestCase;
|
||||
import org.elasticsearch.test.discovery.TestZenDiscovery;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
import org.elasticsearch.xpack.deprecation.Deprecation;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -137,6 +138,9 @@ public class KnownActionsTests extends SecurityIntegTestCase {
|
|||
// also load stuff from Reindex in org.elasticsearch.index.reindex package
|
||||
loadActions(collectSubClasses(Action.class, ReindexPlugin.class), actions);
|
||||
|
||||
// also load stuff from Deprecation in org.elasticsearch.deprecation
|
||||
loadActions(collectSubClasses(Action.class, Deprecation.class), actions);
|
||||
|
||||
return unmodifiableSet(actions);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.deprecation;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.elasticsearch.xpack.deprecation.DeprecationChecks.INDEX_SETTINGS_CHECKS;
|
||||
import static org.hamcrest.core.IsEqual.equalTo;
|
||||
|
||||
public class DeprecationChecksTests extends ESTestCase {
|
||||
|
||||
public void testFilterChecks() throws IOException {
|
||||
DeprecationIssue issue = DeprecationIssueTests.createTestInstance();
|
||||
int numChecksPassed = randomIntBetween(0, 5);
|
||||
int numChecksFailed = 10 - numChecksPassed;
|
||||
List<Supplier<DeprecationIssue>> checks = new ArrayList<>();
|
||||
for (int i = 0; i < numChecksFailed; i++) {
|
||||
checks.add(() -> issue);
|
||||
}
|
||||
for (int i = 0; i < numChecksPassed; i++) {
|
||||
checks.add(() -> null);
|
||||
}
|
||||
List<DeprecationIssue> filteredIssues = DeprecationChecks.filterChecks(checks, Supplier::get);
|
||||
assertThat(filteredIssues.size(), equalTo(numChecksFailed));
|
||||
}
|
||||
|
||||
public void testCoerceBooleanDeprecation() throws IOException {
|
||||
XContentBuilder mapping = XContentFactory.jsonBuilder();
|
||||
mapping.startObject(); {
|
||||
mapping.startObject("properties"); {
|
||||
mapping.startObject("my_boolean"); {
|
||||
mapping.field("type", "boolean");
|
||||
}
|
||||
mapping.endObject();
|
||||
}
|
||||
mapping.endObject();
|
||||
}
|
||||
mapping.endObject();
|
||||
|
||||
IndexMetaData indexMetaData = IndexMetaData.builder("test")
|
||||
.putMapping("testBooleanCoercion", mapping.string())
|
||||
.settings(settings(Version.V_5_6_0))
|
||||
.numberOfShards(1)
|
||||
.numberOfReplicas(0)
|
||||
.build();
|
||||
DeprecationIssue expected = new DeprecationIssue(DeprecationIssue.Level.INFO,
|
||||
"Coercion of boolean fields",
|
||||
"https://www.elastic.co/guide/en/elasticsearch/reference/master/" +
|
||||
"breaking_60_mappings_changes.html#_coercion_of_boolean_fields",
|
||||
Arrays.toString(new String[] { "type: testBooleanCoercion, field: my_boolean" }));
|
||||
List<DeprecationIssue> issues = DeprecationChecks.filterChecks(INDEX_SETTINGS_CHECKS, c -> c.apply(indexMetaData));
|
||||
assertThat(issues.size(), equalTo(1));
|
||||
assertThat(issues.get(0), equalTo(expected));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.deprecation;
|
||||
|
||||
import org.elasticsearch.test.AbstractStreamableTestCase;
|
||||
|
||||
public class DeprecationInfoActionRequestTests extends AbstractStreamableTestCase<DeprecationInfoAction.Request> {
|
||||
|
||||
@Override
|
||||
protected DeprecationInfoAction.Request createTestInstance() {
|
||||
return new DeprecationInfoAction.Request(randomAlphaOfLength(10));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DeprecationInfoAction.Request createBlankInstance() {
|
||||
return new DeprecationInfoAction.Request();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.deprecation;
|
||||
|
||||
import org.elasticsearch.Build;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.cluster.ClusterName;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.cluster.metadata.MetaData;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.test.AbstractStreamableTestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.core.IsEqual.equalTo;
|
||||
|
||||
public class DeprecationInfoActionResponseTests extends AbstractStreamableTestCase<DeprecationInfoAction.Response> {
|
||||
|
||||
@Override
|
||||
protected DeprecationInfoAction.Response createTestInstance() {
|
||||
List<DeprecationIssue> clusterIssues = Stream.generate(DeprecationIssueTests::createTestInstance)
|
||||
.limit(randomIntBetween(0, 10)).collect(Collectors.toList());
|
||||
List<DeprecationIssue> nodeIssues = Stream.generate(DeprecationIssueTests::createTestInstance)
|
||||
.limit(randomIntBetween(0, 10)).collect(Collectors.toList());
|
||||
Map<String, List<DeprecationIssue>> indexIssues = new HashMap<>();
|
||||
for (int i = 0; i < randomIntBetween(0, 10); i++) {
|
||||
List<DeprecationIssue> perIndexIssues = Stream.generate(DeprecationIssueTests::createTestInstance)
|
||||
.limit(randomIntBetween(0, 10)).collect(Collectors.toList());
|
||||
indexIssues.put(randomAlphaOfLength(10), perIndexIssues);
|
||||
}
|
||||
return new DeprecationInfoAction.Response(clusterIssues, nodeIssues, indexIssues);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DeprecationInfoAction.Response createBlankInstance() {
|
||||
return new DeprecationInfoAction.Response();
|
||||
}
|
||||
|
||||
public void testFrom() throws IOException {
|
||||
XContentBuilder mapping = XContentFactory.jsonBuilder().startObject().startObject("_all");
|
||||
mapping.field("enabled", false);
|
||||
mapping.endObject().endObject();
|
||||
|
||||
MetaData metadata = MetaData.builder().put(IndexMetaData.builder("test")
|
||||
.putMapping("testUnderscoreAll", mapping.string())
|
||||
.settings(settings(Version.CURRENT))
|
||||
.numberOfShards(1)
|
||||
.numberOfReplicas(0))
|
||||
.build();
|
||||
|
||||
DiscoveryNode discoveryNode = DiscoveryNode.createLocal(Settings.EMPTY,
|
||||
new TransportAddress(TransportAddress.META_ADDRESS, 9300), "test");
|
||||
ClusterState state = ClusterState.builder(ClusterName.DEFAULT).metaData(metadata).build();
|
||||
List<NodeInfo> nodeInfos = Collections.singletonList(new NodeInfo(Version.CURRENT, Build.CURRENT,
|
||||
discoveryNode, null, null, null, null,
|
||||
null, null, null, null, null, null));
|
||||
IndexNameExpressionResolver resolver = new IndexNameExpressionResolver(Settings.EMPTY);
|
||||
IndicesOptions indicesOptions = IndicesOptions.fromOptions(false, false,
|
||||
true, true);
|
||||
boolean clusterIssueFound = randomBoolean();
|
||||
boolean nodeIssueFound = randomBoolean();
|
||||
boolean indexIssueFound = randomBoolean();
|
||||
DeprecationIssue foundIssue = DeprecationIssueTests.createTestInstance();
|
||||
List<BiFunction<List<NodeInfo>, ClusterState, DeprecationIssue>> clusterSettingsChecks =
|
||||
Collections.unmodifiableList(Arrays.asList(
|
||||
(ln, s) -> clusterIssueFound ? foundIssue : null
|
||||
));
|
||||
List<BiFunction<List<NodeInfo>, ClusterState, DeprecationIssue>> nodeSettingsChecks =
|
||||
Collections.unmodifiableList(Arrays.asList(
|
||||
(ln, s) -> nodeIssueFound ? foundIssue : null
|
||||
));
|
||||
|
||||
List<Function<IndexMetaData, DeprecationIssue>> indexSettingsChecks =
|
||||
Collections.unmodifiableList(Arrays.asList(
|
||||
(idx) -> indexIssueFound ? foundIssue : null
|
||||
));
|
||||
|
||||
DeprecationInfoAction.Response response = DeprecationInfoAction.Response.from(nodeInfos, state,
|
||||
resolver, Strings.EMPTY_ARRAY, indicesOptions,
|
||||
clusterSettingsChecks, nodeSettingsChecks, indexSettingsChecks);
|
||||
|
||||
if (clusterIssueFound) {
|
||||
assertThat(response.getClusterSettingsIssues(), equalTo(Collections.singletonList(foundIssue)));
|
||||
} else {
|
||||
assertThat(response.getClusterSettingsIssues(), empty());
|
||||
}
|
||||
|
||||
if (nodeIssueFound) {
|
||||
assertThat(response.getNodeSettingsIssues(), equalTo(Collections.singletonList(foundIssue)));
|
||||
} else {
|
||||
assertTrue(response.getNodeSettingsIssues().isEmpty());
|
||||
}
|
||||
|
||||
if (indexIssueFound) {
|
||||
assertThat(response.getIndexSettingsIssues(), equalTo(Collections.singletonMap("test",
|
||||
Collections.singletonList(foundIssue))));
|
||||
} else {
|
||||
assertTrue(response.getIndexSettingsIssues().isEmpty());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.deprecation;
|
||||
|
||||
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.test.ESTestCase;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.ToXContent.EMPTY_PARAMS;
|
||||
import static org.elasticsearch.xpack.deprecation.DeprecationIssue.Level;
|
||||
import static org.hamcrest.core.IsEqual.equalTo;
|
||||
|
||||
public class DeprecationIssueTests extends ESTestCase {
|
||||
DeprecationIssue issue;
|
||||
|
||||
static DeprecationIssue createTestInstance() {
|
||||
String details = randomBoolean() ? randomAlphaOfLength(10) : null;
|
||||
return new DeprecationIssue(randomFrom(Level.values()), randomAlphaOfLength(10),
|
||||
randomAlphaOfLength(10), details);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
issue = createTestInstance();
|
||||
}
|
||||
|
||||
public void testEqualsAndHashCode() {
|
||||
DeprecationIssue other = new DeprecationIssue(issue.getLevel(), issue.getMessage(), issue.getUrl(), issue.getDetails());
|
||||
assertThat(issue, equalTo(other));
|
||||
assertThat(other, equalTo(issue));
|
||||
assertThat(issue.hashCode(), equalTo(other.hashCode()));
|
||||
}
|
||||
|
||||
public void testSerialization() throws IOException {
|
||||
BytesStreamOutput out = new BytesStreamOutput();
|
||||
issue.writeTo(out);
|
||||
StreamInput in = out.bytes().streamInput();
|
||||
DeprecationIssue other = new DeprecationIssue(in);
|
||||
assertThat(issue, equalTo(other));
|
||||
}
|
||||
|
||||
public void testToXContent() throws IOException {
|
||||
XContentBuilder builder = XContentFactory.jsonBuilder();
|
||||
issue.toXContent(builder, EMPTY_PARAMS);
|
||||
Map<String, Object> toXContentMap = XContentHelper.convertToMap(builder.bytes(), false, builder.contentType()).v2();
|
||||
String level = (String) toXContentMap.get("level");
|
||||
String message = (String) toXContentMap.get("message");
|
||||
String url = (String) toXContentMap.get("url");
|
||||
if (issue.getDetails() != null) {
|
||||
assertTrue(toXContentMap.containsKey("details"));
|
||||
}
|
||||
String details = (String) toXContentMap.get("details");
|
||||
DeprecationIssue other = new DeprecationIssue(Level.fromString(level), message, url, details);
|
||||
assertThat(issue, equalTo(other));
|
||||
}
|
||||
}
|
|
@ -155,3 +155,4 @@ cluster:admin/reindex/rethrottle
|
|||
indices:data/write/update/byquery
|
||||
indices:data/write/delete/byquery
|
||||
indices:data/write/reindex
|
||||
cluster:admin/xpack/deprecation/info
|
||||
|
|
|
@ -133,3 +133,4 @@ cluster:admin/reindex/rethrottle[n]
|
|||
indices:data/write/update/byquery
|
||||
indices:data/write/delete/byquery
|
||||
indices:data/write/reindex
|
||||
cluster:admin/xpack/deprecation/info
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"xpack.deprecation.info": {
|
||||
"documentation": "http://www.elastic.co/guide/en/migration/current/appendix-api-deprecation-info.html",
|
||||
"methods": [ "GET" ],
|
||||
"url": {
|
||||
"path": "/{index}/_xpack/migration/deprecations",
|
||||
"paths": ["/_xpack/migration/deprecations", "/{index}/_xpack/migration/deprecations"],
|
||||
"parts": {
|
||||
"index": {
|
||||
"type" : "string",
|
||||
"description" : "Index pattern"
|
||||
}
|
||||
},
|
||||
"params": {
|
||||
}
|
||||
},
|
||||
"body": null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
setup:
|
||||
- do:
|
||||
cluster.health:
|
||||
wait_for_status: yellow
|
||||
|
||||
---
|
||||
"Test Deprecations":
|
||||
- do:
|
||||
xpack.deprecation.info:
|
||||
index: "*"
|
||||
- length: { cluster_settings: 0 }
|
||||
- length: { node_settings: 0 }
|
||||
- length: { index_settings: 0 }
|
||||
|
Loading…
Reference in New Issue