From 79f2079fa38f806380ab2a48c769edaea8916dc7 Mon Sep 17 00:00:00 2001 From: lukasz-soszynski-eliatra <110241464+lukasz-soszynski-eliatra@users.noreply.github.com> Date: Tue, 29 Nov 2022 20:29:55 +0100 Subject: [PATCH] Test related to removing index by alias request and alias creation together with index (#2255) Signed-off-by: Lukasz Soszynski Signed-off-by: Lukasz Soszynski <110241464+lukasz-soszynski-eliatra@users.noreply.github.com> --- .../security/SearchOperationTest.java | 77 ++++++++++++++++++- .../framework/matcher/AliasExistsMatcher.java | 66 ++++++++++++++++ .../framework/matcher/ClusterMatchers.java | 4 + 3 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 src/integrationTest/java/org/opensearch/test/framework/matcher/AliasExistsMatcher.java diff --git a/src/integrationTest/java/org/opensearch/security/SearchOperationTest.java b/src/integrationTest/java/org/opensearch/security/SearchOperationTest.java index 5a48784970..f664ab47cd 100644 --- a/src/integrationTest/java/org/opensearch/security/SearchOperationTest.java +++ b/src/integrationTest/java/org/opensearch/security/SearchOperationTest.java @@ -121,6 +121,7 @@ import static org.hamcrest.Matchers.nullValue; import static org.opensearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions.Type.ADD; import static org.opensearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions.Type.REMOVE; +import static org.opensearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions.Type.REMOVE_INDEX; import static org.opensearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE; import static org.opensearch.client.RequestOptions.DEFAULT; import static org.opensearch.rest.RestRequest.Method.DELETE; @@ -156,6 +157,7 @@ import static org.opensearch.test.framework.matcher.BulkResponseMatchers.bulkResponseContainExceptions; import static org.opensearch.test.framework.matcher.BulkResponseMatchers.failureBulkResponse; import static org.opensearch.test.framework.matcher.BulkResponseMatchers.successBulkResponse; +import static org.opensearch.test.framework.matcher.ClusterMatchers.aliasExists; import static org.opensearch.test.framework.matcher.ClusterMatchers.clusterContainSuccessSnapshot; import static org.opensearch.test.framework.matcher.ClusterMatchers.clusterContainTemplate; import static org.opensearch.test.framework.matcher.ClusterMatchers.clusterContainTemplateWithAlias; @@ -211,6 +213,8 @@ public class SearchOperationTest { public static final String INDEX_NAME_SONG_TRANSCRIPTION_JAZZ = "song-transcription-jazz"; public static final String MUSICAL_INDEX_TEMPLATE = "musical-index-template"; + public static final String ALIAS_CREATE_INDEX_WITH_ALIAS_POSITIVE = "alias_create_index_with_alias_positive"; + public static final String ALIAS_CREATE_INDEX_WITH_ALIAS_NEGATIVE = "alias_create_index_with_alias_negative"; public static final String UNDELETABLE_TEMPLATE_NAME = "undeletable-template-name"; @@ -299,16 +303,19 @@ public class SearchOperationTest { "indices:admin/create", "indices:admin/get", "indices:admin/delete", "indices:admin/close", "indices:admin/close*", "indices:admin/open", "indices:admin/resize", "indices:monitor/stats", "indices:monitor/settings/get", "indices:admin/settings/update", "indices:admin/mapping/put", - "indices:admin/mappings/get", "indices:admin/cache/clear" + "indices:admin/mappings/get", "indices:admin/cache/clear", "indices:admin/aliases" ) .on(INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("*"))); + private static User USER_ALLOWED_TO_CREATE_INDEX = new User("user-allowed-to-create-index") + .roles(new Role("create-index-role").indexPermissions("indices:admin/create").on("*")); + @ClassRule public static final LocalCluster cluster = new LocalCluster.Builder() .clusterManager(ClusterManager.THREE_CLUSTER_MANAGERS).anonymousAuth(false) .authc(AUTHC_HTTPBASIC_INTERNAL) .users(ADMIN_USER, LIMITED_READ_USER, LIMITED_WRITE_USER, DOUBLE_READER_USER, REINDEXING_USER, UPDATE_DELETE_USER, - USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES) + USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES, USER_ALLOWED_TO_CREATE_INDEX) .audit(new AuditConfiguration(true) .compliance(new AuditCompliance().enabled(true)) .filters(new AuditFilters().enabledRest(true).enabledTransport(true)) @@ -362,7 +369,9 @@ public void cleanData() throws ExecutionException, InterruptedException { } } - for(String aliasToBeDeleted : List.of(TEMPORARY_ALIAS_NAME, ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0001, ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0002)) { + List aliasesToBeDeleted = List.of(TEMPORARY_ALIAS_NAME, ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0001, + ALIAS_USED_IN_MUSICAL_INDEX_TEMPLATE_0002, ALIAS_CREATE_INDEX_WITH_ALIAS_POSITIVE, ALIAS_CREATE_INDEX_WITH_ALIAS_NEGATIVE); + for(String aliasToBeDeleted : aliasesToBeDeleted) { if(indices.exists(new IndicesExistsRequest(aliasToBeDeleted)).get().isExists()) { AliasActions aliasAction = new AliasActions(AliasActions.Type.REMOVE).indices(SONG_INDEX_NAME).alias(aliasToBeDeleted); internalClient.admin().indices().aliases(new IndicesAliasesRequest().addAliasAction(aliasAction)).get(); @@ -1838,6 +1847,34 @@ public void deleteIndex_negative() throws IOException { } } + @Test + //required permissions: indices:admin/aliases, indices:admin/delete + public void shouldDeleteIndexByAliasRequest_positive() throws IOException { + String indexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("delete_index_by_alias_request_positive"); + IndexOperationsHelper.createIndex(cluster, indexName); + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES)) { + IndicesAliasesRequest request = new IndicesAliasesRequest().addAliasAction(new AliasActions(REMOVE_INDEX).indices(indexName)); + + var response = restHighLevelClient.indices().updateAliases(request, DEFAULT); + + assertThat(response.isAcknowledged(), is(true)); + assertThat(cluster, not(indexExists(indexName))); + } + auditLogsRule.assertExactlyOne(userAuthenticated(USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES).withRestRequest(POST, "/_aliases")); + auditLogsRule.assertExactly(2, grantedPrivilege(USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES, "IndicesAliasesRequest")); + auditLogsRule.assertExactly(2, auditPredicate(INDEX_EVENT).withEffectiveUser(USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES)); + } + + @Test + public void shouldDeleteIndexByAliasRequest_negative() throws IOException { + String indexName = "delete_index_by_alias_request_negative"; + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES)) { + IndicesAliasesRequest request = new IndicesAliasesRequest().addAliasAction(new AliasActions(REMOVE_INDEX).indices(indexName)); + + assertThatThrownBy(() -> restHighLevelClient.indices().updateAliases(request, DEFAULT), statusException(FORBIDDEN)); + } + } + @Test //required permissions: "indices:admin/get" public void getIndex_positive() throws IOException { @@ -2274,4 +2311,38 @@ public void clearIndexCache_negative() throws IOException { ); } } + + @Test + //required permissions: "indices:admin/create", "indices:admin/aliases" + public void shouldCreateIndexWithAlias_positive() throws IOException { + String indexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("create_index_with_alias_positive"); + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES)) { + CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName) + .alias(new Alias(ALIAS_CREATE_INDEX_WITH_ALIAS_POSITIVE)); + + CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, DEFAULT); + + assertThat(createIndexResponse, isSuccessfulCreateIndexResponse(indexName)); + assertThat(cluster, indexExists(indexName)); + assertThat(internalClient, aliasExists(ALIAS_CREATE_INDEX_WITH_ALIAS_POSITIVE)); + } + auditLogsRule.assertExactlyOne(userAuthenticated(USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES).withRestRequest(PUT, "/index_operations_create_index_with_alias_positive")); + auditLogsRule.assertExactly(2, grantedPrivilege(USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES, "CreateIndexRequest")); + auditLogsRule.assertExactly(2, auditPredicate(INDEX_EVENT).withEffectiveUser(USER_ALLOWED_TO_PERFORM_INDEX_OPERATIONS_ON_SELECTED_INDICES)); + } + + @Test + public void shouldCreateIndexWithAlias_negative() throws IOException { + String indexName = INDICES_ON_WHICH_USER_CAN_PERFORM_INDEX_OPERATIONS_PREFIX.concat("create_index_with_alias_negative"); + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(USER_ALLOWED_TO_CREATE_INDEX)) { + CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName) + .alias(new Alias(ALIAS_CREATE_INDEX_WITH_ALIAS_NEGATIVE)); + + assertThatThrownBy(() -> restHighLevelClient.indices().create(createIndexRequest, DEFAULT), statusException(FORBIDDEN)); + + assertThat(internalClient, not(aliasExists(ALIAS_CREATE_INDEX_WITH_ALIAS_NEGATIVE))); + } + auditLogsRule.assertExactlyOne(userAuthenticated(USER_ALLOWED_TO_CREATE_INDEX).withRestRequest(PUT, "/index_operations_create_index_with_alias_negative")); + auditLogsRule.assertExactlyOne(missingPrivilege(USER_ALLOWED_TO_CREATE_INDEX, "CreateIndexRequest")); + } } diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/AliasExistsMatcher.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/AliasExistsMatcher.java new file mode 100644 index 0000000000..ef2ffb365b --- /dev/null +++ b/src/integrationTest/java/org/opensearch/test/framework/matcher/AliasExistsMatcher.java @@ -0,0 +1,66 @@ +/* +* Copyright OpenSearch Contributors +* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +* +*/ +package org.opensearch.test.framework.matcher; + +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; + +import org.opensearch.action.admin.indices.alias.get.GetAliasesRequest; +import org.opensearch.action.admin.indices.alias.get.GetAliasesResponse; +import org.opensearch.client.Client; +import org.opensearch.cluster.metadata.AliasMetadata; +import org.opensearch.common.collect.ImmutableOpenMap; + +import static java.util.Objects.requireNonNull; +import static java.util.Spliterator.IMMUTABLE; +import static java.util.Spliterators.spliteratorUnknownSize; + +class AliasExistsMatcher extends TypeSafeDiagnosingMatcher { + + private final String aliasName; + + public AliasExistsMatcher(String aliasName) { + this.aliasName = requireNonNull(aliasName, "Alias name is required"); + } + + @Override + protected boolean matchesSafely(Client client, Description mismatchDescription) { + try { + GetAliasesResponse response = client.admin().indices().getAliases(new GetAliasesRequest(aliasName)).get(); + ImmutableOpenMap> aliases = response.getAliases(); + Set actualAliasNames = StreamSupport.stream(spliteratorUnknownSize(aliases.valuesIt(), IMMUTABLE), false) + .flatMap(Collection::stream) + .map(AliasMetadata::getAlias) + .collect(Collectors.toSet()); + if(actualAliasNames.contains(aliasName) == false) { + String existingAliases = String.join(", ", actualAliasNames); + mismatchDescription.appendText(" alias does not exist, defined aliases ").appendValue(existingAliases); + return false; + } + return true; + } catch (InterruptedException | ExecutionException e) { + mismatchDescription.appendText("Error occured during checking if cluster contains alias ") + .appendValue(e); + return false; + } + } + + @Override + public void describeTo(Description description) { + description.appendText("Cluster should contain ").appendValue(aliasName).appendText(" alias"); + } +} diff --git a/src/integrationTest/java/org/opensearch/test/framework/matcher/ClusterMatchers.java b/src/integrationTest/java/org/opensearch/test/framework/matcher/ClusterMatchers.java index 7023301f34..eff1f4c803 100644 --- a/src/integrationTest/java/org/opensearch/test/framework/matcher/ClusterMatchers.java +++ b/src/integrationTest/java/org/opensearch/test/framework/matcher/ClusterMatchers.java @@ -52,6 +52,10 @@ public static Matcher snapshotInClusterDoesNotExists(String repositoryNa return new SnapshotInClusterDoesNotExist(repositoryName, snapshotName); } + public static Matcher aliasExists(String aliasName) { + return new AliasExistsMatcher(aliasName); + } + public static Matcher indexExists(String expectedIndexName) { return new IndexExistsMatcher(expectedIndexName); }