This is an automated email from the ASF dual-hosted git repository.
yasithdev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata.git
The following commit(s) were added to refs/heads/master by this push:
new f7ed91cf71 fix: load storage data-movement interfaces via correct FK
column
f7ed91cf71 is described below
commit f7ed91cf7145485dc7a4c8710112e966b9d0ae95
Author: Yasith Jayawardana <[email protected]>
AuthorDate: Tue Jun 9 00:21:29 2026 -0400
fix: load storage data-movement interfaces via correct FK column
StorageResourceEntity's @OneToMany joined on a RESOURCE_ID column the child
entity never writes (it writes STORAGE_RESOURCE_ID, part of its composite @Id),
so a storage resource never loaded its data-movement interfaces and the SFTP
adaptor failed with 'No SCP data movement interface'. Joins on
STORAGE_RESOURCE_ID (read-only, child-owned). Also includes dev-storage
seed/infra fixes (DevStorageInitializer host + self-heal; sftp volume chown).
---
.../orchestration/util/DevStorageInitializer.java | 24 ++++++++++++++++++++--
.../storage/model/StorageResourceEntity.java | 12 ++++++++++-
compose.yml | 1 +
conf/sftp/chown-storage.sh | 7 +++++++
4 files changed, 41 insertions(+), 3 deletions(-)
diff --git
a/airavata-api/orchestration-service/src/main/java/org/apache/airavata/orchestration/util/DevStorageInitializer.java
b/airavata-api/orchestration-service/src/main/java/org/apache/airavata/orchestration/util/DevStorageInitializer.java
index bb8324d134..a651c1e8eb 100644
---
a/airavata-api/orchestration-service/src/main/java/org/apache/airavata/orchestration/util/DevStorageInitializer.java
+++
b/airavata-api/orchestration-service/src/main/java/org/apache/airavata/orchestration/util/DevStorageInitializer.java
@@ -28,6 +28,7 @@ import
org.apache.airavata.model.appcatalog.gatewayprofile.proto.StoragePreferen
import
org.apache.airavata.model.appcatalog.storageresource.proto.StorageResourceDescription;
import org.apache.airavata.model.credential.store.proto.SSHCredential;
import org.apache.airavata.model.data.movement.proto.DMType;
+import org.apache.airavata.model.data.movement.proto.DataMovementProtocol;
import org.apache.airavata.model.data.movement.proto.SCPDataMovement;
import org.apache.airavata.model.data.movement.proto.SecurityProtocol;
import org.apache.airavata.orchestration.service.RegistryServerHandler;
@@ -51,7 +52,9 @@ public class DevStorageInitializer {
private static final Logger logger =
LoggerFactory.getLogger(DevStorageInitializer.class);
- private static final String STORAGE_HOST = "localhost";
+ // The storage-service runs inside the airavata-dind network and reaches
the
+ // atmoz/sftp container by its compose service name, not "localhost".
+ private static final String STORAGE_HOST = "sftp";
private static final String STORAGE_DESCRIPTION = "Dev SFTP storage
(atmoz/sftp container)";
private static final String SFTP_LOGIN_USER = "airavata";
private static final String SFTP_FS_ROOT = "/storage";
@@ -80,7 +83,24 @@ public class DevStorageInitializer {
var allNames = registryHandler.getAllStorageResourceNames();
for (var entry : allNames.entrySet()) {
if (STORAGE_HOST.equals(entry.getValue())) {
- logger.info("Dev storage resource already exists: {}
({})", entry.getValue(), entry.getKey());
+ // Resource exists. Ensure it has an SCP data movement
interface —
+ // a partial prior init can leave it without one, which
then fails
+ // the SFTP adaptor with "No SCP data movement interface".
+ String existingId = entry.getKey();
+ boolean hasScp =
registryHandler.getStorageResource(existingId).getDataMovementInterfacesList()
+ .stream()
+ .anyMatch(i -> i.getDataMovementProtocol() ==
DataMovementProtocol.SCP);
+ if (!hasScp) {
+ SCPDataMovement scpDm = SCPDataMovement.newBuilder()
+ .setSecurityProtocol(SecurityProtocol.SSH_KEYS)
+ .setSshPort(22)
+ .build();
+ registryHandler.addSCPDataMovementDetails(existingId,
DMType.STORAGE_RESOURCE, 0, scpDm);
+ logger.info("Healed dev storage resource {}: added
missing SCP data movement interface",
+ existingId);
+ } else {
+ logger.info("Dev storage resource already exists: {}
({})", entry.getValue(), existingId);
+ }
return;
}
}
diff --git
a/airavata-api/storage-service/src/main/java/org/apache/airavata/storage/model/StorageResourceEntity.java
b/airavata-api/storage-service/src/main/java/org/apache/airavata/storage/model/StorageResourceEntity.java
index 45de96f8ad..5630e1a75e 100644
---
a/airavata-api/storage-service/src/main/java/org/apache/airavata/storage/model/StorageResourceEntity.java
+++
b/airavata-api/storage-service/src/main/java/org/apache/airavata/storage/model/StorageResourceEntity.java
@@ -51,12 +51,22 @@ public class StorageResourceEntity implements Serializable {
@Column(name = "UPDATE_TIME")
private Timestamp updateTime;
+ // The child (STORAGE_INTERFACE) already maps the FK as part of its
composite
+ // @Id (DataMovementInterfaceEntity.resourceId -> STORAGE_RESOURCE_ID), so
the
+ // association must join on that same column and be read-only here (the
child
+ // owns it). Pointing this at a separate "RESOURCE_ID" column left the
+ // association always empty, which broke the SFTP storage adaptor ("No SCP
+ // data movement interface for storage resource").
@OneToMany(
targetEntity = DataMovementInterfaceEntity.class,
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.EAGER)
- @JoinColumn(name = "RESOURCE_ID", referencedColumnName =
"STORAGE_RESOURCE_ID")
+ @JoinColumn(
+ name = "STORAGE_RESOURCE_ID",
+ referencedColumnName = "STORAGE_RESOURCE_ID",
+ insertable = false,
+ updatable = false)
private List<DataMovementInterfaceEntity> dataMovementInterfaces;
public StorageResourceEntity() {}
diff --git a/compose.yml b/compose.yml
index 4a0aebed03..9b7efd8d55 100644
--- a/compose.yml
+++ b/compose.yml
@@ -169,6 +169,7 @@ services:
restart: unless-stopped
volumes:
- ./conf/sftp/id_rsa.pub:/home/airavata/.ssh/keys/id_rsa.pub:ro
+ - ./conf/sftp/chown-storage.sh:/etc/sftp.d/chown-storage.sh:ro
- sftp_data:/home/airavata/storage
command: "airavata::1000"
healthcheck:
diff --git a/conf/sftp/chown-storage.sh b/conf/sftp/chown-storage.sh
new file mode 100755
index 0000000000..0a7514265a
--- /dev/null
+++ b/conf/sftp/chown-storage.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+# atmoz/sftp runs /etc/sftp.d/*.sh as root on container startup, before sshd
+# drops to the chrooted user. The named volume mounted at
/home/airavata/storage
+# is created root-owned by Docker, so the chrooted "airavata" user (uid 1000)
+# cannot create directories or write files there. Chown it on every startup so
+# the storage-service's SFTP adaptor can upload.
+chown -R airavata:airavata /home/airavata/storage