-
Notifications
You must be signed in to change notification settings - Fork 25k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Get Aliases API to the high-level REST client #28799
Changes from 2 commits
6c01eeb
1571cb3
a33ea0f
a919d73
baed505
f74d0b5
7720b71
7238098
e2ffdab
9a2079f
df3b2fb
0e3ad61
519992b
11811ef
474238b
a59a026
b210f49
5b3096b
8660d43
f21b3ca
fa9d4e1
939ae4d
035d823
be1daf7
5da9ed6
5bcc1ce
2e2217a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,6 +60,7 @@ | |
import org.elasticsearch.common.bytes.BytesReference; | ||
import org.elasticsearch.common.lucene.uid.Versions; | ||
import org.elasticsearch.common.unit.TimeValue; | ||
import org.elasticsearch.common.util.CollectionUtils; | ||
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; | ||
import org.elasticsearch.common.xcontent.NamedXContentRegistry; | ||
import org.elasticsearch.common.xcontent.ToXContent; | ||
|
@@ -555,6 +556,33 @@ static Request rollover(RolloverRequest rolloverRequest) throws IOException { | |
return new Request(HttpPost.METHOD_NAME, endpoint, params.getParams(), entity); | ||
} | ||
|
||
static Request getAlias(GetAliasesRequest getAliasesRequest) { | ||
Params params = Params.builder(); | ||
params.withIndicesOptions(getAliasesRequest.indicesOptions()); | ||
params.withLocal(getAliasesRequest.local()); | ||
if (false == CollectionUtils.isEmpty(getAliasesRequest.aliases())) { | ||
params.withName(getAliasesRequest.aliases()); | ||
} else { | ||
params.withName(getAliasesRequest.name()); | ||
} | ||
String endpoint = endpoint(optional(getAliasesRequest.indices(), "_all"), "_alias"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If there are no indices and no aliases specified ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see! but although it is a different response on the REST layer, could its output be parsed into a |
||
return new Request(HttpGet.METHOD_NAME, endpoint, params.getParams(), null); | ||
} | ||
|
||
private static String[] optional(String[] params) { | ||
return optional(params, null); | ||
} | ||
|
||
private static String[] optional(String[] params, String defaultParam) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ideally we wouldn't need these two methods, we would just pass in the empty array, which makes us hit a different endpoint that returns a compatible response. |
||
if (CollectionUtils.isEmpty(params)) { | ||
if (defaultParam != null) { | ||
return new String[] {defaultParam}; | ||
} | ||
return Strings.EMPTY_ARRAY; | ||
} | ||
return params; | ||
} | ||
|
||
private static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) throws IOException { | ||
BytesRef source = XContentHelper.toXContent(toXContent, xContentType, false).toBytesRef(); | ||
return new ByteArrayEntity(source.bytes, source.offset, source.length, createContentType(xContentType)); | ||
|
@@ -807,6 +835,13 @@ Params withIncludeDefaults(boolean includeDefaults) { | |
return this; | ||
} | ||
|
||
Params withName(String[] names) { | ||
if (false == CollectionUtils.isEmpty(names)) { | ||
return putParam("name", String.join(",", names)); | ||
} | ||
return this; | ||
} | ||
|
||
Map<String, String> getParams() { | ||
return Collections.unmodifiableMap(params); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,7 @@ | |
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions; | ||
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.close.CloseIndexRequest; | ||
import org.elasticsearch.action.admin.indices.close.CloseIndexResponse; | ||
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; | ||
|
@@ -63,6 +64,8 @@ | |
import static org.hamcrest.CoreMatchers.hasItem; | ||
import static org.hamcrest.Matchers.equalTo; | ||
import static org.hamcrest.Matchers.not; | ||
import static org.hamcrest.Matchers.notNullValue; | ||
import static org.hamcrest.Matchers.nullValue; | ||
|
||
public class IndicesClientIT extends ESRestHighLevelClientTestCase { | ||
|
||
|
@@ -495,4 +498,125 @@ public void testRollover() throws IOException { | |
assertEquals("test_new", rolloverResponse.getNewIndex()); | ||
} | ||
} | ||
|
||
public void testGetAlias() throws IOException { | ||
{ | ||
createIndex("index1", Settings.EMPTY); | ||
client().performRequest(HttpPut.METHOD_NAME, "/index1/_alias/alias1"); | ||
|
||
createIndex("index2", Settings.EMPTY); | ||
client().performRequest(HttpPut.METHOD_NAME, "/index2/_alias/alias2"); | ||
|
||
createIndex("index3", Settings.EMPTY); | ||
} | ||
GetAliasesRequest getAliasesRequest1 = new GetAliasesRequest().aliases("alias1"); | ||
GetAliasesResponse getAliasesResponse = execute(getAliasesRequest1, highLevelClient().indices()::getAlias, | ||
highLevelClient().indices()::getAliasAsync); | ||
|
||
assertThat(getAliasesResponse.getAliases().size(), equalTo(1)); | ||
assertThat(getAliasesResponse.getAliases().get("index1").size(), equalTo(1)); | ||
assertThat(getAliasesResponse.getAliases().get("index1").get(0), notNullValue()); | ||
assertThat(getAliasesResponse.getAliases().get("index1").get(0).alias(), equalTo("alias1")); | ||
assertThat(getAliasesResponse.getAliases().get("index1").get(0).getFilter(), nullValue()); | ||
assertThat(getAliasesResponse.getAliases().get("index1").get(0).getIndexRouting(), nullValue()); | ||
assertThat(getAliasesResponse.getAliases().get("index1").get(0).getSearchRouting(), nullValue()); | ||
|
||
GetAliasesRequest getAliasesRequest2 = new GetAliasesRequest().aliases("alias*"); | ||
getAliasesResponse = execute(getAliasesRequest2, highLevelClient().indices()::getAlias, highLevelClient().indices()::getAliasAsync); | ||
|
||
assertThat(getAliasesResponse.getAliases().size(), equalTo(2)); | ||
assertThat(getAliasesResponse.getAliases().get("index1").size(), equalTo(1)); | ||
assertThat(getAliasesResponse.getAliases().get("index1").get(0), notNullValue()); | ||
assertThat(getAliasesResponse.getAliases().get("index1").get(0).alias(), equalTo("alias1")); | ||
assertThat(getAliasesResponse.getAliases().get("index2").size(), equalTo(1)); | ||
assertThat(getAliasesResponse.getAliases().get("index2").get(0), notNullValue()); | ||
assertThat(getAliasesResponse.getAliases().get("index2").get(0).alias(), equalTo("alias2")); | ||
|
||
GetAliasesRequest getAliasesRequest3 = new GetAliasesRequest().indices("_all"); | ||
getAliasesResponse = execute(getAliasesRequest3, highLevelClient().indices()::getAlias, highLevelClient().indices()::getAliasAsync); | ||
|
||
assertThat(getAliasesResponse.getAliases().size(), equalTo(3)); | ||
assertThat(getAliasesResponse.getAliases().get("index1").size(), equalTo(1)); | ||
assertThat(getAliasesResponse.getAliases().get("index1").get(0), notNullValue()); | ||
assertThat(getAliasesResponse.getAliases().get("index1").get(0).alias(), equalTo("alias1")); | ||
assertThat(getAliasesResponse.getAliases().get("index2").size(), equalTo(1)); | ||
assertThat(getAliasesResponse.getAliases().get("index2").get(0), notNullValue()); | ||
assertThat(getAliasesResponse.getAliases().get("index2").get(0).alias(), equalTo("alias2")); | ||
assertThat(getAliasesResponse.getAliases().get("index3").size(), equalTo(0)); | ||
|
||
GetAliasesRequest getAliasesRequest4 = new GetAliasesRequest(); | ||
getAliasesResponse = execute(getAliasesRequest4, highLevelClient().indices()::getAlias, highLevelClient().indices()::getAliasAsync); | ||
|
||
assertThat(getAliasesResponse.getAliases().size(), equalTo(3)); | ||
assertThat(getAliasesResponse.getAliases().get("index1").size(), equalTo(1)); | ||
assertThat(getAliasesResponse.getAliases().get("index1").get(0), notNullValue()); | ||
assertThat(getAliasesResponse.getAliases().get("index1").get(0).alias(), equalTo("alias1")); | ||
assertThat(getAliasesResponse.getAliases().get("index2").size(), equalTo(1)); | ||
assertThat(getAliasesResponse.getAliases().get("index2").get(0), notNullValue()); | ||
assertThat(getAliasesResponse.getAliases().get("index2").get(0).alias(), equalTo("alias2")); | ||
assertThat(getAliasesResponse.getAliases().get("index3").size(), equalTo(0)); | ||
|
||
GetAliasesRequest getAliasesRequest5 = new GetAliasesRequest().indices("ind*"); | ||
getAliasesResponse = execute(getAliasesRequest5, highLevelClient().indices()::getAlias, highLevelClient().indices()::getAliasAsync); | ||
|
||
assertThat(getAliasesResponse.getAliases().size(), equalTo(3)); | ||
assertThat(getAliasesResponse.getAliases().get("index1").size(), equalTo(1)); | ||
assertThat(getAliasesResponse.getAliases().get("index1").get(0), notNullValue()); | ||
assertThat(getAliasesResponse.getAliases().get("index1").get(0).alias(), equalTo("alias1")); | ||
assertThat(getAliasesResponse.getAliases().get("index2").size(), equalTo(1)); | ||
assertThat(getAliasesResponse.getAliases().get("index2").get(0), notNullValue()); | ||
assertThat(getAliasesResponse.getAliases().get("index2").get(0).alias(), equalTo("alias2")); | ||
assertThat(getAliasesResponse.getAliases().get("index3").size(), equalTo(0)); | ||
} | ||
|
||
public void testGetAliasesNonExistentIndexOrAlias() throws IOException { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it is worth leaving a comment that we are so thorough here because it is the only way we can check that we haven't slid out of sync with the server because the server renders the xcontent in a spot that is difficult for us to access in a unit test. |
||
|
||
String alias = "alias"; | ||
String index = "index"; | ||
|
||
GetAliasesRequest getAliasesRequest1 = new GetAliasesRequest().indices(index); | ||
ElasticsearchException exception = expectThrows(ElasticsearchException.class, | ||
() -> execute(getAliasesRequest1, highLevelClient().indices()::getAlias, highLevelClient().indices()::getAliasAsync)); | ||
|
||
assertThat(exception.status(), equalTo(RestStatus.NOT_FOUND)); | ||
assertThat(exception.getMessage(), equalTo("Elasticsearch exception [type=index_not_found_exception, reason=no such index]")); | ||
|
||
GetAliasesRequest getAliasesRequest2 = new GetAliasesRequest(alias); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would you mind wrapping these checks into curly brackets so you can declare again the exception variable as a new one and we make sure that there are no interactions between the different checks? |
||
exception = expectThrows(ElasticsearchException.class, | ||
() -> execute(getAliasesRequest2, highLevelClient().indices()::getAlias, highLevelClient().indices()::getAliasAsync)); | ||
|
||
assertThat(exception.status(), equalTo(RestStatus.NOT_FOUND)); | ||
assertThat(exception.getMessage(), equalTo("Elasticsearch exception [type=exception, reason=alias [" + alias + "] missing]")); | ||
|
||
createIndex(index, Settings.EMPTY); | ||
client().performRequest(HttpPut.METHOD_NAME, index + "/_alias/" + alias); | ||
|
||
GetAliasesRequest getAliasesRequest3 = new GetAliasesRequest().indices(index, "non_existent_index"); | ||
exception = expectThrows(ElasticsearchException.class, | ||
() -> execute(getAliasesRequest3, highLevelClient().indices()::getAlias, highLevelClient().indices()::getAliasAsync)); | ||
assertThat(exception.status(), equalTo(RestStatus.NOT_FOUND)); | ||
assertThat(exception.getMessage(), equalTo("Elasticsearch exception [type=index_not_found_exception, reason=no such index]")); | ||
|
||
GetAliasesRequest getAliasesRequest4 = new GetAliasesRequest().indices(index, "non_existent_index").aliases(alias); | ||
exception = expectThrows(ElasticsearchException.class, | ||
() -> execute(getAliasesRequest4, highLevelClient().indices()::getAlias, highLevelClient().indices()::getAliasAsync)); | ||
assertThat(exception.status(), equalTo(RestStatus.NOT_FOUND)); | ||
assertThat(exception.getMessage(), equalTo("Elasticsearch exception [type=index_not_found_exception, reason=no such index]")); | ||
|
||
GetAliasesRequest getAliasesRequest5 = new GetAliasesRequest().indices(index).aliases(alias, "non_existent_alias"); | ||
exception = expectThrows(ElasticsearchException.class, | ||
() -> execute(getAliasesRequest5, highLevelClient().indices()::getAlias, highLevelClient().indices()::getAliasAsync)); | ||
/* | ||
{ | ||
"error": "alias [something] missing", | ||
"status": 404, | ||
"index": { | ||
"aliases": { | ||
"alias": {} | ||
} | ||
} | ||
} | ||
*/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is actually what ES Rest layer is returning in this case... And the high level client cannot parse the exception body here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is a funny response, as the error may be mixed up with an actual response that holds aliases. We have similar situations in a few other places, for instance in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean to change the response to something like :
return 200 and ask the clients to parse the failures to see if there were exceptions ? For moving the logic to the transport, I am not really sure if it is possible. There was an issue and a fix which got reverted because of side effects ( issue : #27763, reverted PR : #28294 ). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mean to leave the final output the same but to refactor the response object. The PR that was reverted was changing things even deeper in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hey @javanna, sorry I didn't get back on this one sooner. If the status ( and the error msg ) are calculated on the transport layer, then they shoud also be serialized, shouldn't they ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no worries, yes additional info added as part of the transport action execution should be serialized over transport. |
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ | |
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions; | ||
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.close.CloseIndexRequest; | ||
import org.elasticsearch.action.admin.indices.close.CloseIndexResponse; | ||
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; | ||
|
@@ -47,6 +48,8 @@ | |
import org.elasticsearch.action.support.IndicesOptions; | ||
import org.elasticsearch.client.ESRestHighLevelClientTestCase; | ||
import org.elasticsearch.client.RestHighLevelClient; | ||
import org.elasticsearch.cluster.metadata.AliasMetaData; | ||
import org.elasticsearch.common.collect.ImmutableOpenMap; | ||
import org.elasticsearch.common.settings.Settings; | ||
import org.elasticsearch.common.unit.ByteSizeUnit; | ||
import org.elasticsearch.common.unit.ByteSizeValue; | ||
|
@@ -59,10 +62,14 @@ | |
|
||
import java.io.IOException; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.concurrent.CountDownLatch; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
import static org.hamcrest.Matchers.equalTo; | ||
import static org.hamcrest.Matchers.notNullValue; | ||
|
||
/** | ||
* This class is used to generate the Java Indices API documentation. | ||
* You need to wrap your code between two tags like: | ||
|
@@ -1055,4 +1062,76 @@ public void onFailure(Exception e) { | |
|
||
assertTrue(latch.await(30L, TimeUnit.SECONDS)); | ||
} | ||
|
||
public void testGetAlias() throws Exception { | ||
RestHighLevelClient client = highLevelClient(); | ||
|
||
{ | ||
CreateIndexResponse createIndexResponse = client.indices().create(new CreateIndexRequest("index").alias(new Alias("alias"))); | ||
assertTrue(createIndexResponse.isAcknowledged()); | ||
} | ||
|
||
{ | ||
// tag::get-alias-request | ||
GetAliasesRequest request = new GetAliasesRequest(); | ||
GetAliasesRequest requestWithAlias = new GetAliasesRequest("alias1"); | ||
GetAliasesRequest requestWithAliases = | ||
new GetAliasesRequest(new String[] {"alias1", "alias2"}); | ||
// end::get-alias-request | ||
|
||
// tag::get-alias-request-alias | ||
request.aliases("alias"); // <1> | ||
// end::get-alias-request-alias | ||
// tag::get-alias-request-indices | ||
request.indices("index"); // <1> | ||
// end::get-alias-request-indices | ||
|
||
// tag::get-alias-request-indicesOptions | ||
request.indicesOptions(IndicesOptions.lenientExpandOpen()); // <1> | ||
// end::get-alias-request-indicesOptions | ||
|
||
// tag::get-alias-request-local | ||
request.local(true); // <1> | ||
// end::get-alias-request-local | ||
|
||
// tag::get-alias-execute | ||
GetAliasesResponse response = client.indices().getAlias(request); | ||
// end::get-alias-execute | ||
|
||
// tag::get-alias-response | ||
ImmutableOpenMap<String,List<AliasMetaData>> aliases = | ||
response.getAliases(); // <1> | ||
// end::get-alias-response | ||
|
||
assertThat(response.getAliases().get("index").size(), equalTo(1)); | ||
assertThat(response.getAliases().get("index").get(0).alias(), equalTo("alias")); | ||
|
||
// tag::get-alias-listener | ||
ActionListener<GetAliasesResponse> listener = | ||
new ActionListener<GetAliasesResponse>() { | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extra line? |
||
@Override | ||
public void onResponse(GetAliasesResponse getAliasesResponse) { | ||
// <1> | ||
} | ||
|
||
@Override | ||
public void onFailure(Exception e) { | ||
// <2> | ||
} | ||
}; | ||
// end::get-alias-listener | ||
|
||
// Replace the empty listener by a blocking listener in test | ||
final CountDownLatch latch = new CountDownLatch(1); | ||
listener = new LatchedActionListener<>(listener, latch); | ||
|
||
// tag::get-alias-execute-async | ||
client.indices().getAliasAsync(request, listener); // <1> | ||
// end::get-alias-execute-async | ||
|
||
assertTrue(latch.await(30L, TimeUnit.SECONDS)); | ||
} | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need this branch after all :) we can get rid of
withName
too, I didn't see that name goes into the request already as part of aliases.