Skip to content
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
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@
<properties>
<gridsuite-dependencies.version>42.0.0</gridsuite-dependencies.version>
<!-- FIXME to remove at next upgrade of gridsuite-dependencies -->
<gridsuite-computation.version>1.0.0</gridsuite-computation.version>
<gridsuite-computation.version>1.1.0</gridsuite-computation.version>
<!-- FIXME to remove at next upgrade of powsybl-ws-dependencies -->
<powsybl-ws-commons.version>1.28.0</powsybl-ws-commons.version>
<powsybl-ws-commons.version>1.28.1</powsybl-ws-commons.version>

<jib.from.image>powsybl/java-dynawo:3.0.0</jib.from.image>
<liquibase-hibernate-package>org.gridsuite.dynamicsecurityanalysis.server</liquibase-hibernate-package>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.gridsuite.dynamicsecurityanalysis.server.service.DynamicSecurityAnalysisService;
import org.gridsuite.dynamicsecurityanalysis.server.service.ParametersService;
import org.gridsuite.dynamicsecurityanalysis.server.service.contexts.DynamicSecurityAnalysisRunContext;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
Expand Down Expand Up @@ -61,6 +62,7 @@ public ResponseEntity<UUID> run(@PathVariable("networkUuid") UUID networkUuid,
@RequestParam(name = REPORTER_ID_HEADER, required = false) String reportName,
@RequestParam(name = REPORT_TYPE_HEADER, required = false, defaultValue = "DynamicSecurityAnalysis") String reportType,
@RequestParam(name = HEADER_PROVIDER, required = false) String provider,
@RequestParam(name = "debug", required = false, defaultValue = "false") boolean debug,
@RequestParam(name = "dynamicSimulationResultUuid") UUID dynamicSimulationResultUuid,
@RequestParam(name = "parametersUuid") UUID parametersUuid,
@RequestHeader(HEADER_USER_ID) String userId) {
Expand All @@ -73,7 +75,8 @@ public ResponseEntity<UUID> run(@PathVariable("networkUuid") UUID networkUuid,
ReportInfos.builder().reportUuid(reportId).reporterId(reportName).computationType(reportType).build(),
userId,
dynamicSimulationResultUuid,
parametersUuid);
parametersUuid,
debug);

UUID resultUuid = dynamicSecurityAnalysisService.runAndSaveResult(dynamicSecurityAnalysisRunContext);
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(resultUuid);
Expand Down Expand Up @@ -138,4 +141,13 @@ public ResponseEntity<List<String>> getProviders() {
public ResponseEntity<String> getDefaultProvider() {
return ResponseEntity.ok().body(dynamicSecurityAnalysisService.getDefaultProvider());
}

@GetMapping(value = "/results/{resultUuid}/download-debug-file", produces = "application/json")
@Operation(summary = "Download a dynamic security analysis debug file")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Dynamic security analysis debug file"),
@ApiResponse(responseCode = "404", description = "Dynamic security analysis debug file has not been found")})
public ResponseEntity<Resource> downloadDebugFile(@Parameter(description = "Result UUID") @PathVariable("resultUuid") UUID resultUuid) {
return dynamicSecurityAnalysisService.downloadDebugFile(resultUuid);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package org.gridsuite.dynamicsecurityanalysis.server.entities;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
Expand All @@ -22,14 +23,10 @@
@Setter
@Table(name = "dynamic_security_analysis_result")
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class DynamicSecurityAnalysisResultEntity {

public DynamicSecurityAnalysisResultEntity(UUID id, DynamicSecurityAnalysisStatus status) {
this.id = id;
this.status = status;
}

@Id
@Column(name = "result_uuid")
private UUID id;
Expand All @@ -38,4 +35,7 @@ public DynamicSecurityAnalysisResultEntity(UUID id, DynamicSecurityAnalysisStatu
@Enumerated(EnumType.STRING)
private DynamicSecurityAnalysisStatus status;

@Column(name = "debugFileLocation")
private String debugFileLocation;

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

import org.gridsuite.dynamicsecurityanalysis.server.entities.DynamicSecurityAnalysisResultEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.UUID;
Expand All @@ -18,4 +21,8 @@
*/
@Repository
public interface DynamicSecurityAnalysisResultRepository extends JpaRepository<DynamicSecurityAnalysisResultEntity, UUID> {
@Modifying
@Query("UPDATE DynamicSecurityAnalysisResultEntity r SET r.debugFileLocation = :debugFileLocation WHERE r.id = :resultUuid")
int updateDebugFileLocation(@Param("resultUuid") UUID resultUuid, @Param("debugFileLocation") String debugFileLocation);

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

package org.gridsuite.dynamicsecurityanalysis.server.service;

import jakarta.transaction.Transactional;
import org.gridsuite.computation.service.AbstractComputationResultService;
import org.gridsuite.dynamicsecurityanalysis.server.DynamicSecurityAnalysisException;
import org.gridsuite.dynamicsecurityanalysis.server.dto.DynamicSecurityAnalysisStatus;
Expand All @@ -16,6 +15,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
Expand Down Expand Up @@ -43,7 +43,7 @@ public DynamicSecurityAnalysisResultService(DynamicSecurityAnalysisResultReposit
public void insertStatus(List<UUID> resultUuids, DynamicSecurityAnalysisStatus status) {
Objects.requireNonNull(resultUuids);
resultRepository.saveAll(resultUuids.stream()
.map(uuid -> new DynamicSecurityAnalysisResultEntity(uuid, status)).toList());
.map(uuid -> new DynamicSecurityAnalysisResultEntity(uuid, status, null)).toList());
}

@Transactional
Expand All @@ -65,6 +65,16 @@ public void updateResult(UUID resultUuid, DynamicSecurityAnalysisStatus status)
}

@Override
@Transactional
public void saveDebugFileLocation(UUID resultUuid, String debugFilePath) {
resultRepository.findById(resultUuid).ifPresentOrElse(
(var resultEntity) -> resultRepository.updateDebugFileLocation(resultUuid, debugFilePath),
() -> resultRepository.save(new DynamicSecurityAnalysisResultEntity(resultUuid, DynamicSecurityAnalysisStatus.NOT_DONE, debugFilePath))
);
}

@Override
@Transactional
public void delete(UUID resultUuid) {
Objects.requireNonNull(resultUuid);
resultRepository.deleteById(resultUuid);
Expand All @@ -77,10 +87,20 @@ public void deleteAll() {
}

@Override
@Transactional(readOnly = true)
public DynamicSecurityAnalysisStatus findStatus(UUID resultUuid) {
Objects.requireNonNull(resultUuid);
return resultRepository.findById(resultUuid)
.map(DynamicSecurityAnalysisResultEntity::getStatus)
.orElse(null);
}

@Override
@Transactional(readOnly = true)
public String findDebugFileLocation(UUID resultUuid) {
Objects.requireNonNull(resultUuid);
return resultRepository.findById(resultUuid)
.map(DynamicSecurityAnalysisResultEntity::getDebugFileLocation)
.orElse(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.powsybl.network.store.client.NetworkStoreService;
import com.powsybl.security.dynamic.DynamicSecurityAnalysisProvider;
import org.gridsuite.computation.s3.ComputationS3Service;
import org.gridsuite.computation.service.AbstractComputationService;
import org.gridsuite.computation.service.NotificationService;
import org.gridsuite.computation.service.UuidGeneratorService;
Expand Down Expand Up @@ -36,8 +37,9 @@ public DynamicSecurityAnalysisService(
ObjectMapper objectMapper,
UuidGeneratorService uuidGeneratorService,
DynamicSecurityAnalysisResultService dynamicSecurityAnalysisResultService,
ComputationS3Service computationS3Service,
@Value("${dynamic-security-analysis.default-provider}") String defaultProvider) {
super(notificationService, dynamicSecurityAnalysisResultService, objectMapper, uuidGeneratorService, defaultProvider);
super(notificationService, dynamicSecurityAnalysisResultService, computationS3Service, objectMapper, uuidGeneratorService, defaultProvider);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.powsybl.security.dynamic.DynamicSecurityAnalysisRunParameters;
import com.powsybl.security.results.PostContingencyResult;
import org.apache.commons.collections4.CollectionUtils;
import org.gridsuite.computation.s3.ComputationS3Service;
import org.gridsuite.computation.service.*;
import org.gridsuite.dynamicsecurityanalysis.server.DynamicSecurityAnalysisException;
import org.gridsuite.dynamicsecurityanalysis.server.dto.DynamicSecurityAnalysisStatus;
Expand Down Expand Up @@ -82,10 +83,11 @@ public DynamicSecurityAnalysisWorkerService(NetworkStoreService networkStoreServ
DynamicSecurityAnalysisObserver observer,
ObjectMapper objectMapper,
DynamicSecurityAnalysisResultService dynamicSecurityAnalysisResultService,
ComputationS3Service computationS3Service,
DynamicSimulationClient dynamicSimulationClient,
ActionsClient actionsClient,
ParametersService parametersService) {
super(networkStoreService, notificationService, reportService, dynamicSecurityAnalysisResultService, executionService, observer, objectMapper);
super(networkStoreService, notificationService, reportService, dynamicSecurityAnalysisResultService, computationS3Service, executionService, observer, objectMapper);
this.dynamicSimulationClient = Objects.requireNonNull(dynamicSimulationClient);
this.actionsClient = Objects.requireNonNull(actionsClient);
this.parametersService = Objects.requireNonNull(parametersService);
Expand Down Expand Up @@ -167,6 +169,9 @@ public void preRun(DynamicSecurityAnalysisRunContext runContext) {

// create a new dynamic security analysis parameters
DynamicSecurityAnalysisParameters parameters = new DynamicSecurityAnalysisParameters();
if (runContext.getDebugDir() != null) {
parameters.setDebugDir(runContext.getDebugDir().toString());
}
parameters.setDynamicSimulationParameters(dynamicSimulationParameters);

// set start and stop times
Expand Down Expand Up @@ -251,33 +256,36 @@ protected void clean(AbstractResultContext<DynamicSecurityAnalysisRunContext> re
super.clean(resultContext);
// clean working directory
Path workDir = resultContext.getRunContext().getWorkDir();
removeWorkingDirectory(workDir);
removeDirectory(workDir);
}

@Override
protected void processDebug(AbstractResultContext<DynamicSecurityAnalysisRunContext> resultContext) {
// copy all content from working directory into debug directory
DynamicSecurityAnalysisRunContext runContext = resultContext.getRunContext();
if (runContext.getWorkDir() != null && runContext.getDebugDir() != null) {
try {
FileUtil.copyDir(runContext.getWorkDir(), runContext.getDebugDir());
} catch (IOException e) {
LOGGER.error("{}: Error occurred while copying directory {} to directory {} => {}",
getComputationType(), runContext.getWorkDir().toAbsolutePath(), runContext.getDebugDir().toAbsolutePath(), e.getMessage());
}
}
super.processDebug(resultContext);
}

private Path createWorkingDirectory() {
Path workDir;
Path localDir = getComputationManager().getLocalDir();
try {
workDir = Files.createTempDirectory(localDir, "dynamic_security_analysis_");
workDir = Files.createTempDirectory(localDir, buildComputationDirPrefix());
} catch (IOException e) {
throw new DynamicSecurityAnalysisException(DUMP_FILE_ERROR, String.format("Error occurred while creating a working directory inside the local directory %s",
localDir.toAbsolutePath()));
}
return workDir;
}

private void removeWorkingDirectory(Path workDir) {
if (workDir != null) {
try {
FileUtil.removeDir(workDir);
} catch (IOException e) {
LOGGER.error(String.format("%s: Error occurred while cleaning working directory at %s", getComputationType(), workDir.toAbsolutePath()), e);
}
} else {
LOGGER.info("{}: No working directory to clean", getComputationType());
}
}

// --- TODO remove these reports when powsybl-dynawo implements --- //
private static void enrichContingenciesTimelineReport(SecurityAnalysisReport securityAnalysisReport, ReportNode reportNode) {
for (PostContingencyResult postContingencyResult : securityAnalysisReport.getResult().getPostContingencyResults()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.powsybl.commons.io.FileUtil;
import com.powsybl.dynamicsimulation.DynamicSimulationParameters;
import com.powsybl.dynamicsimulation.DynamicSimulationProvider;
import com.powsybl.dynawo.DumpFileParameters;
Expand Down Expand Up @@ -57,7 +56,8 @@ public ParametersService(@Value("${dynamic-security-analysis.default-provider}")
public DynamicSecurityAnalysisRunContext createRunContext(UUID networkUuid, String variantId, String receiver,
String provider, ReportInfos reportInfos, String userId,
UUID dynamicSimulationResultUuid,
UUID dynamicSecurityAnalysisParametersUuid) {
UUID dynamicSecurityAnalysisParametersUuid,
boolean debug) {

// get parameters from the local database
DynamicSecurityAnalysisParametersInfos dynamicSecurityAnalysisParametersInfos = getParameters(dynamicSecurityAnalysisParametersUuid);
Expand All @@ -70,6 +70,7 @@ public DynamicSecurityAnalysisRunContext createRunContext(UUID networkUuid, Stri
.reportInfos(reportInfos)
.userId(userId)
.parameters(dynamicSecurityAnalysisParametersInfos)
.debug(debug)
.build();
runContext.setDynamicSimulationResultUuid(dynamicSimulationResultUuid);

Expand All @@ -93,11 +94,9 @@ public DynamicSecurityAnalysisRunContext createRunContext(UUID networkUuid, Stri
// --- Dynamic simulation result related methods --- //

public void setupDumpParameters(Path workDir, DynamicSimulationParameters dynamicSimulationParameters, byte[] zippedOutputState) {
Path dumpDir = workDir.resolve("dump");
FileUtil.createDirectory(dumpDir);
Path dumpFile = unZipDumpFile(dumpDir, zippedOutputState);
Path dumpFile = unZipDumpFile(workDir, zippedOutputState);
DynawoSimulationParameters dynawoSimulationParameters = dynamicSimulationParameters.getExtension(DynawoSimulationParameters.class);
dynawoSimulationParameters.setDumpFileParameters(DumpFileParameters.createImportDumpFileParameters(dumpDir, dumpFile.getFileName().toString()));
dynawoSimulationParameters.setDumpFileParameters(DumpFileParameters.createImportDumpFileParameters(workDir, dumpFile.getFileName().toString()));
}

private Path unZipDumpFile(Path dumpDir, byte[] zippedOutputState) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public static DynamicSecurityAnalysisResultContext fromMessage(Message<String> m
String reporterId = (String) headers.get(REPORTER_ID_HEADER);
String reportType = (String) headers.get(REPORT_TYPE_HEADER);
String userId = (String) headers.get(HEADER_USER_ID);
Boolean debug = (Boolean) headers.get(HEADER_DEBUG);

DynamicSecurityAnalysisRunContext runContext = DynamicSecurityAnalysisRunContext.builder()
.networkUuid(networkUuid)
Expand All @@ -64,6 +65,7 @@ public static DynamicSecurityAnalysisResultContext fromMessage(Message<String> m
.reportInfos(ReportInfos.builder().reportUuid(reportUuid).reporterId(reporterId).computationType(reportType).build())
.userId(userId)
.parameters(parametersInfos)
.debug(debug)
.build();

// specific headers for dynamic simulation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ public class DynamicSecurityAnalysisRunContext extends AbstractComputationRunCon

@Builder
public DynamicSecurityAnalysisRunContext(UUID networkUuid, String variantId, String receiver, String provider,
ReportInfos reportInfos, String userId, DynamicSecurityAnalysisParametersInfos parameters) {
super(networkUuid, variantId, receiver, reportInfos, userId, provider, parameters);
ReportInfos reportInfos, String userId, DynamicSecurityAnalysisParametersInfos parameters, Boolean debug) {
super(networkUuid, variantId, receiver, reportInfos, userId, provider, parameters, debug);
}
}

3 changes: 3 additions & 0 deletions src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ server:
spring:
rabbitmq:
addresses: localhost
cloud:
aws:
endpoint: http://localhost:19000

powsybl-ws:
database:
Expand Down
10 changes: 9 additions & 1 deletion src/main/resources/config/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ spring:
max-attempts: 1
publishRun-out-0:
destination: ${powsybl-ws.rabbitmq.destination.prefix:}dsa.run
publishDebug-out-0:
destination: ${powsybl-ws.rabbitmq.destination.prefix:}dsa.debug
publishResult-out-0:
destination: ${powsybl-ws.rabbitmq.destination.prefix:}dsa.result
consumeCancel-in-0:
Expand All @@ -25,7 +27,7 @@ spring:
destination: ${powsybl-ws.rabbitmq.destination.prefix:}dsa.stopped
publishCancelFailed-out-0:
destination: ${powsybl-ws.rabbitmq.destination.prefix:}dsa.cancelfailed
output-bindings: publishRun-out-0;publishResult-out-0;publishCancel-out-0;publishStopped-out-0;publishCancelFailed-out-0
output-bindings: publishRun-out-0;publishDebug-out-0;publishResult-out-0;publishCancel-out-0;publishStopped-out-0;publishCancelFailed-out-0
rabbit:
bindings:
consumeRun-in-0:
Expand All @@ -38,6 +40,12 @@ spring:
enabled: true
delivery-limit: 2

computation:
s3:
enabled: true

debug-subpath: debug

powsybl-ws:
database:
name: dynamicsecurityanalysis
Expand Down
Loading