-
Notifications
You must be signed in to change notification settings - Fork 1
Add debug mode to process execution #40
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
Changes from all commits
d531a4e
c424ca0
d52722d
4ccd728
76f4b47
1656f57
ffd04df
be0f7d6
37eaf0c
17f1733
a0d8419
ed55f03
daf367c
ad12cc6
4bc4a1f
6c46d1a
c63fb10
ddba4dd
41184a8
cb303c3
ec1dcb4
fe3b18d
38d4044
3f78c8e
97d7039
c9ecb54
45b4e32
2414039
c4535da
c4521be
5e368df
f0988a4
1277850
ad5cff6
ee824f9
f1bcfe4
9e89241
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| /** | ||
| * Copyright (c) 2026, RTE (http://www.rte-france.com) | ||
| * This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
| */ | ||
| package org.gridsuite.monitor.server.config; | ||
|
|
||
| import org.gridsuite.monitor.server.services.S3RestService; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
| import org.springframework.beans.factory.annotation.Value; | ||
| import org.springframework.context.annotation.Bean; | ||
| import org.springframework.context.annotation.Configuration; | ||
| import software.amazon.awssdk.services.s3.S3Client; | ||
|
|
||
| /** | ||
| * @author Kevin Le Saulnier <kevin.le-saulnier at rte-france.com> | ||
| */ | ||
| @Configuration | ||
| public class S3Configuration { | ||
| private static final Logger LOGGER = LoggerFactory.getLogger(S3Configuration.class); | ||
| private final String bucketName; | ||
|
|
||
| public S3Configuration(@Value("${spring.cloud.aws.bucket:ws-bucket}") String bucketName) { | ||
| this.bucketName = bucketName; | ||
| } | ||
|
|
||
| @SuppressWarnings("checkstyle:MethodName") | ||
| @Bean | ||
| public S3RestService s3RestService(S3Client s3Client) { | ||
| LOGGER.info("Configuring S3Service with bucket: {}", bucketName); | ||
| return new S3RestService(s3Client, bucketName); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| /** | ||
| * Copyright (c) 2026, RTE (http://www.rte-france.com) | ||
| * This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
| */ | ||
| package org.gridsuite.monitor.server.services; | ||
|
|
||
| import software.amazon.awssdk.services.s3.S3Client; | ||
| import software.amazon.awssdk.services.s3.model.*; | ||
|
|
||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.IOException; | ||
| import java.io.InputStream; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.function.Function; | ||
| import java.util.zip.ZipEntry; | ||
| import java.util.zip.ZipOutputStream; | ||
|
|
||
| /** | ||
| * @author Kevin Le Saulnier <kevin.le-saulnier at rte-france.com> | ||
| */ | ||
| public class S3RestService { | ||
|
antoinebhs marked this conversation as resolved.
|
||
| private final S3Client s3Client; | ||
|
|
||
| private final String bucketName; | ||
|
|
||
| public S3RestService(S3Client s3Client, String bucketName) { | ||
| this.s3Client = s3Client; | ||
| this.bucketName = bucketName; | ||
| } | ||
|
|
||
| /** | ||
| * We did not use downloadDirectory from s3 methods here because it downloads all files on device directly instead of letting us redirect the stream into zip stream | ||
| */ | ||
| public byte[] downloadDirectoryAsZip(String directoryKey) throws IOException { | ||
| List<String> filesKeys = getFilesKeysInDirectory(directoryKey); | ||
|
|
||
| return buildZip( | ||
| directoryKey, | ||
| filesKeys, | ||
| key -> s3Client.getObject(GetObjectRequest.builder() | ||
| .bucket(bucketName) | ||
| .key(key) | ||
| .build()) | ||
| ); | ||
| } | ||
|
|
||
| byte[] buildZip(String directoryKey, List<String> filesS3Keys, Function<String, InputStream> s3ObjectFetcher) throws IOException { | ||
| ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); | ||
| try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) { | ||
| for (String fileS3Key : filesS3Keys) { | ||
| if (fileS3Key.endsWith("/")) { | ||
| // s3 files with key endpoint with "/" are most of the time DIROBJ, empty s3 objects that simulate directory for users | ||
| // we ignore them here to prevent errors | ||
| continue; | ||
| } | ||
| String zipEntryName = fileS3Key.substring(directoryKey.length() + 1); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In standard S3 like our dev platform, S3 also returns the directory itself. This might be an issue here. ?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed by filtering ou elements ending by "/" |
||
| zipOutputStream.putNextEntry(new ZipEntry(zipEntryName)); | ||
| try (InputStream in = s3ObjectFetcher.apply(fileS3Key)) { | ||
| in.transferTo(zipOutputStream); | ||
| } | ||
| zipOutputStream.closeEntry(); | ||
| } | ||
| } | ||
|
|
||
| return outputStream.toByteArray(); | ||
| } | ||
|
|
||
| List<String> getFilesKeysInDirectory(String directoryKey) { | ||
|
antoinebhs marked this conversation as resolved.
|
||
| List<String> filesS3Keys = new ArrayList<>(); | ||
| ListObjectsV2Request request = ListObjectsV2Request.builder() | ||
| .bucket(bucketName) | ||
| .prefix(directoryKey) | ||
| .build(); | ||
| ListObjectsV2Response response; | ||
| do { | ||
| response = s3Client.listObjectsV2(request); | ||
| response.contents().forEach(obj -> filesS3Keys.add(obj.key())); | ||
|
|
||
| request = request.toBuilder() | ||
| .continuationToken(response.nextContinuationToken()) | ||
| .build(); | ||
| } while (Boolean.TRUE.equals(response.isTruncated())); // S3 pagination, this loop ends if this is the last page | ||
|
|
||
| return filesS3Keys; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| /** | ||
| * Copyright (c) 2026, RTE (http://www.rte-france.com) | ||
| * This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
| */ | ||
| package org.gridsuite.monitor.server.utils; | ||
|
|
||
| import org.springframework.beans.factory.annotation.Value; | ||
| import org.springframework.stereotype.Component; | ||
|
|
||
| import java.util.UUID; | ||
|
|
||
| /** | ||
| * @author Kevin Le Saulnier <kevin.le-saulnier at rte-france.com> | ||
| */ | ||
| @Component | ||
| public final class S3PathResolver { | ||
| private final String s3RootPath; | ||
|
|
||
| public S3PathResolver(@Value("${powsybl-ws.s3.subpath.prefix:}${debug-subpath:debug}") String s3RootPath) { | ||
| this.s3RootPath = s3RootPath; | ||
| } | ||
|
|
||
| /** | ||
| * Builds root path used to build debug file location | ||
| * @param processType | ||
| * @param executionId | ||
| * @return {executionEnvName}_debug/process/{processType}/{executionId} | ||
| */ | ||
| public String toDebugLocation(String processType, UUID executionId) { | ||
| String s3Delimiter = "/"; | ||
| return String.join(s3Delimiter, s3RootPath, "process", processType, executionId.toString()); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| <?xml version="1.1" encoding="UTF-8" standalone="no"?> | ||
| <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd"> | ||
| <changeSet author="lesaulnierkev (generated)" id="1770884531328-1"> | ||
| <addColumn tableName="process_execution"> | ||
| <column name="debug_file_location" type="varchar(255)"/> | ||
| </addColumn> | ||
| </changeSet> | ||
| </databaseChangeLog> |
Uh oh!
There was an error while loading. Please reload this page.