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 91cf66b9d feat(portal): repoint application deployment reads to gRPC
(Track D, D2) (#166)
91cf66b9d is described below
commit 91cf66b9d58da88d0ebd9d098735d48c660daa3b
Author: Yasith Jayawardana <[email protected]>
AuthorDate: Mon Jun 8 19:29:14 2026 -0400
feat(portal): repoint application deployment reads to gRPC (Track D, D2)
(#166)
Migrate ApplicationDeploymentViewSet.get_list/get_instance from the
Thrift client to the gRPC research facade (get_accessible_application_
deployments / get_application_deployments_for_app_module_and_group_
resource_profile / get_application_deployment). Write actions and the
queues action stay on Thrift: queues reads a ComputeResource, so it
moves with the compute-resources family.
New application_deployment adapter recursively adapts the nested command
lists (moduleLoadCmds/preJobCommands/postJobCommands -> CommandObject)
and env-path lists (libPrependPaths/libAppendPaths/setEnvironment ->
SetEnvPaths). The serializer renders parallelism as a raw integer (the
auto-generated field is an IntegerField, not a ThriftEnumField), and the
proto/Thrift ApplicationParallelismType integers differ per name (proto
SERIAL=1 vs Thrift SERIAL=0), so the adapter bridges by NAME via the
shared _thrift_enum helper to emit the Thrift integer the frontend
expects -- passing the raw proto int would shift every value by one. The
queue-default cluster (defaultQueueName/NodeCount/CPUCount/Walltime) maps
the proto-zero 'unset' sentinels back to None so the serializer renders
null as Thrift did. userHasWriteAccess migrates to the gRPC sharing
helper.
Verified: manage.py check clean; accessible list returns 200 against the
live backend; offline serializer render with real nested protobuf
confirms command/env lists adapt, parallelism maps to the correct Thrift
int for every value, queue-defaults render null, and userHasWriteAccess
resolves via sharing. (The dev backend has no compute resources to seed a
full deployment, so nested live data was validated via the offline render
against real protobuf.)
---
.../django_airavata/apps/api/grpc_adapters.py | 43 ++++++++++++++++++++++
.../django_airavata/apps/api/serializers.py | 6 +--
.../django_airavata/apps/api/views.py | 13 ++++---
3 files changed, 52 insertions(+), 10 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 30761dadf..e806d8ec4 100644
--- a/airavata-django-portal/django_airavata/apps/api/grpc_adapters.py
+++ b/airavata-django-portal/django_airavata/apps/api/grpc_adapters.py
@@ -13,6 +13,9 @@ serializers are made protobuf-native.
from types import SimpleNamespace
+from airavata.model.appcatalog.parallelism.ttypes import (
+ ApplicationParallelismType as _ThriftParallelismType,
+)
from airavata.model.application.io.ttypes import DataType as _ThriftDataType
from airavata.model.credential.store.ttypes import SummaryType as
_ThriftSummaryType
@@ -164,3 +167,43 @@ def application_interface(pb):
archiveWorkingDirectory=pb.archive_working_directory,
hasOptionalFileInputs=pb.has_optional_file_inputs,
)
+
+
+def _command_object(pb):
+ """gRPC ``CommandObject`` -> ``CommandObjectSerializer`` shape."""
+ return SimpleNamespace(command=pb.command, commandOrder=pb.command_order)
+
+
+def _set_env_paths(pb):
+ """gRPC ``SetEnvPaths`` -> ``SetEnvPathsSerializer`` shape."""
+ return SimpleNamespace(
+ name=pb.name, value=pb.value, envPathOrder=pb.env_path_order)
+
+
+def application_deployment(pb):
+ """gRPC ``ApplicationDeploymentDescription`` ->
``ApplicationDeploymentDescriptionSerializer`` shape.
+
+ Recursively adapts the nested command/env-path lists. ``parallelism`` is an
+ enum with the proto/Thrift integer mismatch (proto SERIAL=1 vs Thrift
+ SERIAL=0) -> bridged by name. The queue-default cluster maps the proto-zero
+ "unset" sentinels back to None so the serializer renders null as Thrift
did.
+ """
+ return SimpleNamespace(
+ appDeploymentId=pb.app_deployment_id,
+ appModuleId=pb.app_module_id,
+ computeHostId=pb.compute_host_id,
+ executablePath=pb.executable_path,
+ parallelism=_thrift_enum(pb, 'parallelism', _ThriftParallelismType),
+ appDeploymentDescription=pb.app_deployment_description,
+ moduleLoadCmds=[_command_object(c) for c in pb.module_load_cmds],
+ libPrependPaths=[_set_env_paths(p) for p in pb.lib_prepend_paths],
+ libAppendPaths=[_set_env_paths(p) for p in pb.lib_append_paths],
+ setEnvironment=[_set_env_paths(p) for p in pb.set_environment],
+ preJobCommands=[_command_object(c) for c in pb.pre_job_commands],
+ postJobCommands=[_command_object(c) for c in pb.post_job_commands],
+ defaultQueueName=pb.default_queue_name or None,
+ defaultNodeCount=pb.default_node_count or None,
+ defaultCPUCount=pb.default_cpu_count or None,
+ defaultWalltime=pb.default_walltime or None,
+ editableByUser=pb.editable_by_user,
+ )
diff --git a/airavata-django-portal/django_airavata/apps/api/serializers.py
b/airavata-django-portal/django_airavata/apps/api/serializers.py
index 901f99969..6d99f5c48 100644
--- a/airavata-django-portal/django_airavata/apps/api/serializers.py
+++ b/airavata-django-portal/django_airavata/apps/api/serializers.py
@@ -515,10 +515,8 @@ class ApplicationDeploymentDescriptionSerializer(
allow_null=True)
def get_userHasWriteAccess(self, appDeployment):
- request = self.context['request']
- return request.airavata_client.userHasAccess(
- request.authz_token, appDeployment.appDeploymentId,
- ResourcePermissionType.WRITE)
+ return user_has_access(
+ self.context['request'], appDeployment.appDeploymentId)
class ComputeResourceDescriptionSerializer(
diff --git a/airavata-django-portal/django_airavata/apps/api/views.py
b/airavata-django-portal/django_airavata/apps/api/views.py
index 078c9d4f8..7b48b955f 100644
--- a/airavata-django-portal/django_airavata/apps/api/views.py
+++ b/airavata-django-portal/django_airavata/apps/api/views.py
@@ -630,15 +630,16 @@ class ApplicationDeploymentViewSet(APIBackedViewSet):
raise ParseError("Query params appModuleId and "
"groupResourceProfileId are required together.")
if app_module_id and group_resource_profile_id:
- return
self.request.airavata_client.getApplicationDeploymentsForAppModuleAndGroupResourceProfile(
- self.authz_token, app_module_id, group_resource_profile_id)
+ deployments =
self.request.airavata.research.get_application_deployments_for_app_module_and_group_resource_profile(
+ app_module_id, group_resource_profile_id)
else:
- return
self.request.airavata_client.getAccessibleApplicationDeployments(
- self.authz_token, self.gateway_id, ResourcePermissionType.READ)
+ deployments =
self.request.airavata.research.get_accessible_application_deployments(
+ self.gateway_id)
+ return [grpc_adapters.application_deployment(d) for d in deployments]
def get_instance(self, lookup_value):
- return self.request.airavata_client.getApplicationDeployment(
- self.authz_token, lookup_value)
+ return grpc_adapters.application_deployment(
+
self.request.airavata.research.get_application_deployment(lookup_value))
def perform_create(self, serializer):
application_deployment = serializer.save()