diff --git a/Makefile b/Makefile
index 6019b1ed..4e11286d 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ DEMO_MODE := 0
FORCE := 0
# Required System files
-DOCKER_COMPOSE_EXE := $(shell which docker-compose)
+DOCKER_COMPOSE_EXE := $(shell which docker) compose
CURL_EXE := $(shell which curl)
MVN_EXE := $(shell which mvn)
@@ -38,6 +38,7 @@ RETRY_CMD := $(DOCKER_DIR)/retry-command.sh
# Commands
DOCKER_COMPOSE_CMD := echo "*********** DEMO_MODE = $(DEMO_MODE) **************" \
&& echo "*********** FORCE = $(FORCE) **************" \
+ && echo "*********** Docker file = $(DOCKERFILE_NAME) **************" \
&& MY_UID=$(MY_UID) MY_GID=$(MY_GID) DOCKERFILE_NAME=$(DOCKERFILE_NAME) $(DOCKER_COMPOSE_EXE) -f $(ROOT_DIR)/docker-compose.yml
SCORE_CLIENT_CMD := $(DOCKER_COMPOSE_CMD) run --rm -u $(THIS_USER) score-client bin/score-client
SCORE_CLIENT_TEST := $(DOCKER_COMPOSE_CMD) run --rm -u $(THIS_USER) score-client /data/run_tests.sh
@@ -77,17 +78,17 @@ _ping_song_server:
_setup-object-storage:
@echo $(YELLOW)$(INFO_HEADER) "Setting up bucket score.data and heliograph" $(END)
- @if $(DOCKER_COMPOSE_CMD) run aws-cli --endpoint-url http://object-storage:9000 s3 ls s3://score.data ; then \
+ @if $(DOCKER_COMPOSE_CMD) run --remove-orphans aws-cli --endpoint-url http://object-storage:9000 s3 ls s3://score.data ; then \
echo $(YELLOW)$(INFO_HEADER) "Bucket already exists. Skipping creation..." $(END); \
else \
- $(DOCKER_COMPOSE_CMD) run aws-cli --endpoint-url http://object-storage:9000 s3 mb s3://score.data; \
+ $(DOCKER_COMPOSE_CMD) run --remove-orphans aws-cli --endpoint-url http://object-storage:9000 s3 mb s3://score.data; \
fi
- @$(DOCKER_COMPOSE_CMD) run aws-cli --endpoint-url http://object-storage:9000 s3 cp /score-data/heliograph s3://score.data/data/heliograph
+ @$(DOCKER_COMPOSE_CMD) run --remove-orphans aws-cli --endpoint-url http://object-storage:9000 s3 cp /score-data/heliograph s3://score.data/data/heliograph
_destroy-object-storage:
@echo $(YELLOW)$(INFO_HEADER) "Removing bucket score.data" $(END)
- @if $(DOCKER_COMPOSE_CMD) run aws-cli --endpoint-url http://object-storage:9000 s3 ls s3://score.data ; then \
- $(DOCKER_COMPOSE_CMD) run aws-cli --endpoint-url http://object-storage:9000 s3 rb s3://score.data --force; \
+ @if $(DOCKER_COMPOSE_CMD) run --remove-orphans aws-cli --endpoint-url http://object-storage:9000 s3 ls s3://score.data ; then \
+ $(DOCKER_COMPOSE_CMD) run --remove-orphans aws-cli --endpoint-url http://object-storage:9000 s3 rb s3://score.data --force; \
else \
echo $(YELLOW)$(INFO_HEADER) "Bucket does not exist. Skipping..." $(END); \
fi
diff --git a/docker-compose.yml b/docker-compose.yml
index cde27bd5..73ee5b5b 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,4 +1,3 @@
-version: '3.7'
services:
keycloak-server:
image: docker.io/bitnami/keycloak:22
diff --git a/docker/keycloak-init/data_import/myrealm-users-0.json b/docker/keycloak-init/data_import/myrealm-users-0.json
index 01eb8bfd..7f2d2668 100644
--- a/docker/keycloak-init/data_import/myrealm-users-0.json
+++ b/docker/keycloak-init/data_import/myrealm-users-0.json
@@ -8,7 +8,7 @@
"totp" : false,
"emailVerified" : false,
"attributes" : {
- "api-keys" : [ "{\"name\":\"4978D340EDFA11ABF4A6B282C762676DCFAAEF55496631A6474D55C17CB96DCB\",\"scope\":[\"song.READ\",\"score.WRITE\",\"score.READ\",\"song.WRITE\"],\"expiryDate\":1746499545473,\"issueDate\":1714963545473,\"isRevoked\":false,\"description\":\"write and read\"}" ]
+ "api-keys" : [ "{\"name\":\"4978D340EDFA11ABF4A6B282C762676DCFAAEF55496631A6474D55C17CB96DCB\",\"scope\":[\"song.READ\",\"score.WRITE\",\"score.READ\",\"song.WRITE\"],\"expiryDate\":1904308934000,\"issueDate\":1714963545473,\"isRevoked\":false,\"description\":\"write and read\"}" ]
},
"credentials" : [ {
"id" : "b2152773-6246-4f74-bddd-6440e99dc860",
diff --git a/pom.xml b/pom.xml
index 622e4dff..2e9ee84d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -260,7 +260,7 @@ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF S
2021.0.8
- 1.11.219
+ 1.12.797
8.6.6
diff --git a/score-client/src/main/java/bio/overture/score/client/storage/ScoreStorageService.java b/score-client/src/main/java/bio/overture/score/client/storage/ScoreStorageService.java
index d0a6793d..44453e0e 100644
--- a/score-client/src/main/java/bio/overture/score/client/storage/ScoreStorageService.java
+++ b/score-client/src/main/java/bio/overture/score/client/storage/ScoreStorageService.java
@@ -259,6 +259,12 @@ public void finalizeUploadPart(
partNumber);
retry.execute(
ctx -> {
+ log.debug(
+ "Local checksum {} for part {}",
+ disableChecksum
+ ? "disabled"
+ : (md5.equals(etag) ? "validation passed" : "validation failed"),
+ partNumber);
if (disableChecksum || md5.equals(etag)) {
serviceTemplate.exchange(
endpoint
diff --git a/score-server/src/main/java/bio/overture/score/server/metadata/MetadataFile.java b/score-server/src/main/java/bio/overture/score/server/metadata/MetadataFile.java
new file mode 100644
index 00000000..24c28b32
--- /dev/null
+++ b/score-server/src/main/java/bio/overture/score/server/metadata/MetadataFile.java
@@ -0,0 +1,23 @@
+package bio.overture.score.server.metadata;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class MetadataFile {
+ private String objectId;
+ private String studyId;
+ private String analysisId;
+ private String fileName;
+ private String fileSize;
+ private String fileType;
+ private String fileMd5sum;
+ private String fileAccess;
+}
diff --git a/score-server/src/main/java/bio/overture/score/server/metadata/MetadataService.java b/score-server/src/main/java/bio/overture/score/server/metadata/MetadataService.java
index 803a3e6f..196741b1 100644
--- a/score-server/src/main/java/bio/overture/score/server/metadata/MetadataService.java
+++ b/score-server/src/main/java/bio/overture/score/server/metadata/MetadataService.java
@@ -62,6 +62,23 @@ public MetadataEntity getEntity(@NonNull String id) {
}
}
+ public MetadataFile getFile(@NonNull String studyId, @NonNull String id) {
+ log.debug("using " + metadataUrl + " for MetaData server");
+ try {
+ return restTemplate
+ .getForEntity(metadataUrl + "/studies/" + studyId + "/files/" + id, MetadataFile.class)
+ .getBody();
+ } catch (HttpClientErrorException e) {
+ if (e.getStatusCode() == NOT_FOUND) {
+ throw new IdNotFoundException(format("File %s is not registered on the server.", id));
+ }
+
+ log.error("Unexpected response code {} while getting ID {}", e.getStatusCode(), id);
+
+ throw e;
+ }
+ }
+
public String getAnalysisStateForMetadata(@NonNull MetadataEntity metadataEntity) {
val studyId = getStudyId(metadataEntity);
val analysisId = getAnalysisId(metadataEntity);
diff --git a/score-server/src/main/java/bio/overture/score/server/repository/s3/S3UploadService.java b/score-server/src/main/java/bio/overture/score/server/repository/s3/S3UploadService.java
index 7cbad788..b7d4a4f5 100644
--- a/score-server/src/main/java/bio/overture/score/server/repository/s3/S3UploadService.java
+++ b/score-server/src/main/java/bio/overture/score/server/repository/s3/S3UploadService.java
@@ -86,7 +86,7 @@ public class S3UploadService implements UploadService {
public ObjectSpecification initiateUpload(
String objectId, long fileSize, String md5, boolean overwrite) {
// First ensure that the system is aware of the requested object
- checkRegistered(objectId);
+ checkRegistered(objectId, md5);
val objectKey = ObjectKeys.getObjectKey(dataDir, objectId);
log.debug("Initiating upload for object key: {}, overwrite: {}", objectKey, overwrite);
@@ -142,7 +142,9 @@ public ObjectSpecification initiateUpload(
return spec;
} catch (AmazonServiceException e) {
log.error("Multipart Upload Initialization failure", e);
- if (e.getErrorCode().equals("KMS.DisabledException")) {
+ if (e.getErrorCode().equals("BadDigest")) {
+ throw new NotRetryableException(e);
+ } else if (e.getErrorCode().equals("KMS.DisabledException")) {
throw new InternalUnrecoverableError(e);
}
@@ -432,7 +434,7 @@ public void deletePart(String objectId, String uploadId, int partNumber) {
stateStore.deletePart(objectId, uploadId, partNumber);
}
- void checkRegistered(String objectId) {
+ void checkRegistered(String objectId, String md5) {
val entity = metadataClient.getEntity(objectId);
if (!entity.getId().equals(objectId)) {
val message =
@@ -444,6 +446,17 @@ void checkRegistered(String objectId) {
throw new InternalUnrecoverableError(message);
}
+ val registeredFile = metadataClient.getFile(entity.getProjectCode(), objectId);
+ if (!registeredFile.getFileMd5sum().equals(md5)) {
+ val message =
+ String.format(
+ "Critical Error: checked for objectId %s with md5 %s and metadata server returned md5 %s as match",
+ objectId, md5, registeredFile.getFileMd5sum());
+
+ log.error(message); // Log to audit log file
+ throw new InternalUnrecoverableError(message);
+ }
+
if (!useLegacyMode) {
checkUnpublishedAnalysisState(entity);
}