This is an automated email from the ASF dual-hosted git repository.
yasithdev pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airavata-portals.git
The following commit(s) were added to refs/heads/main by this push:
new 07dc7a6b6 feat(portal): repoint storage resource reads to gRPC (Track
D, D2) (#167)
07dc7a6b6 is described below
commit 07dc7a6b60129c0d4303b2953ed4b63df2321279
Author: Yasith Jayawardana <[email protected]>
AuthorDate: Mon Jun 8 19:35:26 2026 -0400
feat(portal): repoint storage resource reads to gRPC (Track D, D2) (#167)
Migrate StorageResourceViewSet.get_instance and the all_names action
from the Thrift client to the gRPC storage facade (storage.get_storage_
resource / get_all_storage_resource_names). Write actions stay on Thrift
pending D3.
New storage_resource adapter recursively adapts the nested
dataMovementInterfaces (DataMovementInterface) via a shared
_data_movement_interface adapter that the compute-resources family will
reuse. DataMovementProtocol needs an EXPLICIT proto-name -> Thrift-value
map rather than the by-name _thrift_enum helper: the names diverge (proto
prefixes the colliding member as DATA_MOVEMENT_PROTOCOL_LOCAL vs Thrift
LOCAL) and proto carries a GRID_FTP member Thrift never had. A new
_thrift_enum_mapped helper does the explicit-map bridge and returns None
for unmapped/UNKNOWN members (the nested fields are nullable). The
serializer renders dataMovementProtocol as a raw integer, so the map
emits the Thrift integer the frontend expects. Top-level creation/update
times keep their int (UTCPosixTimestampDateTimeField is not nullable);
nested timestamps map the proto-zero sentinel to None.
Verified: manage.py check clean; all_names + get_instance round-trip the
real dev storage resource live (200, ISO timestamps, correct fields);
offline serializer render exercises the full DataMovementProtocol map
(LOCAL/SCP/SFTP/UNICORE bridged to the right Thrift ints, GRID_FTP ->
None) and nested timestamp null handling.
---
.../django_airavata/apps/api/grpc_adapters.py | 57 ++++++++++++++++++++++
.../django_airavata/apps/api/views.py | 9 ++--
2 files changed, 61 insertions(+), 5 deletions(-)
diff --git a/airavata-django-portal/django_airavata/apps/api/grpc_adapters.py
b/airavata-django-portal/django_airavata/apps/api/grpc_adapters.py
index e806d8ec4..3cfe01802 100644
--- a/airavata-django-portal/django_airavata/apps/api/grpc_adapters.py
+++ b/airavata-django-portal/django_airavata/apps/api/grpc_adapters.py
@@ -18,6 +18,9 @@ from airavata.model.appcatalog.parallelism.ttypes import (
)
from airavata.model.application.io.ttypes import DataType as _ThriftDataType
from airavata.model.credential.store.ttypes import SummaryType as
_ThriftSummaryType
+from airavata.model.data.movement.ttypes import (
+ DataMovementProtocol as _ThriftDataMovementProtocol,
+)
def _thrift_enum(pb, field, thrift_enum):
@@ -33,6 +36,60 @@ def _thrift_enum(pb, field, thrift_enum):
return getattr(thrift_enum, name)
+def _thrift_enum_mapped(pb, field, proto_name_to_thrift):
+ """Bridge a proto enum field to a Thrift value via an EXPLICIT name map.
+
+ Needed when the proto and Thrift enum member NAMES diverge — proto3
prefixes
+ members whose bare name would collide in the file (e.g. proto
+ ``DATA_MOVEMENT_PROTOCOL_LOCAL`` vs Thrift ``LOCAL``), and some members
exist
+ on only one side (e.g. proto-only ``GRID_FTP``). Unmapped members —
including
+ the zero ``*_UNKNOWN`` sentinel and proto-only values — return None (the
+ serializer fields are nullable for these).
+ """
+ enum_descriptor = pb.DESCRIPTOR.fields_by_name[field].enum_type
+ proto_name = enum_descriptor.values_by_number[getattr(pb, field)].name
+ return proto_name_to_thrift.get(proto_name)
+
+
+# proto DataMovementProtocol member name -> Thrift DataMovementProtocol value.
+# Names diverge (proto prefixes LOCAL; proto-only GRID_FTP has no Thrift
value).
+_DATA_MOVEMENT_PROTOCOL = {
+ 'DATA_MOVEMENT_PROTOCOL_LOCAL': _ThriftDataMovementProtocol.LOCAL,
+ 'SCP': _ThriftDataMovementProtocol.SCP,
+ 'SFTP': _ThriftDataMovementProtocol.SFTP,
+ 'UNICORE_STORAGE_SERVICE':
_ThriftDataMovementProtocol.UNICORE_STORAGE_SERVICE,
+}
+
+
+def _data_movement_interface(pb):
+ """gRPC ``DataMovementInterface`` -> auto-generated serializer shape."""
+ return SimpleNamespace(
+ dataMovementInterfaceId=pb.data_movement_interface_id,
+ dataMovementProtocol=_thrift_enum_mapped(
+ pb, 'data_movement_protocol', _DATA_MOVEMENT_PROTOCOL),
+ priorityOrder=pb.priority_order,
+ creationTime=pb.creation_time or None,
+ updateTime=pb.update_time or None,
+ storageResourceId=pb.storage_resource_id,
+ )
+
+
+def storage_resource(pb):
+ """gRPC ``StorageResourceDescription`` -> ``StorageResourceSerializer``
shape."""
+ return SimpleNamespace(
+ storageResourceId=pb.storage_resource_id,
+ hostName=pb.host_name,
+ storageResourceDescription=pb.storage_resource_description,
+ enabled=pb.enabled,
+ dataMovementInterfaces=[
+ _data_movement_interface(d) for d in pb.data_movement_interfaces],
+ # top-level creation/update use UTCPosixTimestampDateTimeField (not
+ # nullable, divides by 1000) -> keep the int.
+ creationTime=pb.creation_time,
+ updateTime=pb.update_time,
+ )
+
+
def proto_summary_type(thrift_summary_type):
"""Thrift ``SummaryType`` -> proto ``SummaryType`` enum value (by name).
diff --git a/airavata-django-portal/django_airavata/apps/api/views.py
b/airavata-django-portal/django_airavata/apps/api/views.py
index 7b48b955f..6eea9d420 100644
--- a/airavata-django-portal/django_airavata/apps/api/views.py
+++ b/airavata-django-portal/django_airavata/apps/api/views.py
@@ -1486,15 +1486,14 @@ class StorageResourceViewSet(mixins.RetrieveModelMixin,
lookup_field = 'storage_resource_id'
def get_instance(self, lookup_value, format=None):
- return self.request.airavata_client.getStorageResource(
- self.authz_token, lookup_value)
+ return grpc_adapters.storage_resource(
+ self.request.airavata.storage.get_storage_resource(lookup_value))
@action(detail=False)
def all_names(self, request, format=None):
- """Return a map of compute resource names keyed by resource id."""
+ """Return a map of storage resource names keyed by resource id."""
return Response(
- request.airavata_client.getAllStorageResourceNames(
- request.authz_token))
+ request.airavata.storage.get_all_storage_resource_names())
class StoragePreferenceViewSet(APIBackedViewSet):