diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/api/IndexProvisionApi.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/api/IndexProvisionApi.java index f17b8810b2befd4748fe7c81daade7fce9e7d918..6979e0d99c830f9693adb8fe551eea2b3f3a269a 100644 --- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/api/IndexProvisionApi.java +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/api/IndexProvisionApi.java @@ -36,6 +36,7 @@ public class IndexProvisionApi { @PreAuthorize("@authorizationFilter.hasPermission('" + SearchServiceRole.ADMIN + "')") @PostMapping(path = "/aliases") public ResponseEntity<IndexAliasesResult> createIndexAliases() { - return new ResponseEntity<>(indexAliasService.createIndexAliasesForAll(), HttpStatus.OK); + IndexAliasesResult result = indexAliasService.createIndexAliasesForAll(); + return new ResponseEntity<>(result, HttpStatus.OK); } } diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/IndexAliasServiceImpl.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/IndexAliasServiceImpl.java index e09e98bced5a036b339b4748db16985d6ea4f5c4..24a88f22116e7b910ef16c12e28f1b5e5e5acaf4 100644 --- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/IndexAliasServiceImpl.java +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/IndexAliasServiceImpl.java @@ -19,12 +19,17 @@ import com.google.api.client.util.Strings; import org.apache.http.HttpStatus; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.client.GetAliasesResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.cluster.metadata.AliasMetadata; import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.search.aggregations.bucket.terms.Terms; +import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; +import org.elasticsearch.search.builder.SearchSourceBuilder; import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; import org.opengroup.osdu.core.common.model.http.AppException; import org.opengroup.osdu.core.common.search.ElasticIndexNameResolver; @@ -39,8 +44,6 @@ import java.util.stream.Collectors; @Component public class IndexAliasServiceImpl implements IndexAliasService{ - @Inject - private StorageService storageService; @Inject private ElasticIndexNameResolver elasticIndexNameResolver; @Inject @@ -50,19 +53,9 @@ public class IndexAliasServiceImpl implements IndexAliasService{ @Override public IndexAliasesResult createIndexAliasesForAll() { - List<String> allKinds = null; - try { - allKinds = storageService.getAllKinds(); - } catch (Exception e) { - jaxRsDpsLog.error("storage service all kinds request failed", e); - throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "storage service cannot respond with all kinds", "an unknown error has occurred.", e); - } - if (Objects.isNull(allKinds)) { - throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "storage service cannot respond with all kinds", "index aliases provision failed"); - } - IndexAliasesResult result = new IndexAliasesResult(); try (RestHighLevelClient restClient = this.elasticClientHandler.createRestClient()) { + List<String> allKinds = getAllKinds(restClient); Set<String> allExistingAliases = getAllExistingAliases(restClient); for (String kind : allKinds) { String alias = elasticIndexNameResolver.getIndexAliasFromKind(kind); @@ -102,14 +95,11 @@ public class IndexAliasServiceImpl implements IndexAliasService{ Map<String, String> indexAliasMap = new HashMap<>(); indexAliasMap.put(actualIndexName, elasticIndexNameResolver.getIndexAliasFromKind(kind)); - if(actualIndexName.equals(elasticIndexNameResolver.getIndexNameFromKind(kind))) { - // We create alias for major version kind only if the actual index name matches the name converted from the kind - String kindWithMajorVersion = getKindWithMajorVersion(kind); - if(elasticIndexNameResolver.isIndexAliasSupported(kindWithMajorVersion)) { - String index = elasticIndexNameResolver.getIndexNameFromKind(kindWithMajorVersion); - String alias = elasticIndexNameResolver.getIndexAliasFromKind(kindWithMajorVersion); - indexAliasMap.put(index, alias); - } + String kindWithMajorVersion = getKindWithMajorVersion(kind); + if(elasticIndexNameResolver.isIndexAliasSupported(kindWithMajorVersion)) { + String index = elasticIndexNameResolver.getIndexNameFromKind(kindWithMajorVersion); + String alias = elasticIndexNameResolver.getIndexAliasFromKind(kindWithMajorVersion); + indexAliasMap.put(index, alias); } boolean ok = true; @@ -194,4 +184,19 @@ public class IndexAliasServiceImpl implements IndexAliasService{ } return null; } + + private List<String> getAllKinds(RestHighLevelClient client) throws IOException { + List<String> kinds; + SearchRequest elasticSearchRequest = new SearchRequest("_all"); + TermsAggregationBuilder termsAggregationBuilder = new TermsAggregationBuilder("kinds"); + termsAggregationBuilder.field("kind"); + termsAggregationBuilder.size(10000); + SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); + sourceBuilder.aggregation(termsAggregationBuilder); + elasticSearchRequest.source(sourceBuilder); + SearchResponse searchResponse = client.search(elasticSearchRequest, RequestOptions.DEFAULT); + Terms kindBuckets = searchResponse.getAggregations().get("kinds"); + kinds = kindBuckets.getBuckets().stream().map(bucket -> bucket.getKey().toString()).collect(Collectors.toList()); + return kinds; + } } diff --git a/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/IndexAliasServiceImplTest.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/IndexAliasServiceImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..94e074e6fd96194a8a19d5c1acbc02b5dd7216f2 --- /dev/null +++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/IndexAliasServiceImplTest.java @@ -0,0 +1,176 @@ +package org.opengroup.osdu.indexer.service; + +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; +import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.action.support.master.AcknowledgedResponse; +import org.elasticsearch.client.GetAliasesResponse; +import org.elasticsearch.client.IndicesClient; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.cluster.metadata.AliasMetadata; +import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.search.aggregations.Aggregations; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; +import org.opengroup.osdu.core.common.search.ElasticIndexNameResolver; +import org.opengroup.osdu.indexer.model.IndexAliasesResult; +import org.opengroup.osdu.indexer.service.mock.BucketMock; +import org.opengroup.osdu.indexer.service.mock.TermMock; +import org.opengroup.osdu.indexer.util.ElasticClientHandler; +import org.powermock.api.mockito.PowerMockito; +import org.springframework.context.annotation.Lazy; + +import java.io.IOException; +import java.util.*; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +@RunWith(MockitoJUnitRunner.class) +public class IndexAliasServiceImplTest { + @Mock + private ElasticClientHandler elasticClientHandler; + @Mock + private ElasticIndexNameResolver elasticIndexNameResolver; + @Mock + @Lazy + private JaxRsDpsLog log; + @InjectMocks + private IndexAliasServiceImpl sut; + + private RestHighLevelClient restHighLevelClient; + private IndicesClient indicesClient; + private GetAliasesResponse getAliasesResponse, getAliasesNotFoundResponse; + + + private static String kind = "common:welldb:wellbore:1.2.0"; + private static String index = "common-welldb-wellbore-1.2.0"; + private static String alias = "a1234567890"; + + @Before + public void setup() { + initMocks(this); + indicesClient = PowerMockito.mock(IndicesClient.class); + restHighLevelClient = PowerMockito.mock(RestHighLevelClient.class); + getAliasesResponse = PowerMockito.mock(GetAliasesResponse.class); + getAliasesNotFoundResponse = PowerMockito.mock(GetAliasesResponse.class); + + } + + @Test + public void createIndexAlias_test_when_index_name_is_not_alias() throws IOException { + AcknowledgedResponse updateAliasesResponse = new AcknowledgedResponse(true); + when(elasticIndexNameResolver.getIndexNameFromKind(any())).thenReturn(index); + when(elasticIndexNameResolver.getIndexAliasFromKind(any())).thenReturn(alias); + when(elasticIndexNameResolver.isIndexAliasSupported(any())).thenReturn(true); + when(restHighLevelClient.indices()).thenReturn(indicesClient); + when(indicesClient.getAlias(any(GetAliasesRequest.class), any(RequestOptions.class))).thenReturn(getAliasesNotFoundResponse); + when(getAliasesNotFoundResponse.status()).thenReturn(RestStatus.NOT_FOUND); + when(indicesClient.updateAliases(any(IndicesAliasesRequest.class), any(RequestOptions.class))).thenReturn(updateAliasesResponse); + + boolean ok = sut.createIndexAlias(restHighLevelClient, kind); + Assert.assertTrue(ok); + } + + @Test + public void createIndexAlias_test_when_index_name_is_alias() throws IOException { + Map<String, Set<AliasMetadata>> aliases = new HashMap<>(); + Set<AliasMetadata> aliasMetadataSet = new HashSet<>(); + aliasMetadataSet.add(AliasMetadata.builder(index).build()); + aliases.put(index + "_123456789", aliasMetadataSet); + + AcknowledgedResponse updateAliasesResponse = new AcknowledgedResponse(true); + when(elasticIndexNameResolver.getIndexNameFromKind(any())).thenReturn(index); + when(elasticIndexNameResolver.getIndexAliasFromKind(any())).thenReturn(alias); + when(elasticIndexNameResolver.isIndexAliasSupported(any())).thenReturn(true); + when(restHighLevelClient.indices()).thenReturn(indicesClient); + when(indicesClient.getAlias(any(GetAliasesRequest.class), any(RequestOptions.class))).thenReturn(getAliasesResponse); + when(getAliasesResponse.status()).thenReturn(RestStatus.OK); + when(getAliasesResponse.getAliases()).thenReturn(aliases); + when(indicesClient.updateAliases(any(IndicesAliasesRequest.class), any(RequestOptions.class))).thenReturn(updateAliasesResponse); + + boolean ok = sut.createIndexAlias(restHighLevelClient, kind); + Assert.assertTrue(ok); + } + + @Test + public void createIndexAlias_test_when_updateAliases_fails() throws IOException { + AcknowledgedResponse updateAliasesResponse = new AcknowledgedResponse(false); + when(elasticIndexNameResolver.getIndexNameFromKind(any())).thenReturn(index); + when(elasticIndexNameResolver.getIndexAliasFromKind(any())).thenReturn(alias); + when(elasticIndexNameResolver.isIndexAliasSupported(any())).thenReturn(true); + when(restHighLevelClient.indices()).thenReturn(indicesClient); + when(indicesClient.getAlias(any(GetAliasesRequest.class), any(RequestOptions.class))).thenReturn(getAliasesNotFoundResponse); + when(getAliasesNotFoundResponse.status()).thenReturn(RestStatus.NOT_FOUND); + when(indicesClient.updateAliases(any(IndicesAliasesRequest.class), any(RequestOptions.class))).thenReturn(updateAliasesResponse); + + boolean ok = sut.createIndexAlias(restHighLevelClient, kind); + Assert.assertFalse(ok); + } + + @Test + public void createIndexAlias_test_when_updateAliases_throws_exception() throws IOException { + when(elasticIndexNameResolver.getIndexNameFromKind(any())).thenReturn(index); + when(elasticIndexNameResolver.getIndexAliasFromKind(any())).thenReturn(alias); + when(elasticIndexNameResolver.isIndexAliasSupported(any())).thenReturn(true); + when(restHighLevelClient.indices()).thenReturn(indicesClient); + when(indicesClient.getAlias(any(GetAliasesRequest.class), any(RequestOptions.class))).thenReturn(getAliasesNotFoundResponse); + when(getAliasesNotFoundResponse.status()).thenReturn(RestStatus.NOT_FOUND); + when(indicesClient.updateAliases(any(IndicesAliasesRequest.class), any(RequestOptions.class))).thenThrow(IOException.class); + + boolean ok = sut.createIndexAlias(restHighLevelClient, kind); + Assert.assertFalse(ok); + } + + @Test + public void createIndexAliasesForAll_test() throws IOException { + String unsupportedKind = "common:welldb:wellbore:1"; + String unsupportedIndex = unsupportedKind.replace(":", "-"); + + SearchResponse searchResponse = PowerMockito.mock(SearchResponse.class); + Aggregations aggregations = PowerMockito.mock(Aggregations.class); + TermMock terms = PowerMockito.mock(TermMock.class); + BucketMock bucket = PowerMockito.mock(BucketMock.class); + BucketMock bucket2 = PowerMockito.mock(BucketMock.class); + List<BucketMock> bucketList = Arrays.asList(bucket, bucket, bucket2); + AcknowledgedResponse updateAliasesResponse = new AcknowledgedResponse(true); + when(elasticIndexNameResolver.getIndexNameFromKind(any())) + .thenAnswer(invocation ->{ + String argument = invocation.getArgument(0); + return argument.replace(":", "-"); + }); + when(elasticIndexNameResolver.getIndexAliasFromKind(any())).thenReturn(alias); + when(elasticIndexNameResolver.isIndexAliasSupported(any())) + .thenAnswer(invocation ->{ + String argument = invocation.getArgument(0); + return !unsupportedKind.equals(argument); + }); + when(elasticClientHandler.createRestClient()).thenReturn(restHighLevelClient); + when(restHighLevelClient.indices()).thenReturn(indicesClient); + when(restHighLevelClient.search(any(SearchRequest.class), any(RequestOptions.class))).thenReturn(searchResponse); + when(searchResponse.getAggregations()).thenReturn(aggregations); + when(aggregations.get(anyString())).thenReturn(terms); + when(terms.getBuckets()).thenReturn(bucketList); + when(bucket.getKey()).thenReturn(kind); + when(bucket2.getKey()).thenReturn(unsupportedKind); + when(indicesClient.getAlias(any(GetAliasesRequest.class), any(RequestOptions.class))).thenReturn(getAliasesNotFoundResponse); + when(getAliasesNotFoundResponse.status()).thenReturn(RestStatus.NOT_FOUND); + when(indicesClient.updateAliases(any(IndicesAliasesRequest.class), any(RequestOptions.class))).thenReturn(updateAliasesResponse); + + IndexAliasesResult result = sut.createIndexAliasesForAll(); + Assert.assertEquals(2,result.getIndicesWithAliases().size()); + Assert.assertEquals(index, result.getIndicesWithAliases().get(0)); + Assert.assertEquals(1,result.getIndicesWithoutAliases().size()); + Assert.assertEquals(unsupportedIndex, result.getIndicesWithoutAliases().get(0)); + } +} diff --git a/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/mock/BucketMock.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/mock/BucketMock.java new file mode 100644 index 0000000000000000000000000000000000000000..8b276d22c4d9c7b511de7e2909ca34385996808b --- /dev/null +++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/mock/BucketMock.java @@ -0,0 +1,44 @@ +package org.opengroup.osdu.indexer.service.mock; + +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.search.aggregations.Aggregations; +import org.elasticsearch.search.aggregations.bucket.terms.Terms; + +import java.io.IOException; + +public class BucketMock implements Terms.Bucket { + @Override + public Number getKeyAsNumber() { + return null; + } + + @Override + public long getDocCountError() { + return 0; + } + + @Override + public Object getKey() { + return null; + } + + @Override + public String getKeyAsString() { + return null; + } + + @Override + public long getDocCount() { + return 0; + } + + @Override + public Aggregations getAggregations() { + return null; + } + + @Override + public XContentBuilder toXContent(XContentBuilder xContentBuilder, Params params) throws IOException { + return null; + } +} diff --git a/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/mock/TermMock.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/mock/TermMock.java new file mode 100644 index 0000000000000000000000000000000000000000..8af60e8a9cf488e18db5246667a30f0ca50d82d8 --- /dev/null +++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/mock/TermMock.java @@ -0,0 +1,50 @@ +package org.opengroup.osdu.indexer.service.mock; + +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.search.aggregations.bucket.terms.Terms; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +public class TermMock implements Terms { + @Override + public List<BucketMock> getBuckets() { + return null; + } + + @Override + public Bucket getBucketByKey(String s) { + return null; + } + + @Override + public long getDocCountError() { + return 0; + } + + @Override + public long getSumOfOtherDocCounts() { + return 0; + } + + @Override + public String getName() { + return null; + } + + @Override + public String getType() { + return null; + } + + @Override + public Map<String, Object> getMetadata() { + return null; + } + + @Override + public XContentBuilder toXContent(XContentBuilder xContentBuilder, Params params) throws IOException { + return null; + } +}