Skip to content
Open
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 @@ -12,17 +12,19 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import org.gridsuite.directory.server.dto.ElementAttributes;
import org.gridsuite.directory.server.services.SupervisionService;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

/**
* @author Kevin Le Saulnier <kevin.lesaulnier at rte-france.com>
*/
@RestController
@RequestMapping(value = "/" + DirectoryApi.API_VERSION + "/supervision")
@RequestMapping(value = "/" + DirectoryApi.API_VERSION + "/supervision", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@Tag(name = "directory-server - Supervision")
public class SupervisionController {
private final SupervisionService service;
Expand All @@ -47,4 +49,17 @@ public ResponseEntity<Void> deleteElements(@RequestParam("ids") List<UUID> eleme
service.deleteElementsByIds(elementsUuid);
return ResponseEntity.ok().build();
}

@PostMapping(value = "/elements/recreate-index", produces = MediaType.TEXT_PLAIN_VALUE)
@Operation(summary = "Recreate the index then reindex data")
@ApiResponse(responseCode = "200", description = "Success of the index recreation & reindexing of elements")
@ApiResponse(responseCode = "500", description = "An error happen while recreating the index.\nAn manual intervention is needing as no details of the error is available.")
public ResponseEntity<Optional<String>> deleteElements() {
if (service.recreateIndexDirectoryElementInfos()) {
return ResponseEntity.ok().build();
} else {
return ResponseEntity.internalServerError().contentType(MediaType.TEXT_PLAIN)
.body(Optional.of("An error happen while re-creating the index. As no details is available an manual intervention is required."));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package org.gridsuite.directory.server.services;

import lombok.extern.slf4j.Slf4j;
import org.gridsuite.directory.server.dto.ElementAttributes;
import org.gridsuite.directory.server.dto.elasticsearch.DirectoryElementInfos;
import org.gridsuite.directory.server.repository.DirectoryElementEntity;
import org.gridsuite.directory.server.repository.DirectoryElementRepository;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.stereotype.Service;

import java.util.List;
Expand All @@ -11,13 +15,17 @@
import static org.gridsuite.directory.server.dto.ElementAttributes.toElementAttributes;

@Service
@Slf4j
public class SupervisionService {
private final DirectoryElementRepository directoryElementRepository;
private final DirectoryRepositoryService repositoryService;
private final ElasticsearchTemplate esTemplate;

public SupervisionService(DirectoryRepositoryService repositoryService, DirectoryElementRepository directoryElementRepository) {
public SupervisionService(DirectoryRepositoryService repositoryService, DirectoryElementRepository directoryElementRepository,
ElasticsearchTemplate elasticsearchTemplate) {
this.repositoryService = repositoryService;
this.directoryElementRepository = directoryElementRepository;
this.esTemplate = elasticsearchTemplate;
}

public List<ElementAttributes> getStashedElementsAttributes() {
Expand All @@ -35,4 +43,28 @@ public void deleteElementsByIds(List<UUID> uuids) {
public List<DirectoryElementEntity> getStashedElements() {
return directoryElementRepository.findAllByStashed(true);
}

public boolean recreateIndexDirectoryElementInfos() {
final IndexOperations idxDirectoryElementInfos = esTemplate.indexOps(DirectoryElementInfos.class);
final String idxDirectoryElementInfosName = idxDirectoryElementInfos.getIndexCoordinates().getIndexName();
log.warn("Recreating ElasticSearch index {}", idxDirectoryElementInfosName);
if (idxDirectoryElementInfos.exists()) {
log.info("Index {} found, delete it.", idxDirectoryElementInfosName);
if (idxDirectoryElementInfos.delete()) {
log.info("Successfully delete index {}", idxDirectoryElementInfosName);
} else {
log.error("A problem seems to happen when deleting index {}...", idxDirectoryElementInfosName);
return false;
}
}
if (idxDirectoryElementInfos.createWithMapping()) {
log.info("Index {} successfully recreated!", idxDirectoryElementInfosName);
} else {
log.info("An error happen while re-creating index {}...", idxDirectoryElementInfosName);
return false;
}
log.info("Re-indexing all elements of {}", idxDirectoryElementInfosName);
repositoryService.reindexAllElements();
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,30 @@
*/
package org.gridsuite.directory.server;

import org.gridsuite.directory.server.dto.elasticsearch.DirectoryElementInfos;
import org.gridsuite.directory.server.elasticsearch.DirectoryElementInfosRepository;
import org.gridsuite.directory.server.repository.DirectoryElementEntity;
import org.gridsuite.directory.server.repository.DirectoryElementRepository;
import org.gridsuite.directory.server.services.DirectoryRepositoryService;
import org.gridsuite.directory.server.services.SupervisionService;
import org.gridsuite.directory.server.utils.elasticsearch.DisableElasticsearch;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;

import java.time.Instant;
import java.util.List;
import java.util.UUID;

import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;

Expand All @@ -39,6 +48,12 @@ class SupervisionTest {
@MockBean
DirectoryElementInfosRepository directoryElementInfosRepository;

@SpyBean
DirectoryRepositoryService repositoryService;

@MockBean(name = "elasticsearchOperations")
ElasticsearchTemplate elasticsearchTemplate;

List<DirectoryElementEntity> expectedElements = List.of(
new DirectoryElementEntity(UUID.randomUUID(), UUID.randomUUID(), "dir1", "DIRECTORY", "user1", null, Instant.now(), Instant.now(), "user1", true, Instant.now()),
new DirectoryElementEntity(UUID.randomUUID(), UUID.randomUUID(), "filter1", "FILTER", "user1", null, Instant.now(), Instant.now(), "user1", true, Instant.now()),
Expand All @@ -57,14 +72,52 @@ void testGetStashedElements() {
void testDeleteElements() {
List<UUID> uuidsToDelete = List.of(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID());
supervisionService.deleteElementsByIds(uuidsToDelete);

verify(repositoryService).deleteElements(uuidsToDelete);
verify(directoryElementRepository, times(1)).deleteAllById(uuidsToDelete);
verify(directoryElementInfosRepository, times(1)).deleteAllById(uuidsToDelete);
}

@ParameterizedTest
@CsvSource(nullValues = { "null" }, value = {
"false, null, true, true", //not existant, juste recreate
"false, null, false, false", //not existant, error while creating
"true, true, true, true", //delete + create + reindex OK
"true, true, false, false", //delete, but error while creating
"true, false, null, false" //exist, but error while deleting
})
void testReindexElements(final boolean exists, final Boolean delete, final Boolean create, final boolean result) {
final IndexOperations idxOps = mock(IndexOperations.class);
when(elasticsearchTemplate.indexOps(any(Class.class))).thenReturn(idxOps);
when(idxOps.getIndexCoordinates()).thenReturn(IndexCoordinates.of("test-mock-index")); //for logs
when(idxOps.exists()).thenReturn(exists);
if (delete != null) {
when(idxOps.delete()).thenReturn(delete);
}
if (create != null) {
when(idxOps.createWithMapping()).thenReturn(create);
}
doNothing().when(repositoryService).reindexAllElements(); //intercept call
assertThat(supervisionService.recreateIndexDirectoryElementInfos()).as("service call result").isEqualTo(result);
verify(elasticsearchTemplate).indexOps(DirectoryElementInfos.class);
verify(idxOps, atLeastOnce()).getIndexCoordinates();
verify(idxOps).exists();
if (delete != null) {
verify(idxOps).delete();
}
if (create != null) {
verify(idxOps).createWithMapping();
}
if (create == Boolean.TRUE) {
verify(repositoryService).reindexAllElements();
}
verifyNoMoreInteractions(idxOps);
}

@AfterEach
public void verifyNoMoreInteractionsMocks() {
verifyNoMoreInteractions(directoryElementRepository);
verifyNoMoreInteractions(directoryElementInfosRepository);
verifyNoMoreInteractions(repositoryService);
verifyNoMoreInteractions(elasticsearchTemplate);
}
}