Skip to content

Commit

Permalink
HLRC: Get Deprecation Info API (#36279)
Browse files Browse the repository at this point in the history
This commit adds the Get Deprecation Info API and associated
documentation.

Relates #29827
  • Loading branch information
hub-cap authored Dec 7, 2018
1 parent c32e4fb commit ca09936
Show file tree
Hide file tree
Showing 10 changed files with 547 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

package org.elasticsearch.client;

import org.elasticsearch.client.migration.DeprecationInfoRequest;
import org.elasticsearch.client.migration.DeprecationInfoResponse;
import org.elasticsearch.client.migration.IndexUpgradeInfoRequest;
import org.elasticsearch.client.migration.IndexUpgradeInfoResponse;
import org.elasticsearch.action.ActionListener;
Expand Down Expand Up @@ -72,4 +74,28 @@ public void upgradeAsync(IndexUpgradeRequest request, RequestOptions options, Ac
restHighLevelClient.performRequestAsyncAndParseEntity(request, MigrationRequestConverters::migrate, options,
BulkByScrollResponse::fromXContent, listener, Collections.emptySet());
}

/**
* Get deprecation info for one or more indices
* @param request the request
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @return the response
* @throws IOException in case there is a problem sending the request or parsing back the response
*/
public DeprecationInfoResponse getDeprecationInfo(DeprecationInfoRequest request, RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(request, MigrationRequestConverters::getDeprecationInfo, options,
DeprecationInfoResponse::fromXContent, Collections.emptySet());
}

/**
* Asynchronously get deprecation info for one or more indices
* @param request the request
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @param listener the listener to be notified upon request completion
*/
public void getDeprecationInfoAsync(DeprecationInfoRequest request, RequestOptions options,
ActionListener<DeprecationInfoResponse> listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(request, MigrationRequestConverters::getDeprecationInfo, options,
DeprecationInfoResponse::fromXContent, listener, Collections.emptySet());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.elasticsearch.client.migration.DeprecationInfoRequest;
import org.elasticsearch.client.migration.IndexUpgradeInfoRequest;
import org.elasticsearch.client.migration.IndexUpgradeRequest;

Expand Down Expand Up @@ -48,6 +49,15 @@ static Request submitMigrateTask(IndexUpgradeRequest indexUpgradeRequest) {
return prepareMigrateRequest(indexUpgradeRequest, false);
}

static Request getDeprecationInfo(DeprecationInfoRequest deprecationInfoRequest) {
String endpoint = new RequestConverters.EndpointBuilder()
.addCommaSeparatedPathParts(deprecationInfoRequest.getIndices())
.addPathPartAsIs("_migration", "deprecations")
.build();

return new Request(HttpGet.METHOD_NAME, endpoint);
}

private static Request prepareMigrateRequest(IndexUpgradeRequest indexUpgradeRequest, boolean waitForCompletion) {
String endpoint = new RequestConverters.EndpointBuilder()
.addPathPartAsIs("_migration", "upgrade")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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.client.migration;

import org.elasticsearch.client.Validatable;

import java.util.Collections;
import java.util.List;
import java.util.Objects;

public class DeprecationInfoRequest implements Validatable {

private final List<String> indices;

public DeprecationInfoRequest(List<String> indices) {
this.indices = Collections.unmodifiableList(Objects.requireNonNull(indices, "indices cannot be null"));
}

public DeprecationInfoRequest() {
this.indices = Collections.unmodifiableList(Collections.emptyList());
}

public List<String> getIndices() {
return indices;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
/*
* 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.client.migration;

import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.XContentParser;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;

public class DeprecationInfoResponse {

private static final ParseField CLUSTER_SETTINGS = new ParseField("cluster_settings");
private static final ParseField NODE_SETTINGS = new ParseField("node_settings");
private static final ParseField INDEX_SETTINGS = new ParseField("index_settings");

private final List<DeprecationIssue> clusterSettingsIssues;
private final List<DeprecationIssue> nodeSettingsIssues;
private final Map<String, List<DeprecationIssue>> indexSettingsIssues;

public DeprecationInfoResponse(List<DeprecationIssue> clusterSettingsIssues, List<DeprecationIssue> nodeSettingsIssues,
Map<String, List<DeprecationIssue>> indexSettingsIssues) {
this.clusterSettingsIssues = Objects.requireNonNull(clusterSettingsIssues, "cluster settings issues cannot be null");
this.nodeSettingsIssues = Objects.requireNonNull(nodeSettingsIssues, "node settings issues cannot be null");
this.indexSettingsIssues = Objects.requireNonNull(indexSettingsIssues, "index settings issues cannot be null");
}

public List<DeprecationIssue> getClusterSettingsIssues() {
return clusterSettingsIssues;
}

public List<DeprecationIssue> getNodeSettingsIssues() {
return nodeSettingsIssues;
}

public Map<String, List<DeprecationIssue>> getIndexSettingsIssues() {
return indexSettingsIssues;
}

private static List<DeprecationIssue> parseDeprecationIssues(XContentParser parser) throws IOException {
List<DeprecationIssue> issues = new ArrayList<>();
XContentParser.Token token = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
if (token == XContentParser.Token.START_OBJECT) {
issues.add(DeprecationIssue.PARSER.parse(parser, null));
}
}
return issues;
}

public static DeprecationInfoResponse fromXContent(XContentParser parser) throws IOException {
Map<String, List<DeprecationIssue>> indexSettings = new HashMap<>();
List<DeprecationIssue> clusterSettings = new ArrayList<>();
List<DeprecationIssue> nodeSettings = new ArrayList<>();
String fieldName = null;
XContentParser.Token token;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
fieldName = parser.currentName();
} else if (CLUSTER_SETTINGS.getPreferredName().equals(fieldName)) {
clusterSettings.addAll(parseDeprecationIssues(parser));
} else if (NODE_SETTINGS.getPreferredName().equals(fieldName)) {
nodeSettings.addAll(parseDeprecationIssues(parser));
} else if (INDEX_SETTINGS.getPreferredName().equals(fieldName)) {
// parse out the key/value pairs
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
String key = parser.currentName();
List<DeprecationIssue> value = parseDeprecationIssues(parser);
if (value.size() > 0) { // only add indices that contain deprecation issues
indexSettings.put(key, value);
}
}
}
}
return new DeprecationInfoResponse(clusterSettings, nodeSettings, indexSettings);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DeprecationInfoResponse that = (DeprecationInfoResponse) o;
return Objects.equals(clusterSettingsIssues, that.clusterSettingsIssues) &&
Objects.equals(nodeSettingsIssues, that.nodeSettingsIssues) &&
Objects.equals(indexSettingsIssues, that.indexSettingsIssues);
}

@Override
public int hashCode() {
return Objects.hash(clusterSettingsIssues, nodeSettingsIssues, indexSettingsIssues);
}

@Override
public String toString() {
return clusterSettingsIssues.toString() + ":" + nodeSettingsIssues.toString() + ":" + indexSettingsIssues.toString();
}

/**
* Information about deprecated items
*/
public static class DeprecationIssue {

private static final ParseField LEVEL = new ParseField("level");
private static final ParseField MESSAGE = new ParseField("message");
private static final ParseField URL = new ParseField("url");
private static final ParseField DETAILS = new ParseField("details");

static final ConstructingObjectParser<DeprecationIssue, Void> PARSER =
new ConstructingObjectParser<>("deprecation_issue", true,
a -> new DeprecationIssue(Level.fromString((String) a[0]), (String) a[1], (String) a[2], (String) a[3]));

static {
PARSER.declareString(ConstructingObjectParser.constructorArg(), LEVEL);
PARSER.declareString(ConstructingObjectParser.constructorArg(), MESSAGE);
PARSER.declareString(ConstructingObjectParser.constructorArg(), URL);
PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), DETAILS);
}

public enum Level {
NONE,
INFO,
WARNING,
CRITICAL
;

public static Level fromString(String value) {
return Level.valueOf(value.toUpperCase(Locale.ROOT));
}

@Override
public String toString() {
return name().toLowerCase(Locale.ROOT);
}
}

private Level level;
private String message;
private String url;
private String details;

public DeprecationIssue(Level level, String message, String url, @Nullable String details) {
this.level = level;
this.message = message;
this.url = url;
this.details = details;
}

public Level getLevel() {
return level;
}

public String getMessage() {
return message;
}

public String getUrl() {
return url;
}

public String getDetails() {
return details;
}

@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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,20 @@
package org.elasticsearch.client;

import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.client.migration.DeprecationInfoRequest;
import org.elasticsearch.client.migration.DeprecationInfoResponse;
import org.elasticsearch.client.migration.IndexUpgradeInfoRequest;
import org.elasticsearch.client.migration.IndexUpgradeInfoResponse;
import org.elasticsearch.client.migration.IndexUpgradeRequest;
import org.elasticsearch.client.tasks.TaskSubmissionResponse;
import org.elasticsearch.common.settings.Settings;

import java.io.IOException;
import java.util.Collections;
import java.util.function.BooleanSupplier;

import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;

public class MigrationIT extends ESRestHighLevelClientTestCase {

Expand Down Expand Up @@ -73,6 +77,16 @@ public void testUpgradeWithTaskApi() throws IOException, InterruptedException {
awaitBusy(hasUpgradeCompleted);
}

public void testGetDeprecationInfo() throws IOException {
createIndex("test", Settings.EMPTY);
DeprecationInfoRequest request = new DeprecationInfoRequest(Collections.singletonList("test"));
DeprecationInfoResponse response = highLevelClient().migration().getDeprecationInfo(request, RequestOptions.DEFAULT);
// a test like this cannot test actual deprecations
assertThat(response.getClusterSettingsIssues().size(), equalTo(0));
assertThat(response.getIndexSettingsIssues().size(), equalTo(0));
assertThat(response.getNodeSettingsIssues().size(), equalTo(0));
}

/**
* Using low-level api as high-level-rest-client's getTaskById work is in progress.
* TODO revisit once that work is finished
Expand Down
Loading

0 comments on commit ca09936

Please sign in to comment.