Skip to content
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

Fix Get Alias API handling of hidden indices with visible aliases #53147

Merged
merged 5 commits into from
Mar 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class GetAliasesRequest extends MasterNodeReadRequest<GetAliasesRequest>

private String[] indices = Strings.EMPTY_ARRAY;
private String[] aliases = Strings.EMPTY_ARRAY;
private IndicesOptions indicesOptions = IndicesOptions.strictExpand();
private IndicesOptions indicesOptions = IndicesOptions.strictExpandHidden();
private String[] originalAliases = Strings.EMPTY_ARRAY;

public GetAliasesRequest(String... aliases) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ public enum Option {
EnumSet.of(WildcardStates.OPEN, WildcardStates.CLOSED, WildcardStates.HIDDEN));
public static final IndicesOptions STRICT_EXPAND_OPEN_CLOSED =
new IndicesOptions(EnumSet.of(Option.ALLOW_NO_INDICES), EnumSet.of(WildcardStates.OPEN, WildcardStates.CLOSED));
public static final IndicesOptions STRICT_EXPAND_OPEN_CLOSED_HIDDEN =
new IndicesOptions(EnumSet.of(Option.ALLOW_NO_INDICES),
EnumSet.of(WildcardStates.OPEN, WildcardStates.CLOSED, WildcardStates.HIDDEN));
public static final IndicesOptions STRICT_EXPAND_OPEN_FORBID_CLOSED =
new IndicesOptions(EnumSet.of(Option.ALLOW_NO_INDICES, Option.FORBID_CLOSED_INDICES), EnumSet.of(WildcardStates.OPEN));
public static final IndicesOptions STRICT_EXPAND_OPEN_HIDDEN_FORBID_CLOSED =
Expand Down Expand Up @@ -406,6 +409,14 @@ public static IndicesOptions strictExpand() {
return STRICT_EXPAND_OPEN_CLOSED;
}

/**
* @return indices option that requires every specified index to exist, expands wildcards to both open and closed indices, includes
* hidden indices, and allows that no indices are resolved from wildcard expressions (not returning an error).
*/
public static IndicesOptions strictExpandHidden() {
return STRICT_EXPAND_OPEN_CLOSED_HIDDEN;
}

/**
* @return indices option that requires each specified index or alias to exist, doesn't expand wildcards and
* throws error if any of the aliases resolves to multiple indices
Expand Down
65 changes: 65 additions & 0 deletions server/src/test/java/org/elasticsearch/index/HiddenIndexIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

package org.elasticsearch.index;

import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequestBuilder;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesResponse;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse;
import org.elasticsearch.action.search.SearchResponse;
Expand All @@ -36,7 +39,10 @@

import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;

public class HiddenIndexIT extends ESIntegTestCase {

Expand Down Expand Up @@ -135,4 +141,63 @@ public void testNonGlobalTemplateCanMakeIndexHidden() {
GetSettingsResponse getSettingsResponse = client().admin().indices().prepareGetSettings("my_hidden_pattern1").get();
assertThat(getSettingsResponse.getSetting("my_hidden_pattern1", "index.hidden"), is("true"));
}

public void testAliasesForHiddenIndices() {
final String hiddenIndex = "hidden-index";
final String visibleAlias = "alias-visible";
final String hiddenAlias = "alias-hidden";
final String dotHiddenAlias = ".alias-hidden";

assertAcked(client().admin().indices().prepareCreate(hiddenIndex)
.setSettings(Settings.builder().put("index.hidden", true).build())
.get());

assertAcked(admin().indices().prepareAliases()
.addAliasAction(IndicesAliasesRequest.AliasActions.add().index(hiddenIndex).alias(visibleAlias)));

// The index should be returned here when queried by name or by wildcard because the alias is visible
final GetAliasesRequestBuilder req = client().admin().indices().prepareGetAliases(visibleAlias);
GetAliasesResponse response = req.get();
assertThat(response.getAliases().get(hiddenIndex), hasSize(1));
assertThat(response.getAliases().get(hiddenIndex).get(0).alias(), equalTo(visibleAlias));
assertThat(response.getAliases().get(hiddenIndex).get(0).isHidden(), nullValue());

response = client().admin().indices().prepareGetAliases("alias*").get();
assertThat(response.getAliases().get(hiddenIndex), hasSize(1));
assertThat(response.getAliases().get(hiddenIndex).get(0).alias(), equalTo(visibleAlias));
assertThat(response.getAliases().get(hiddenIndex).get(0).isHidden(), nullValue());

// Now try with a hidden alias
assertAcked(admin().indices().prepareAliases()
.addAliasAction(IndicesAliasesRequest.AliasActions.remove().index(hiddenIndex).alias(visibleAlias))
.addAliasAction(IndicesAliasesRequest.AliasActions.add().index(hiddenIndex).alias(hiddenAlias).isHidden(true)));

// Querying by name directly should get the right result
response = client().admin().indices().prepareGetAliases(hiddenAlias).get();
assertThat(response.getAliases().get(hiddenIndex), hasSize(1));
assertThat(response.getAliases().get(hiddenIndex).get(0).alias(), equalTo(hiddenAlias));
assertThat(response.getAliases().get(hiddenIndex).get(0).isHidden(), equalTo(true));

// querying by wildcard should get the right result because the indices options include hidden by default
response = client().admin().indices().prepareGetAliases("alias*").get();
assertThat(response.getAliases().get(hiddenIndex), hasSize(1));
assertThat(response.getAliases().get(hiddenIndex).get(0).alias(), equalTo(hiddenAlias));
assertThat(response.getAliases().get(hiddenIndex).get(0).isHidden(), equalTo(true));

// But we should get no results if we specify indices options that don't include hidden
response = client().admin().indices().prepareGetAliases("alias*")
.setIndicesOptions(IndicesOptions.strictExpandOpen()).get();
assertThat(response.getAliases().get(hiddenIndex), nullValue());

// Now try with a hidden alias that starts with a dot
assertAcked(admin().indices().prepareAliases()
.addAliasAction(IndicesAliasesRequest.AliasActions.remove().index(hiddenIndex).alias(hiddenAlias))
.addAliasAction(IndicesAliasesRequest.AliasActions.add().index(hiddenIndex).alias(dotHiddenAlias).isHidden(true)));

// Check that querying by dot-prefixed pattern returns the alias
response = client().admin().indices().prepareGetAliases(".alias*").get();
assertThat(response.getAliases().get(hiddenIndex), hasSize(1));
assertThat(response.getAliases().get(hiddenIndex).get(0).alias(), equalTo(dotHiddenAlias));
assertThat(response.getAliases().get(hiddenIndex).get(0).isHidden(), equalTo(true));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@

import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesAction;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesAction;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequestBuilder;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexAction;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.rest.action.admin.indices.AliasesNotFoundException;
import org.elasticsearch.test.SecurityIntegTestCase;
import org.hamcrest.Matchers;
import org.junit.Before;

import java.util.Collections;
Expand All @@ -28,6 +31,8 @@
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.nullValue;

public class IndexAliasesTests extends SecurityIntegTestCase {

Expand Down Expand Up @@ -590,6 +595,61 @@ public void testRemoveIndex() {
assertAliases(client().admin().indices().prepareGetAliases().setAliases("*"), "bogus_index_1", "bogus_alias_1", "bogus_alias_2");
}

public void testAliasesForHiddenIndices() {
final String hiddenIndex = "test_hidden";
final String visibleAlias = "alias_visible";
final String hiddenAlias = "alias_hidden";

final Map<String, String> createHeaders = Collections.singletonMap(
BASIC_AUTH_HEADER, basicAuthHeaderValue("all_on_test", new SecureString("test123".toCharArray())));
final Client createClient = client(createHeaders);

final Map<String, String> aliasHeaders = Collections.singletonMap(
BASIC_AUTH_HEADER, basicAuthHeaderValue("aliases_only", new SecureString("test123".toCharArray())));
final Client aliasesClient = client(aliasHeaders);

assertAcked(createClient.admin().indices().prepareCreate(hiddenIndex)
.setSettings(Settings.builder().put("index.hidden", true).build())
.get());

assertAcked(aliasesClient.admin().indices().prepareAliases()
.addAliasAction(IndicesAliasesRequest.AliasActions.add().index(hiddenIndex).alias(visibleAlias)));

// The index should be returned here when queried by name or by wildcard because the alias is visible
final GetAliasesRequestBuilder req = aliasesClient.admin().indices().prepareGetAliases(visibleAlias);
GetAliasesResponse response = req.get();
assertThat(response.getAliases().get(hiddenIndex), hasSize(1));
assertThat(response.getAliases().get(hiddenIndex).get(0).alias(), Matchers.equalTo(visibleAlias));
assertThat(response.getAliases().get(hiddenIndex).get(0).isHidden(), nullValue());

response = client().admin().indices().prepareGetAliases("alias*").get();
assertThat(response.getAliases().get(hiddenIndex), hasSize(1));
assertThat(response.getAliases().get(hiddenIndex).get(0).alias(), Matchers.equalTo(visibleAlias));
assertThat(response.getAliases().get(hiddenIndex).get(0).isHidden(), nullValue());

// Now try with a hidden alias
assertAcked(aliasesClient.admin().indices().prepareAliases()
.addAliasAction(IndicesAliasesRequest.AliasActions.remove().index(hiddenIndex).alias(visibleAlias))
.addAliasAction(IndicesAliasesRequest.AliasActions.add().index(hiddenIndex).alias(hiddenAlias).isHidden(true)));

// Querying by name directly should get the right result
response = aliasesClient.admin().indices().prepareGetAliases(hiddenAlias).get();
assertThat(response.getAliases().get(hiddenIndex), hasSize(1));
assertThat(response.getAliases().get(hiddenIndex).get(0).alias(), Matchers.equalTo(hiddenAlias));
assertThat(response.getAliases().get(hiddenIndex).get(0).isHidden(), Matchers.equalTo(true));

// querying by wildcard should get the right result because the indices options include hidden by default
response = aliasesClient.admin().indices().prepareGetAliases("alias*").get();
assertThat(response.getAliases().get(hiddenIndex), hasSize(1));
assertThat(response.getAliases().get(hiddenIndex).get(0).alias(), Matchers.equalTo(hiddenAlias));
assertThat(response.getAliases().get(hiddenIndex).get(0).isHidden(), Matchers.equalTo(true));

// But we should get no results if we specify indices options that don't include hidden
response = aliasesClient.admin().indices().prepareGetAliases("alias*")
.setIndicesOptions(IndicesOptions.strictExpandOpen()).get();
assertThat(response.getAliases().get(hiddenIndex), nullValue());
}

private static Client client(final Map<String, String> headers) {
// it should not matter what client we send the request to, but let's pin all requests to a specific node
final Client client;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -983,11 +983,12 @@ public void testResolveAllGetAliasesRequest() {
request.aliases("alias1");
final List<String> authorizedIndices = buildAuthorizedIndices(user, GetAliasesAction.NAME);
List<String> indices = resolveIndices(request, authorizedIndices).getLocal();
//the union of all resolved indices and aliases gets returned
String[] expectedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foobarfoo", "foofoo", "foofoo-closed", "alias1"};
assertThat(indices.size(), equalTo(expectedIndices.length));
assertThat(indices, hasItems(expectedIndices));
String[] replacedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foobarfoo", "foofoo", "foofoo-closed"};
//the union of all resolved indices and aliases gets returned, including hidden indices as Get Aliases includes hidden by default
String[] expectedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foobarfoo", "foofoo", "foofoo-closed", "alias1",
"hidden-open", "hidden-closed", ".hidden-open", ".hidden-closed"};
assertSameValues(indices, expectedIndices);
String[] replacedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foobarfoo", "foofoo", "foofoo-closed", "hidden-open",
"hidden-closed", ".hidden-open", ".hidden-closed"};
//_all gets replaced with all indices that user is authorized for
assertThat(request.indices(), arrayContainingInAnyOrder(replacedIndices));
assertThat(request.aliases(), arrayContainingInAnyOrder("alias1"));
Expand Down Expand Up @@ -1063,8 +1064,9 @@ public void testResolveAllAliasesGetAliasesRequest() {
}
final List<String> authorizedIndices = buildAuthorizedIndices(user, GetAliasesAction.NAME);
List<String> indices = resolveIndices(request, authorizedIndices).getLocal();
//the union of all resolved indices and aliases gets returned
String[] expectedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foobarfoo", "foofoo", "foofoo-closed"};
//the union of all resolved indices and aliases gets returned, including hidden indices as Get Aliases includes hidden by default
String[] expectedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foobarfoo", "foofoo", "foofoo-closed", "hidden-open",
"hidden-closed", ".hidden-open", ".hidden-closed"};
assertSameValues(indices, expectedIndices);
//_all gets replaced with all indices that user is authorized for
assertThat(request.indices(), arrayContainingInAnyOrder(expectedIndices));
Expand All @@ -1078,11 +1080,14 @@ public void testResolveAllAndExplicitAliasesGetAliasesRequest() {
}
final List<String> authorizedIndices = buildAuthorizedIndices(user, GetAliasesAction.NAME);
List<String> indices = resolveIndices(request, authorizedIndices).getLocal();
//the union of all resolved indices and aliases gets returned
String[] expectedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foobarfoo", "foofoo", "foofoo-closed", "explicit"};
//the union of all resolved indices and aliases gets returned, including hidden indices as Get Aliases includes hidden by default
String[] expectedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foobarfoo", "foofoo", "foofoo-closed", "explicit",
"hidden-open", "hidden-closed", ".hidden-open", ".hidden-closed"};
logger.info("indices: {}", indices);
assertSameValues(indices, expectedIndices);
//_all gets replaced with all indices that user is authorized for
assertThat(request.indices(), arrayContainingInAnyOrder("bar", "bar-closed", "foofoobar", "foobarfoo", "foofoo", "foofoo-closed"));
assertThat(request.indices(), arrayContainingInAnyOrder("bar", "bar-closed", "foofoobar", "foobarfoo", "foofoo", "foofoo-closed",
"hidden-open", "hidden-closed", ".hidden-open", ".hidden-closed"));
assertThat(request.aliases(), arrayContainingInAnyOrder("foofoobar", "foobarfoo", "explicit"));
}

Expand All @@ -1093,8 +1098,9 @@ public void testResolveAllAndWildcardsAliasesGetAliasesRequest() {
}
final List<String> authorizedIndices = buildAuthorizedIndices(user, GetAliasesAction.NAME);
List<String> indices = resolveIndices(request, authorizedIndices).getLocal();
//the union of all resolved indices and aliases gets returned
String[] expectedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foobarfoo", "foofoo", "foofoo-closed"};
//the union of all resolved indices and aliases gets returned, including hidden indices as Get Aliases includes hidden by default
String[] expectedIndices = new String[]{"bar", "bar-closed", "foofoobar", "foobarfoo", "foofoo", "foofoo-closed", "hidden-open",
"hidden-closed", ".hidden-open", ".hidden-closed"};
assertSameValues(indices, expectedIndices);
//_all gets replaced with all indices that user is authorized for
assertThat(request.indices(), arrayContainingInAnyOrder(expectedIndices));
Expand Down Expand Up @@ -1134,10 +1140,13 @@ public void testResolveAliasesExclusionWildcardsGetAliasesRequest() {
//union of all resolved indices and aliases gets returned, based on what user is authorized for
//note that the index side will end up containing matching aliases too, which is fine, as es core would do
//the same and resolve those aliases to their corresponding concrete indices (which we let core do)
String[] expectedIndices = new String[]{"bar", "bar-closed", "foobarfoo", "foofoo", "foofoo-closed", "foofoobar"};
//also includes hidden indices as Get Aliases includes hidden by default
String[] expectedIndices = new String[]{"bar", "bar-closed", "foobarfoo", "foofoo", "foofoo-closed", "foofoobar", "hidden-open",
"hidden-closed", ".hidden-open", ".hidden-closed"};
assertSameValues(indices, expectedIndices);
//alias foofoobar on both sides, that's fine, es core would do the same, same as above
assertThat(request.indices(), arrayContainingInAnyOrder("bar", "bar-closed", "foobarfoo", "foofoo", "foofoo-closed", "foofoobar"));
assertThat(request.indices(), arrayContainingInAnyOrder("bar", "bar-closed", "foobarfoo", "foofoo", "foofoo-closed", "foofoobar",
"hidden-open", "hidden-closed", ".hidden-open", ".hidden-closed"));
assertThat(request.aliases(), arrayContainingInAnyOrder("foofoobar"));
}

Expand Down