Add granular error list to alias action response (#106514)

When an alias action list is posted with must_exist==false, and succeeds only partially, a list of results for each action are now returned. The results contain information about the requested action, indices, and aliases. If must_exist==true, or all actions fail, the call will return a 400 status along with the associated exception.
This commit is contained in:
Parker Timmins 2024-04-09 11:11:49 -06:00 committed by GitHub
parent 24aed5c7fe
commit 75228dfd45
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 766 additions and 58 deletions

View file

@ -0,0 +1,6 @@
pr: 106514
summary: Add granular error list to alias action response
area: Indices APIs
type: feature
issues:
- 94478

View file

@ -121,6 +121,77 @@ POST _aliases
// TEST[s/^/PUT _data_stream\/logs-nginx.access-prod\nPUT _data_stream\/logs-my_app-default\n/]
// end::alias-multiple-actions-example[]
[discrete]
[[multiple-action-results]]
=== Multiple action results
When using multiple actions, if some succeed and some fail, a list of per-action results will be returned.
Consider a similar action list to the previous example, but now with an alias `log-non-existing`, which does not yet exist.
In this case, the `remove` action will fail, but the `add` action will succeed.
The response will contain the list `action_results`, with a result for every requested action.
[source,console]
----
POST _aliases
{
"actions": [
{
"remove": {
"index": "index1",
"alias": "logs-non-existing"
}
},
{
"add": {
"index": "index2",
"alias": "logs-non-existing"
}
}
]
}
----
// TEST[s/^/PUT \/index1\nPUT \/index2\n/]
The API returns the following result:
[source,console-result]
--------------------------------------------------
{
"acknowledged": true,
"errors": true,
"action_results": [
{
"action": {
"type": "remove",
"indices": [ "index1" ],
"aliases": [ "logs-non-existing" ],
},
"status": 404,
"error": {
"type": "aliases_not_found_exception",
"reason": "aliases [logs-non-existing] missing",
"resource.type": "aliases",
"resource.id": "logs-non-existing"
}
},
{
"action": {
"type": "add",
"indices": [ "index2" ],
"aliases": [ "logs-non-existing" ],
},
"status": 200
}
]
}
--------------------------------------------------
Allowing the action list to succeed partially may not provide the desired result.
It may be more appropriate to set `must_exist` to `true`, which will cause the entire action
list to fail if a single action fails.
[discrete]
[[add-alias-at-creation]]
=== Add an alias at index creation

View file

@ -145,10 +145,16 @@ the alias points to one data stream.
+
Only the `add` action supports this parameter.
// tag::alias-options[]
`must_exist`::
(Optional, Boolean)
If `true`, the alias must exist to perform the action. Defaults to `false`. Only
the `remove` action supports this parameter.
Affects the behavior when attempting to remove an alias which does not exist.
If `true`, removing an alias which does not exist will cause all actions to fail.
If `false`, removing an alias which does not exist will only cause that removal to fail.
Defaults to `false`.
// end::alias-options[]
+
Only the `remove` action supports this parameter.
// tag::alias-options[]
`routing`::
@ -168,3 +174,51 @@ stream aliases don't support this parameter.
Only the `add` action supports this parameter.
=====
====
[role="child_attributes"]
[[indices-aliases-api-response-body]]
==== {api-response-body-title}
`acknowledged`::
(Boolean)
If `true`, the request received a response from the master node within the
`timeout` period.
`errors`::
(Boolean)
If `true`, at least one of the requested actions failed.
`action_results`::
(Optional, array of objects) Results for each requested action.
+
.Properties of `action_results` objects
[%collapsible%open]
====
`action`::
(object)
Description of the associated action request.
+
.Properties of `action` object
[%collapsible%open]
=====
`type`::
(string) The type of the associated action, one of `add`, `remove`, or `remove_index`.
`indices`::
(array of strings) List of indices in the associated action.
`aliases`::
(array of strings) List of aliases in the associated action.
=====
`status`::
(integer) HTTP status code returned for the action.
`error`::
(Optional, object) Contains additional information about the failed action.
+
Only present if the action failed.
====

View file

@ -307,3 +307,86 @@
indices.get_alias:
name: this-does-not-exist*
- is_false: ds-first.aliases.my-alias
---
"Action Results with multiple matching aliases":
- skip:
version: " - 8.13.99"
reason: "alias action results do not work until 8.14"
features: allowed_warnings
- do:
allowed_warnings:
- "index template [my-template] has index patterns [log-*] matching patterns from existing older templates [global] with patterns (global => [*]); this template [my-template] will take precedence during new index creation"
indices.put_index_template:
name: my-template
body:
index_patterns: [ log-* ]
template:
settings:
index.number_of_replicas: 0
data_stream: { }
- do:
indices.create_data_stream:
name: log-foobar
- is_true: acknowledged
- do:
indices.update_aliases:
body:
actions:
- add:
index: log-foobar
aliases: test_alias1
- remove:
index: log-foobar
aliases: test_non_existing
must_exist: false
- is_true: errors
- length: { action_results: 2 }
- match: { action_results.0.status: 200 }
- match: { action_results.0.action: { 'type': 'add', 'indices': ['log-foobar'], 'aliases': ['test_alias1'] } }
- match: { action_results.0.error: null }
- match: { action_results.1.status: 404 }
- match: { action_results.1.action: { 'type': 'remove', 'indices': ['log-foobar'], 'aliases': ['test_non_existing'] } }
- match: { action_results.1.error.type: aliases_not_found_exception }
---
"Single action result per action":
- skip:
version: " - 8.13.99"
reason: "alias action results do not work until 8.14"
features: allowed_warnings
- do:
allowed_warnings:
- "index template [my-template] has index patterns [log-*] matching patterns from existing older templates [global] with patterns (global => [*]); this template [my-template] will take precedence during new index creation"
indices.put_index_template:
name: my-template
body:
index_patterns: [ log-* ]
template:
settings:
index.number_of_replicas: 0
data_stream: { }
- do:
indices.create_data_stream:
name: log-test-1
- do:
indices.create_data_stream:
name: log-test-2
- is_true: acknowledged
- do:
indices.update_aliases:
body:
actions:
- add:
index: log-test-*
aliases: test_alias1
- remove:
index: log-test-*
aliases: test_non_existing
must_exist: false
- is_true: errors
- length: { action_results: 2 }
- match: { action_results.0.status: 200}
- match: { action_results.0.action: { 'type': 'add', 'indices': ['log-test-1', 'log-test-2'], 'aliases': ['test_alias1'] } }
- match: { action_results.0.error: null }
- match: { action_results.1.status: 404 }
- match: { action_results.1.action: { 'type': 'remove', 'indices': ['log-test-1', 'log-test-2'], 'aliases': ['test_non_existing'] } }
- match: { action_results.1.error.type: aliases_not_found_exception }

View file

@ -82,3 +82,100 @@
- remove_index:
index: test_index
must_exist: true
---
"Partial success with must_exist == false":
- skip:
version: " - 8.13.99"
reason: "alias action results do not work until 8.14"
- do:
indices.create:
index: test_index
- do:
indices.update_aliases:
body:
actions:
- add:
index: test_index
aliases: test_alias1
- remove:
index: test_index
aliases: test_non_existing
must_exist: false
- is_true: errors
- match: { action_results.0.status: 200 }
- match: { action_results.0.action: { 'type': 'add', 'indices': ['test_index'], 'aliases': ['test_alias1'] } }
- match: { action_results.0.error: null }
- match: { action_results.1.status: 404 }
- match: { action_results.1.action: { 'type': 'remove', 'indices': ['test_index'], 'aliases': ['test_non_existing'] } }
- match: { action_results.1.error.type: aliases_not_found_exception }
---
"Partial success with must_exist == null (default)":
- skip:
version: " - 8.13.99"
reason: "alias action results do not work until 8.14"
- do:
indices.create:
index: test_index
- do:
indices.update_aliases:
body:
actions:
- add:
index: test_index
aliases: test_alias1
- remove:
index: test_index
aliases: test_non_existing
- is_true: errors
- match: { action_results.0.status: 200}
- match: { action_results.0.action: { 'type': 'add', 'indices': ['test_index'], 'aliases': ['test_alias1'] } }
- match: { action_results.0.error: null }
- match: { action_results.1.status: 404}
- match: { action_results.1.action: { 'type': 'remove', 'indices': ['test_index'], 'aliases': ['test_non_existing'] } }
- match: { action_results.1.error.type: aliases_not_found_exception }
---
"No action_results field if all actions successful":
- skip:
version: " - 8.13.99"
reason: "alias action results do not work until 8.14"
- do:
indices.create:
index: test_index
- do:
indices.update_aliases:
body:
actions:
- add:
index: test_index
aliases: test_alias1
- is_false: errors
- match: { action_results: null }
---
"Single result per input action":
- skip:
version: " - 8.13.99"
reason: "alias action results do not work until 8.14"
- do:
indices.create:
index: test_index1
- do:
indices.create:
index: test_index2
- do:
indices.update_aliases:
body:
actions:
- add:
index: test_index*
aliases: test_alias1
- remove:
index: test_index*
aliases: test_non_existing
- length: { action_results: 2 }
- is_true: errors
- match: { action_results.0.status: 200}
- match: { action_results.0.action: { 'type': 'add', 'indices': ['test_index1', 'test_index2'], 'aliases': ['test_alias1'] } }
- match: { action_results.0.error: null }
- match: { action_results.1.status: 404}
- match: { action_results.1.action: { 'type': 'remove', 'indices': ['test_index1', 'test_index2'], 'aliases': ['test_non_existing'] } }
- match: { action_results.1.error.type: aliases_not_found_exception }

View file

@ -164,6 +164,7 @@ public class TransportVersions {
public static final TransportVersion ESQL_ORDINAL_BLOCK = def(8_623_00_0);
public static final TransportVersion ML_INFERENCE_COHERE_RERANK = def(8_624_00_0);
public static final TransportVersion INDEXING_PRESSURE_DOCUMENT_REJECTIONS_COUNT = def(8_625_00_0);
public static final TransportVersion ALIAS_ACTION_RESULTS = def(8_626_00_0);
/*
* STOP! READ THIS FIRST! No, really,

View file

@ -7,6 +7,7 @@
*/
package org.elasticsearch.action.admin.indices.alias;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse.AliasActionResult;
import org.elasticsearch.cluster.ack.ClusterStateUpdateRequest;
import org.elasticsearch.cluster.metadata.AliasAction;
@ -18,8 +19,11 @@ import java.util.List;
public class IndicesAliasesClusterStateUpdateRequest extends ClusterStateUpdateRequest<IndicesAliasesClusterStateUpdateRequest> {
private final List<AliasAction> actions;
public IndicesAliasesClusterStateUpdateRequest(List<AliasAction> actions) {
private final List<IndicesAliasesResponse.AliasActionResult> actionResults;
public IndicesAliasesClusterStateUpdateRequest(List<AliasAction> actions, List<AliasActionResult> actionResults) {
this.actions = actions;
this.actionResults = actionResults;
}
/**
@ -28,4 +32,8 @@ public class IndicesAliasesClusterStateUpdateRequest extends ClusterStateUpdateR
public List<AliasAction> actions() {
return actions;
}
public List<AliasActionResult> getActionResults() {
return actionResults;
}
}

View file

@ -83,7 +83,6 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
private static final ParseField IS_WRITE_INDEX = new ParseField("is_write_index");
private static final ParseField IS_HIDDEN = new ParseField("is_hidden");
private static final ParseField MUST_EXIST = new ParseField("must_exist");
private static final ParseField ADD = new ParseField("add");
private static final ParseField REMOVE = new ParseField("remove");
private static final ParseField REMOVE_INDEX = new ParseField("remove_index");
@ -105,6 +104,10 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
return value;
}
public String getFieldName() {
return fieldName;
}
public static Type fromValue(byte value) {
return switch (value) {
case 0 -> ADD;

View file

@ -10,7 +10,6 @@ package org.elasticsearch.action.admin.indices.alias;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.support.master.AcknowledgedRequestBuilder;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.internal.ElasticsearchClient;
import org.elasticsearch.index.query.QueryBuilder;
@ -21,7 +20,7 @@ import java.util.Map;
*/
public class IndicesAliasesRequestBuilder extends AcknowledgedRequestBuilder<
IndicesAliasesRequest,
AcknowledgedResponse,
IndicesAliasesResponse,
IndicesAliasesRequestBuilder> {
public IndicesAliasesRequestBuilder(ElasticsearchClient client) {

View file

@ -0,0 +1,245 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.action.admin.indices.alias;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.TransportVersions;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.rest.action.admin.indices.AliasesNotFoundException;
import org.elasticsearch.xcontent.ToXContentObject;
import org.elasticsearch.xcontent.XContentBuilder;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* Response with error information for a request to add/remove aliases for one or more indices.
* Contains an acknowledged boolean, an errors boolean, and a list of results.
* The result list is only present if there are errors, and contains a result for every input action.
* This response replaces AcknowledgedResponse, and knows how to de/serialize from/to AcknowledgedResponse
* in case of mixed version clusters.
*/
public class IndicesAliasesResponse extends AcknowledgedResponse {
// Response without any error information, analogous to AcknowledgedResponse.FALSE
public static final IndicesAliasesResponse NOT_ACKNOWLEDGED = new IndicesAliasesResponse(false, false, List.of());
// Response without any error information, analogous to AcknowledgedResponse.TRUE
public static final IndicesAliasesResponse ACKNOWLEDGED_NO_ERRORS = new IndicesAliasesResponse(true, false, List.of());
private static final String ACTION_RESULTS_FIELD = "action_results";
private static final String ERRORS_FIELD = "errors";
private final List<AliasActionResult> actionResults;
private final boolean errors;
protected IndicesAliasesResponse(StreamInput in) throws IOException {
super(in);
if (in.getTransportVersion().onOrAfter(TransportVersions.ALIAS_ACTION_RESULTS)) {
this.errors = in.readBoolean();
this.actionResults = in.readCollectionAsImmutableList(AliasActionResult::new);
} else {
this.errors = false;
this.actionResults = List.of();
}
}
/**
* @param acknowledged whether the update was acknowledged by all the relevant nodes in the cluster
* @param errors true if any of the requested actions failed
* @param actionResults the list of results for each input action, only present if there are errors
*/
IndicesAliasesResponse(boolean acknowledged, boolean errors, final List<AliasActionResult> actionResults) {
super(acknowledged);
this.errors = errors;
this.actionResults = actionResults;
}
public List<AliasActionResult> getActionResults() {
return actionResults;
}
public boolean hasErrors() {
return errors;
}
/**
* Build a response from a list of action results. Sets the errors boolean based
* on whether an of the individual results contain an error.
* @param actionResults an action result for each of the requested alias actions
* @return response containing all action results
*/
public static IndicesAliasesResponse build(final List<AliasActionResult> actionResults) {
assert actionResults.isEmpty() == false : "IndicesAliasesResponse must be instantiated with at least one action result.";
final boolean errors = actionResults.stream().anyMatch(a -> a.error != null);
return new IndicesAliasesResponse(true, errors, actionResults);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
if (out.getTransportVersion().onOrAfter(TransportVersions.ALIAS_ACTION_RESULTS)) {
out.writeBoolean(errors);
out.writeCollection(actionResults);
}
}
@Override
protected void addCustomFields(XContentBuilder builder, Params params) throws IOException {
builder.field(ERRORS_FIELD, errors);
// if there are no errors, don't provide granular list of results
if (errors) {
builder.field(ACTION_RESULTS_FIELD, actionResults);
}
}
@Override
// Only used equals in tests
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (super.equals(o) == false) return false;
IndicesAliasesResponse response = (IndicesAliasesResponse) o;
return errors == response.errors && Objects.equals(actionResults, response.actionResults);
}
@Override
// Only used hashCode in tests
public int hashCode() {
return Objects.hash(super.hashCode(), actionResults, errors);
}
/**
* Result for a single alias add/remove action
*/
public static class AliasActionResult implements Writeable, ToXContentObject {
/**
* Resolved indices to which the action applies. This duplicates information
* which exists in the action, but is included because the action indices may
* or may not be resolved depending on if the security layer is used or not.
*/
private final List<String> indices;
private final AliasActions action;
private final ElasticsearchException error;
/**
* Build result that could be either a success or failure
* @param indices the resolved indices to which the associated action applies
* @param action the alias action consisting of add/remove, aliases, and indices
* @param numAliasesRemoved the number of aliases remove, if any
* @return the action result
*/
public static AliasActionResult build(List<String> indices, AliasActions action, int numAliasesRemoved) {
if (action.actionType() == AliasActions.Type.REMOVE && numAliasesRemoved == 0) {
return buildRemoveError(indices, action);
}
return buildSuccess(indices, action);
}
/**
* Build an error result for a failed remove action.
*/
private static AliasActionResult buildRemoveError(List<String> indices, AliasActions action) {
return new AliasActionResult(indices, action, new AliasesNotFoundException((action.getOriginalAliases())));
}
/**
* Build a success action result with no errors.
*/
public static AliasActionResult buildSuccess(List<String> indices, AliasActions action) {
return new AliasActionResult(indices, action, null);
}
private int getStatus() {
return error == null ? 200 : error.status().getStatus();
}
private AliasActionResult(List<String> indices, AliasActions action, ElasticsearchException error) {
assert indices.isEmpty() == false : "Alias action result must be instantiated with at least one index";
this.indices = indices;
this.action = action;
this.error = error;
}
private AliasActionResult(StreamInput in) throws IOException {
this.indices = in.readStringCollectionAsList();
this.action = new AliasActions(in);
this.error = in.readException();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeStringCollection(indices);
action.writeTo(out);
out.writeException(error);
}
public static final String ACTION_FIELD = "action";
public static final String ACTION_TYPE_FIELD = "type";
public static final String ACTION_INDICES_FIELD = "indices";
public static final String ACTION_ALIASES_FIELD = "aliases";
public static final String STATUS_FIELD = "status";
public static final String ERROR_FIELD = "error";
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
// include subset of fields from action request
builder.field(ACTION_FIELD);
builder.startObject();
builder.field(ACTION_TYPE_FIELD, action.actionType().getFieldName());
builder.field(ACTION_INDICES_FIELD, indices.stream().sorted().collect(Collectors.toList()));
builder.array(ACTION_ALIASES_FIELD, action.getOriginalAliases());
builder.endObject();
builder.field(STATUS_FIELD, getStatus());
if (error != null) {
builder.startObject(ERROR_FIELD);
error.toXContent(builder, params);
builder.endObject();
}
builder.endObject();
return builder;
}
@Override
// Only used equals in tests
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AliasActionResult that = (AliasActionResult) o;
return Objects.equals(indices, that.indices) && Objects.equals(action, that.action)
// ElasticsearchException does not have hashCode() so assume errors are equal iff class and message are equal
&& Objects.equals(error == null ? null : error.getMessage(), that.error == null ? null : that.error.getMessage())
&& Objects.equals(error == null ? null : error.getClass(), that.error == null ? null : that.error.getClass());
}
@Override
// Only used hashCode in tests
public int hashCode() {
return Objects.hash(
indices,
action,
// ElasticsearchException does not have hashCode() so assume errors are equal iff class and message are equal
error == null ? null : error.getMessage(),
error == null ? null : error.getClass()
);
}
}
}

View file

@ -14,9 +14,9 @@ import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.ActionType;
import org.elasticsearch.action.RequestValidators;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse.AliasActionResult;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.support.master.AcknowledgedTransportMasterNodeAction;
import org.elasticsearch.action.support.master.TransportMasterNodeAction;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.block.ClusterBlockException;
import org.elasticsearch.cluster.block.ClusterBlockLevel;
@ -56,10 +56,10 @@ import static java.util.Collections.unmodifiableList;
/**
* Add/remove aliases action
*/
public class TransportIndicesAliasesAction extends AcknowledgedTransportMasterNodeAction<IndicesAliasesRequest> {
public class TransportIndicesAliasesAction extends TransportMasterNodeAction<IndicesAliasesRequest, IndicesAliasesResponse> {
public static final String NAME = "indices:admin/aliases";
public static final ActionType<AcknowledgedResponse> TYPE = new ActionType<>(NAME);
public static final ActionType<IndicesAliasesResponse> TYPE = new ActionType<>(NAME);
private static final Logger logger = LogManager.getLogger(TransportIndicesAliasesAction.class);
private final MetadataIndexAliasesService indexAliasesService;
@ -85,6 +85,7 @@ public class TransportIndicesAliasesAction extends AcknowledgedTransportMasterNo
actionFilters,
IndicesAliasesRequest::new,
indexNameExpressionResolver,
IndicesAliasesResponse::new,
EsExecutors.DIRECT_EXECUTOR_SERVICE
);
this.indexAliasesService = indexAliasesService;
@ -106,15 +107,19 @@ public class TransportIndicesAliasesAction extends AcknowledgedTransportMasterNo
Task task,
final IndicesAliasesRequest request,
final ClusterState state,
final ActionListener<AcknowledgedResponse> listener
final ActionListener<IndicesAliasesResponse> listener
) {
// Expand the indices names
List<AliasActions> actions = request.aliasActions();
List<AliasAction> finalActions = new ArrayList<>();
List<AliasActionResult> actionResults = new ArrayList<>();
// Resolve all the AliasActions into AliasAction instances and gather all the aliases
Set<String> aliases = new HashSet<>();
for (AliasActions action : actions) {
int numAliasesRemoved = 0;
List<String> resolvedIndices = new ArrayList<>();
List<String> concreteDataStreams = indexNameExpressionResolver.dataStreamNames(
state,
request.indicesOptions(),
@ -161,18 +166,24 @@ public class TransportIndicesAliasesAction extends AcknowledgedTransportMasterNo
finalActions.add(new AddDataStreamAlias(alias, dataStreamName, action.writeIndex(), action.filter()));
}
}
actionResults.add(AliasActionResult.buildSuccess(concreteDataStreams, action));
continue;
}
case REMOVE -> {
for (String dataStreamName : concreteDataStreams) {
for (String alias : concreteDataStreamAliases(action, state.metadata(), dataStreamName)) {
finalActions.add(new AliasAction.RemoveDataStreamAlias(alias, dataStreamName, action.mustExist()));
numAliasesRemoved++;
}
}
if (nonBackingIndices.isEmpty() == false) {
// Regular aliases/indices match as well with the provided expression.
// (Only when adding new aliases, matching both data streams and indices is disallowed)
resolvedIndices.addAll(concreteDataStreams);
} else {
actionResults.add(AliasActionResult.build(concreteDataStreams, action, numAliasesRemoved));
continue;
}
}
@ -224,6 +235,7 @@ public class TransportIndicesAliasesAction extends AcknowledgedTransportMasterNo
case REMOVE:
for (String alias : concreteAliases(action, state.metadata(), index.getName())) {
finalActions.add(new AliasAction.Remove(index.getName(), alias, action.mustExist()));
numAliasesRemoved++;
}
break;
case REMOVE_INDEX:
@ -233,14 +245,18 @@ public class TransportIndicesAliasesAction extends AcknowledgedTransportMasterNo
throw new IllegalArgumentException("Unsupported action [" + action.actionType() + "]");
}
}
Arrays.stream(concreteIndices).map(Index::getName).forEach(resolvedIndices::add);
actionResults.add(AliasActionResult.build(resolvedIndices, action, numAliasesRemoved));
}
if (finalActions.isEmpty() && false == actions.isEmpty()) {
throw new AliasesNotFoundException(aliases.toArray(new String[aliases.size()]));
}
request.aliasActions().clear();
IndicesAliasesClusterStateUpdateRequest updateRequest = new IndicesAliasesClusterStateUpdateRequest(unmodifiableList(finalActions))
.ackTimeout(request.timeout())
.masterNodeTimeout(request.masterNodeTimeout());
IndicesAliasesClusterStateUpdateRequest updateRequest = new IndicesAliasesClusterStateUpdateRequest(
unmodifiableList(finalActions),
unmodifiableList(actionResults)
).ackTimeout(request.timeout()).masterNodeTimeout(request.masterNodeTimeout());
indexAliasesService.indicesAliases(updateRequest, listener.delegateResponse((l, e) -> {
logger.debug("failed to perform aliases", e);

View file

@ -12,6 +12,7 @@ import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequestBuilder;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesResponse;
@ -371,7 +372,7 @@ public interface IndicesAdminClient extends ElasticsearchClient {
* @param request The index aliases request
* @return The result future
*/
ActionFuture<AcknowledgedResponse> aliases(IndicesAliasesRequest request);
ActionFuture<IndicesAliasesResponse> aliases(IndicesAliasesRequest request);
/**
* Allows to add/remove aliases from indices.
@ -379,7 +380,7 @@ public interface IndicesAdminClient extends ElasticsearchClient {
* @param request The index aliases request
* @param listener A listener to be notified with a result
*/
void aliases(IndicesAliasesRequest request, ActionListener<AcknowledgedResponse> listener);
void aliases(IndicesAliasesRequest request, ActionListener<IndicesAliasesResponse> listener);
/**
* Allows to add/remove aliases from indices.

View file

@ -118,6 +118,7 @@ import org.elasticsearch.action.admin.cluster.storedscripts.TransportDeleteStore
import org.elasticsearch.action.admin.cluster.storedscripts.TransportPutStoredScriptAction;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.action.admin.indices.alias.TransportIndicesAliasesAction;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesAction;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
@ -1083,12 +1084,12 @@ public abstract class AbstractClient implements Client {
}
@Override
public ActionFuture<AcknowledgedResponse> aliases(final IndicesAliasesRequest request) {
public ActionFuture<IndicesAliasesResponse> aliases(final IndicesAliasesRequest request) {
return execute(TransportIndicesAliasesAction.TYPE, request);
}
@Override
public void aliases(final IndicesAliasesRequest request, final ActionListener<AcknowledgedResponse> listener) {
public void aliases(final IndicesAliasesRequest request, final ActionListener<IndicesAliasesResponse> listener) {
execute(TransportIndicesAliasesAction.TYPE, request, listener);
}

View file

@ -8,10 +8,10 @@
package org.elasticsearch.cluster.metadata;
import org.elasticsearch.ResourceNotFoundException;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.common.Strings;
import org.elasticsearch.core.Nullable;
import org.elasticsearch.rest.action.admin.indices.AliasesNotFoundException;
/**
* Individual operation to perform on the cluster state as part of an {@link IndicesAliasesRequest}.
@ -189,7 +189,7 @@ public abstract class AliasAction {
boolean apply(NewAliasValidator aliasValidator, Metadata.Builder metadata, IndexMetadata index) {
if (false == index.getAliases().containsKey(alias)) {
if (mustExist != null && mustExist) {
throw new ResourceNotFoundException("required alias [" + alias + "] does not exist");
throw new AliasesNotFoundException(alias);
}
return false;
}

View file

@ -11,7 +11,7 @@ package org.elasticsearch.cluster.metadata;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesClusterStateUpdateRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.ClusterStateAckListener;
import org.elasticsearch.cluster.ClusterStateTaskExecutor;
@ -79,7 +79,10 @@ public class MetadataIndexAliasesService {
this.taskQueue = clusterService.createTaskQueue("index-aliases", Priority.URGENT, this.executor);
}
public void indicesAliases(final IndicesAliasesClusterStateUpdateRequest request, final ActionListener<AcknowledgedResponse> listener) {
public void indicesAliases(
final IndicesAliasesClusterStateUpdateRequest request,
final ActionListener<IndicesAliasesResponse> listener
) {
taskQueue.submitTask("index-aliases", new ApplyAliasesTask(request, listener), null); // TODO use request.masterNodeTimeout() here?
}
@ -254,7 +257,7 @@ public class MetadataIndexAliasesService {
/**
* A cluster state update task that consists of the cluster state request and the listeners that need to be notified upon completion.
*/
record ApplyAliasesTask(IndicesAliasesClusterStateUpdateRequest request, ActionListener<AcknowledgedResponse> listener)
record ApplyAliasesTask(IndicesAliasesClusterStateUpdateRequest request, ActionListener<IndicesAliasesResponse> listener)
implements
ClusterStateTaskListener,
ClusterStateAckListener {
@ -271,17 +274,17 @@ public class MetadataIndexAliasesService {
@Override
public void onAllNodesAcked() {
listener.onResponse(AcknowledgedResponse.TRUE);
listener.onResponse(IndicesAliasesResponse.build(request.getActionResults()));
}
@Override
public void onAckFailure(Exception e) {
listener.onResponse(AcknowledgedResponse.FALSE);
listener.onResponse(IndicesAliasesResponse.NOT_ACKNOWLEDGED);
}
@Override
public void onAckTimeout() {
listener.onResponse(AcknowledgedResponse.FALSE);
listener.onResponse(IndicesAliasesResponse.NOT_ACKNOWLEDGED);
}
@Override

View file

@ -0,0 +1,108 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.action.admin.indices.alias;
import org.elasticsearch.TransportVersions;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.index.alias.RandomAliasActionsGenerator;
import org.elasticsearch.test.AbstractWireSerializingTestCase;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class IndicesAliasesResponseTests extends AbstractWireSerializingTestCase<IndicesAliasesResponse> {
public void testMixedModeSerialization() throws IOException {
// AcknowledgedResponse to IndicesAliasesResponse
// in version before TransportVersions.ALIAS_ACTION_RESULTS
{
var ack = AcknowledgedResponse.of(randomBoolean());
try (BytesStreamOutput output = new BytesStreamOutput()) {
ack.writeTo(output);
try (StreamInput in = output.bytes().streamInput()) {
in.setTransportVersion(TransportVersions.V_8_12_0);
var indicesAliasesResponse = new IndicesAliasesResponse(in);
assertEquals(ack.isAcknowledged(), indicesAliasesResponse.isAcknowledged());
assertTrue(indicesAliasesResponse.getActionResults().isEmpty());
assertFalse(indicesAliasesResponse.hasErrors());
}
}
}
// IndicesAliasesResponse to AcknowledgedResponse
// out version before TransportVersions.ALIAS_ACTION_RESULTS
{
var indicesAliasesResponse = randomIndicesAliasesResponse();
try (BytesStreamOutput output = new BytesStreamOutput()) {
output.setTransportVersion(TransportVersions.V_8_12_0);
indicesAliasesResponse.writeTo(output);
try (StreamInput in = output.bytes().streamInput()) {
var ack = AcknowledgedResponse.readFrom(in);
assertEquals(ack.isAcknowledged(), indicesAliasesResponse.isAcknowledged());
}
}
}
}
@Override
protected Writeable.Reader<IndicesAliasesResponse> instanceReader() {
return IndicesAliasesResponse::new;
}
@Override
protected IndicesAliasesResponse createTestInstance() {
return randomIndicesAliasesResponse();
}
private static IndicesAliasesResponse randomIndicesAliasesResponse() {
int numActions = between(0, 5);
List<IndicesAliasesResponse.AliasActionResult> results = new ArrayList<>();
for (int i = 0; i < numActions; ++i) {
results.add(randomIndicesAliasesResult());
}
return new IndicesAliasesResponse(randomBoolean(), randomBoolean(), results);
}
@Override
protected IndicesAliasesResponse mutateInstance(IndicesAliasesResponse instance) throws IOException {
switch (between(0, 2)) {
case 0: {
boolean acknowledged = instance.isAcknowledged() == false;
return new IndicesAliasesResponse(acknowledged, instance.hasErrors(), instance.getActionResults());
}
case 1: {
boolean errors = instance.hasErrors() == false;
return new IndicesAliasesResponse(instance.isAcknowledged(), errors, instance.getActionResults());
}
default: {
var results = new ArrayList<>(instance.getActionResults());
if (results.isEmpty()) {
results.add(randomIndicesAliasesResult());
} else {
results.remove(between(0, results.size() - 1));
}
return new IndicesAliasesResponse(instance.isAcknowledged(), instance.hasErrors(), results);
}
}
}
private static IndicesAliasesResponse.AliasActionResult randomIndicesAliasesResult() {
var action = RandomAliasActionsGenerator.randomAliasAction();
var indices = Arrays.asList(generateRandomStringArray(10, 5, false, false));
return IndicesAliasesResponse.AliasActionResult.build(indices, action, randomIntBetween(0, 3));
}
}

View file

@ -8,8 +8,9 @@
package org.elasticsearch.cluster.metadata;
import org.elasticsearch.ResourceNotFoundException;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesClusterStateUpdateRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse.AliasActionResult;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.service.ClusterService;
@ -19,6 +20,7 @@ import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.core.Tuple;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.IndexVersion;
import org.elasticsearch.rest.action.admin.indices.AliasesNotFoundException;
import org.elasticsearch.test.ClusterServiceUtils;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.index.IndexVersionUtils;
@ -156,11 +158,11 @@ public class MetadataIndexAliasesServiceTests extends ESTestCase {
// Show that removing non-existing alias with mustExist == true fails
final ClusterState finalCS = after;
final ResourceNotFoundException iae = expectThrows(
ResourceNotFoundException.class,
final AliasesNotFoundException iae = expectThrows(
AliasesNotFoundException.class,
() -> service.applyAliasActions(finalCS, singletonList(new AliasAction.Remove(index, "test_2", true)))
);
assertThat(iae.getMessage(), containsString("required alias [test_2] does not exist"));
assertThat(iae.getMessage(), containsString("aliases [test_2] missing"));
}
public void testMultipleIndices() {
@ -690,10 +692,12 @@ public class MetadataIndexAliasesServiceTests extends ESTestCase {
String index = randomAlphaOfLength(5);
ClusterState before = createIndex(ClusterState.builder(ClusterName.DEFAULT).build(), index);
IndicesAliasesClusterStateUpdateRequest addAliasRequest = new IndicesAliasesClusterStateUpdateRequest(
List.of(new AliasAction.Add(index, "test", null, null, null, null, null))
List.of(new AliasAction.Add(index, "test", null, null, null, null, null)),
List.of(AliasActionResult.buildSuccess(List.of(index), AliasActions.add().aliases("test").indices(index)))
);
IndicesAliasesClusterStateUpdateRequest removeAliasRequest = new IndicesAliasesClusterStateUpdateRequest(
List.of(new AliasAction.Remove(index, "test", true))
List.of(new AliasAction.Remove(index, "test", true)),
List.of(AliasActionResult.buildSuccess(List.of(index), AliasActions.remove().aliases("test").indices(index)))
);
ClusterState after = ClusterStateTaskExecutorUtils.executeAndAssertSuccessful(

View file

@ -14,9 +14,9 @@ import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
import org.elasticsearch.action.admin.cluster.health.TransportClusterHealthAction;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexAbstraction;
@ -130,7 +130,9 @@ public class AnnotationIndex {
client.threadPool().getThreadContext(),
ML_ORIGIN,
requestBuilder.request(),
finalDelegate.<AcknowledgedResponse>delegateFailureAndWrap((l, r) -> checkMappingsListener.onResponse(r.isAcknowledged())),
finalDelegate.<IndicesAliasesResponse>delegateFailureAndWrap(
(l, r) -> checkMappingsListener.onResponse(r.isAcknowledged())
),
client.admin().indices()::aliases
);
});

View file

@ -16,6 +16,7 @@ import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
@ -295,7 +296,7 @@ public final class MlIndexAndAlias {
client.threadPool().getThreadContext(),
ML_ORIGIN,
request,
listener.<AcknowledgedResponse>delegateFailureAndWrap((l, resp) -> l.onResponse(resp.isAcknowledged())),
listener.<IndicesAliasesResponse>delegateFailureAndWrap((l, resp) -> l.onResponse(resp.isAcknowledged())),
client.admin().indices()::aliases
);
}

View file

@ -9,8 +9,8 @@ package org.elasticsearch.xpack.core.ilm;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.cluster.metadata.AliasMetadata;
import org.elasticsearch.cluster.metadata.IndexMetadata;
import org.elasticsearch.index.IndexVersion;
@ -90,8 +90,8 @@ public class ShrinkSetAliasStepTests extends AbstractStepTestCase<ShrinkSetAlias
IndicesAliasesRequest request = (IndicesAliasesRequest) invocation.getArguments()[0];
assertThat(request.getAliasActions(), equalTo(expectedAliasActions));
@SuppressWarnings("unchecked")
ActionListener<AcknowledgedResponse> listener = (ActionListener<AcknowledgedResponse>) invocation.getArguments()[1];
listener.onResponse(AcknowledgedResponse.TRUE);
ActionListener<IndicesAliasesResponse> listener = (ActionListener<IndicesAliasesResponse>) invocation.getArguments()[1];
listener.onResponse(IndicesAliasesResponse.ACKNOWLEDGED_NO_ERRORS);
return null;
}).when(indicesClient).aliases(Mockito.any(), Mockito.any());
@ -113,7 +113,7 @@ public class ShrinkSetAliasStepTests extends AbstractStepTestCase<ShrinkSetAlias
Mockito.doAnswer((Answer<Void>) invocation -> {
@SuppressWarnings("unchecked")
ActionListener<AcknowledgedResponse> listener = (ActionListener<AcknowledgedResponse>) invocation.getArguments()[1];
ActionListener<IndicesAliasesResponse> listener = (ActionListener<IndicesAliasesResponse>) invocation.getArguments()[1];
listener.onFailure(exception);
return null;
}).when(indicesClient).aliases(Mockito.any(), Mockito.any());

View file

@ -13,11 +13,11 @@ import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.template.put.TransportPutComposableIndexTemplateAction;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.support.master.MasterNodeRequest;
import org.elasticsearch.client.internal.AdminClient;
import org.elasticsearch.client.internal.Client;
@ -97,8 +97,8 @@ public class MlIndexAndAliasTests extends ESTestCase {
);
doAnswer(withResponse(new CreateIndexResponse(true, true, FIRST_CONCRETE_INDEX))).when(indicesAdminClient).create(any(), any());
when(indicesAdminClient.prepareAliases()).thenReturn(new IndicesAliasesRequestBuilder(client));
doAnswer(withResponse(AcknowledgedResponse.TRUE)).when(indicesAdminClient).aliases(any(), any());
doAnswer(withResponse(AcknowledgedResponse.TRUE)).when(indicesAdminClient).putTemplate(any(), any());
doAnswer(withResponse(IndicesAliasesResponse.ACKNOWLEDGED_NO_ERRORS)).when(indicesAdminClient).aliases(any(), any());
doAnswer(withResponse(IndicesAliasesResponse.ACKNOWLEDGED_NO_ERRORS)).when(indicesAdminClient).putTemplate(any(), any());
clusterAdminClient = mock(ClusterAdminClient.class);
doAnswer(invocationOnMock -> {
@ -116,8 +116,9 @@ public class MlIndexAndAliasTests extends ESTestCase {
when(client.threadPool()).thenReturn(threadPool);
when(client.admin()).thenReturn(adminClient);
doAnswer(invocationOnMock -> {
ActionListener<AcknowledgedResponse> actionListener = (ActionListener<AcknowledgedResponse>) invocationOnMock.getArguments()[2];
actionListener.onResponse(AcknowledgedResponse.TRUE);
ActionListener<IndicesAliasesResponse> actionListener = (ActionListener<IndicesAliasesResponse>) invocationOnMock
.getArguments()[2];
actionListener.onResponse(IndicesAliasesResponse.ACKNOWLEDGED_NO_ERRORS);
return null;
}).when(client)
.execute(

View file

@ -18,6 +18,7 @@ import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesResponse;
import org.elasticsearch.action.delete.DeleteRequest;
@ -223,7 +224,7 @@ public class SearchApplicationIndexService {
public void putSearchApplication(SearchApplication app, boolean create, ActionListener<DocWriteResponse> listener) {
createOrUpdateAlias(app, new ActionListener<>() {
@Override
public void onResponse(AcknowledgedResponse acknowledgedResponse) {
public void onResponse(IndicesAliasesResponse response) {
updateSearchApplication(app, create, listener);
}
@ -240,7 +241,7 @@ public class SearchApplicationIndexService {
});
}
private void createOrUpdateAlias(SearchApplication app, ActionListener<AcknowledgedResponse> listener) {
private void createOrUpdateAlias(SearchApplication app, ActionListener<IndicesAliasesResponse> listener) {
final Metadata metadata = clusterService.state().metadata();
final String searchAliasName = getSearchAliasName(app);
@ -332,14 +333,14 @@ public class SearchApplicationIndexService {
);
client.admin().indices().aliases(aliasesRequest, new ActionListener<>() {
@Override
public void onResponse(AcknowledgedResponse acknowledgedResponse) {
listener.onResponse(AcknowledgedResponse.TRUE);
public void onResponse(IndicesAliasesResponse response) {
listener.onResponse(response);
}
@Override
public void onFailure(Exception e) {
if (e instanceof ResourceNotFoundException) {
listener.onResponse(AcknowledgedResponse.TRUE);
listener.onResponse(IndicesAliasesResponse.ACKNOWLEDGED_NO_ERRORS);
} else {
listener.onFailure(e);
}

View file

@ -10,6 +10,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.action.admin.indices.alias.TransportIndicesAliasesAction;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesAction;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
@ -173,7 +174,7 @@ public final class MlInitializationService implements ClusterStateListener {
String[] mlHiddenIndexPatterns = MachineLearning.getMlHiddenIndexPatterns();
// Step 5: Handle errors encountered on the way.
ActionListener<AcknowledgedResponse> finalListener = ActionListener.wrap(updateAliasesResponse -> {
ActionListener<IndicesAliasesResponse> finalListener = ActionListener.wrap(updateAliasesResponse -> {
if (updateAliasesResponse.isAcknowledged() == false) {
logger.warn("One or more of the ML internal aliases could not be made hidden.");
return;
@ -194,7 +195,7 @@ public final class MlInitializationService implements ClusterStateListener {
}
if (indicesAliasesRequest.getAliasActions().isEmpty()) {
logger.debug("There are no ML internal aliases that need to be made hidden, [{}]", getAliasesResponse.getAliases());
finalListener.onResponse(AcknowledgedResponse.TRUE);
finalListener.onResponse(IndicesAliasesResponse.ACKNOWLEDGED_NO_ERRORS);
return;
}
String indicesWithNonHiddenAliasesString = indicesAliasesRequest.getAliasActions()

View file

@ -10,6 +10,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
@ -287,7 +288,7 @@ public class JobDataDeleter {
AtomicReference<String[]> indexNames = new AtomicReference<>();
final ActionListener<AcknowledgedResponse> completionHandler = ActionListener.wrap(
final ActionListener<IndicesAliasesResponse> completionHandler = ActionListener.wrap(
response -> finishedHandler.accept(response.isAcknowledged()),
failureHandler
);
@ -295,7 +296,7 @@ public class JobDataDeleter {
// Step 9. If we did not drop the indices and after DBQ state done, we delete the aliases
ActionListener<BulkByScrollResponse> dbqHandler = ActionListener.wrap(bulkByScrollResponse -> {
if (bulkByScrollResponse == null) { // no action was taken by DBQ, assume indices were deleted
completionHandler.onResponse(AcknowledgedResponse.TRUE);
completionHandler.onResponse(IndicesAliasesResponse.ACKNOWLEDGED_NO_ERRORS);
} else {
if (bulkByScrollResponse.isTimedOut()) {
logger.warn("[{}] DeleteByQuery for indices [{}] timed out.", jobId, String.join(", ", indexNames.get()));
@ -469,7 +470,7 @@ public class JobDataDeleter {
executeAsyncWithOrigin(client, ML_ORIGIN, RefreshAction.INSTANCE, refreshRequest, refreshListener);
}
private void deleteAliases(@SuppressWarnings("HiddenField") String jobId, ActionListener<AcknowledgedResponse> finishedHandler) {
private void deleteAliases(@SuppressWarnings("HiddenField") String jobId, ActionListener<IndicesAliasesResponse> finishedHandler) {
final String readAliasName = AnomalyDetectorsIndex.jobResultsAliasedName(jobId);
final String writeAliasName = AnomalyDetectorsIndex.resultsWriteAlias(jobId);
@ -486,7 +487,7 @@ public class JobDataDeleter {
if (removeRequest == null) {
// don't error if the job's aliases have already been deleted - carry on and delete the
// rest of the job's data
finishedHandler.onResponse(AcknowledgedResponse.TRUE);
finishedHandler.onResponse(IndicesAliasesResponse.ACKNOWLEDGED_NO_ERRORS);
return;
}
executeAsyncWithOrigin(

View file

@ -16,6 +16,7 @@ import org.elasticsearch.ResourceNotFoundException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.DelegatingActionListener;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
@ -344,7 +345,7 @@ public class JobResultsProvider {
client.threadPool().getThreadContext(),
ML_ORIGIN,
request,
ActionListener.<AcknowledgedResponse>wrap(r -> finalListener.onResponse(true), finalListener::onFailure),
ActionListener.<IndicesAliasesResponse>wrap(r -> finalListener.onResponse(true), finalListener::onFailure),
client.admin().indices()::aliases
);
}, finalListener::onFailure);

View file

@ -11,7 +11,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.client.internal.Client;
import org.elasticsearch.cluster.ClusterChangedEvent;
import org.elasticsearch.cluster.ClusterState;
@ -97,7 +97,7 @@ class TransformClusterStateListener implements ClusterStateListener {
client.threadPool().getThreadContext(),
TRANSFORM_ORIGIN,
request,
ActionListener.<AcknowledgedResponse>wrap(r -> finalListener.onResponse(r.isAcknowledged()), finalListener::onFailure),
ActionListener.<IndicesAliasesResponse>wrap(r -> finalListener.onResponse(r.isAcknowledged()), finalListener::onFailure),
client.admin().indices()::aliases
);
}