-
Notifications
You must be signed in to change notification settings - Fork 6
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
ALS-7014: Implement signed URL functionality for data exports #119
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
03c984e
ALS-7014: Presigned url initial commit with some test code
ramari16 e6786cd
ALS-7014: Fix content type, add log message
ramari16 2cb69bc
ALS-7014: Move s3 configs to property files
ramari16 e69e440
ALS-7014: Clean up some things
ramari16 9d0a260
ALS-7014: Set default parameter values
ramari16 eeb971b
ALS-7165: Update table name to include dataset id
ramari16 b530902
ALS-7014: Fix pfb schema issue
ramari16 9741c2b
ALS-7014: Remove unecessary null check
ramari16 108ad61
ALS-7014: Increment pic-sure version
ramari16 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
84 changes: 84 additions & 0 deletions
84
...ng/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/processing/upload/SignUrlService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package edu.harvard.hms.dbmi.avillach.hpds.processing.upload; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Component; | ||
import software.amazon.awssdk.core.sync.RequestBody; | ||
import software.amazon.awssdk.regions.Region; | ||
import software.amazon.awssdk.services.s3.S3Client; | ||
import software.amazon.awssdk.services.s3.model.GetObjectRequest; | ||
import software.amazon.awssdk.services.s3.model.PutObjectRequest; | ||
import software.amazon.awssdk.services.s3.presigner.S3Presigner; | ||
import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest; | ||
import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest; | ||
|
||
import java.io.File; | ||
import java.time.Duration; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
@Component | ||
public class SignUrlService { | ||
|
||
private final String bucketName; | ||
private final int signedUrlExpiryMinutes; | ||
private final Region region; | ||
|
||
private static Logger log = LoggerFactory.getLogger(SignUrlService.class); | ||
|
||
@Autowired | ||
public SignUrlService( | ||
@Value("${data-export.s3.bucket-name:}") String bucketName, | ||
@Value("${data-export.s3.region:us-east-1}") String region, | ||
@Value("${data-export.s3.signedUrl-expiry-minutes:60}") int signedUrlExpiryMinutes | ||
) { | ||
this.bucketName = bucketName; | ||
this.signedUrlExpiryMinutes = signedUrlExpiryMinutes; | ||
this.region = Region.of(region); | ||
} | ||
|
||
public void uploadFile(File file, String objectKey) { | ||
S3Client s3 = S3Client.builder() | ||
.region(region) | ||
.build(); | ||
|
||
putS3Object(s3, bucketName, objectKey, file); | ||
s3.close(); | ||
} | ||
|
||
// This example uses RequestBody.fromFile to avoid loading the whole file into | ||
// memory. | ||
public void putS3Object(S3Client s3, String bucketName, String objectKey, File file) { | ||
Map<String, String> metadata = new HashMap<>(); | ||
PutObjectRequest putOb = PutObjectRequest.builder() | ||
.bucket(bucketName) | ||
.key(objectKey) | ||
.metadata(metadata) | ||
.build(); | ||
|
||
s3.putObject(putOb, RequestBody.fromFile(file)); | ||
log.info("Successfully placed " + objectKey + " into bucket " + bucketName); | ||
} | ||
|
||
public String createPresignedGetUrl(String keyName) { | ||
PresignedGetObjectRequest presignedRequest; | ||
try (S3Presigner presigner = S3Presigner.builder().region(region).build()) { | ||
GetObjectRequest objectRequest = GetObjectRequest.builder() | ||
.bucket(bucketName) | ||
.key(keyName) | ||
.build(); | ||
|
||
GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder() | ||
.signatureDuration(Duration.ofMinutes(signedUrlExpiryMinutes)) // The URL will expire in 10 minutes. | ||
.getObjectRequest(objectRequest) | ||
.build(); | ||
|
||
presignedRequest = presigner.presignGetObject(presignRequest); | ||
} | ||
log.info("Presigned URL: [{}]", presignedRequest.url().toString()); | ||
|
||
return presignedRequest.url().toExternalForm(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is 400 a fair response code for pending statuses? Maybe 202?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think it is appropriate. Or at least consistent with the current workflow of the /result endpoint. The front end polls /status until it is SUCCESS, then calls this endpoint for a signed url, or /result for the document itself