You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ma...@apache.org on 2018/01/29 21:07:15 UTC

[airavata-django-portal] 03/03: AIRAVATA-2615 List job details in experiment summary

This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit 550884b5e2a4096d90a245614a83eeccc3b00fe5
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Mon Jan 29 16:07:04 2018 -0500

    AIRAVATA-2615 List job details in experiment summary
---
 django_airavata/apps/api/serializers.py            | 10 +++++++-
 .../js/models/FullExperiment.js                    | 10 ++++++--
 .../static/django_airavata_api/js/models/Job.js    | 30 ++++++++++++++++++++++
 .../django_airavata_api/js/models/JobState.js      | 14 ++++++++++
 .../django_airavata_api/js/models/JobStatus.js     | 20 +++++++++++++++
 django_airavata/apps/api/views.py                  | 13 +++++++++-
 .../js/components/experiment/ExperimentSummary.vue | 22 ++++++++++++++++
 7 files changed, 115 insertions(+), 4 deletions(-)

diff --git a/django_airavata/apps/api/serializers.py b/django_airavata/apps/api/serializers.py
index d9d32cc..3a0fd09 100644
--- a/django_airavata/apps/api/serializers.py
+++ b/django_airavata/apps/api/serializers.py
@@ -5,6 +5,7 @@ from airavata.model.appcatalog.computeresource.ttypes import BatchQueue
 from airavata.model.application.io.ttypes import InputDataObjectType, OutputDataObjectType
 from airavata.model.data.replica.ttypes import DataProductModel, DataReplicaLocationModel
 from airavata.model.experiment.ttypes import ExperimentModel
+from airavata.model.job.ttypes import JobModel
 from airavata.model.status.ttypes import ExperimentStatus
 from airavata.model.workspace.ttypes import Project
 
@@ -245,6 +246,7 @@ class ExperimentSerializer(
     url = FullyEncodedHyperlinkedIdentityField(view_name='django_airavata_api:experiment-detail', lookup_field='experimentId', lookup_url_kwarg='experiment_id')
     full_experiment = FullyEncodedHyperlinkedIdentityField(view_name='django_airavata_api:full-experiment-detail', lookup_field='experimentId', lookup_url_kwarg='experiment_id')
     project = FullyEncodedHyperlinkedIdentityField(view_name='django_airavata_api:project-detail', lookup_field='projectId', lookup_url_kwarg='project_id')
+    jobs = FullyEncodedHyperlinkedIdentityField(view_name='django_airavata_api:experiment-jobs', lookup_field='experimentId', lookup_url_kwarg='experiment_id')
     userName = GatewayUsernameDefaultField()
     gatewayId = GatewayIdDefaultField()
     creationTime = UTCPosixTimestampDateTimeField(allow_null=True)
@@ -270,7 +272,7 @@ class FullExperiment:
 
     def __init__(self, experimentModel, project=None, outputDataProducts=None,
                  inputDataProducts=None, applicationModule=None,
-                 computeResource=None):
+                 computeResource=None, jobDetails=None):
         self.experiment = experimentModel
         self.experimentId = experimentModel.experimentId
         self.project = project
@@ -278,6 +280,11 @@ class FullExperiment:
         self.inputDataProducts = inputDataProducts
         self.applicationModule = applicationModule
         self.computeResource = computeResource
+        self.jobDetails = jobDetails
+
+
+class JobSerializer(thrift_utils.create_serializer_class(JobModel)):
+    creationTime = UTCPosixTimestampDateTimeField()
 
 
 class FullExperimentSerializer(serializers.Serializer):
@@ -291,6 +298,7 @@ class FullExperimentSerializer(serializers.Serializer):
     applicationModule = ApplicationModuleSerializer(read_only=True)
     computeResource = ComputeResourceDescriptionSerializer(read_only=True)
     project = ProjectSerializer(read_only=True)
+    jobDetails = JobSerializer(many=True, read_only=True)
 
     def create(self, validated_data):
         raise Exception("Not implemented")
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/FullExperiment.js b/django_airavata/apps/api/static/django_airavata_api/js/models/FullExperiment.js
index 6059b2a..b7bac6a 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/FullExperiment.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/FullExperiment.js
@@ -2,8 +2,9 @@
 import ApplicationModule from './ApplicationModule'
 import BaseModel from './BaseModel'
 import ComputeResourceDescription from './ComputeResourceDescription'
-import DataProduct from './DataProduct.js'
+import DataProduct from './DataProduct'
 import Experiment from './Experiment'
+import Job from './Job'
 import Project from './Project'
 
 const FIELDS = [
@@ -33,7 +34,12 @@ const FIELDS = [
         name: 'inputDataProducts',
         type: DataProduct,
         list: true
-    }
+    },
+    {
+        name: 'jobDetails',
+        type: Job,
+        list: true,
+    },
 ];
 
 export default class FullExperiment extends BaseModel {
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/Job.js b/django_airavata/apps/api/static/django_airavata_api/js/models/Job.js
new file mode 100644
index 0000000..866088a
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/Job.js
@@ -0,0 +1,30 @@
+import BaseModel from './BaseModel';
+import JobStatus from './JobStatus';
+
+const FIELDS = [
+     'jobId',
+     'taskId',
+     'processId',
+     'jobDescription',
+     {
+         name: 'creationTime',
+         type: 'date',
+     },
+     {
+         name: 'jobStatuses',
+         type: JobStatus,
+         list: true,
+     },
+     'computeResourceConsumed',
+     'jobName',
+     'workingDir',
+     'stdOut',
+     'stdErr',
+     'exitCode',
+];
+
+export default class Job extends BaseModel {
+    constructor(data = {}) {
+        super(FIELDS, data);
+    }
+}
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/JobState.js b/django_airavata/apps/api/static/django_airavata_api/js/models/JobState.js
new file mode 100644
index 0000000..88d616d
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/JobState.js
@@ -0,0 +1,14 @@
+import BaseEnum from './BaseEnum'
+
+export default class JobState extends BaseEnum {
+}
+JobState.init([
+    'SUBMITTED',
+    'QUEUED',
+    'ACTIVE',
+    'COMPLETE',
+    'CANCELED',
+    'FAILED',
+    'SUSPENDED',
+    'UNKNOWN',
+]);
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/JobStatus.js b/django_airavata/apps/api/static/django_airavata_api/js/models/JobStatus.js
new file mode 100644
index 0000000..3aaac57
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/JobStatus.js
@@ -0,0 +1,20 @@
+import BaseModel from './BaseModel';
+import JobState from './JobState';
+
+const FIELDS = [
+     {
+         name: 'jobState',
+         type: JobState,
+     },
+     {
+         name: 'timeOfStateChange',
+         type: 'date',
+     },
+     'reason',
+];
+
+export default class JobStatus extends BaseModel {
+    constructor(data = {}) {
+        super(FIELDS, data);
+    }
+}
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index 99fce0d..c9b2f57 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -259,6 +259,14 @@ class ExperimentViewSet(APIBackedViewSet):
         except Exception as e:
             return Response({'success': False, 'errorMessage': e.message})
 
+    @detail_route(methods=['get'])
+    def jobs(self, request, experiment_id=None):
+        jobs = request.airavata_client.getJobDetails(
+            self.authz_token, experiment_id)
+        serializer = serializers.JobSerializer(
+            jobs, many=True, context={'request': request})
+        return Response(serializer.data)
+
 
 class FullExperimentViewSet(mixins.RetrieveModelMixin,
                             GenericAPIBackedViewSet):
@@ -303,13 +311,16 @@ class FullExperimentViewSet(mixins.RetrieveModelMixin,
             if compute_resource_id else None
         project = self.request.airavata_client.getProject(
             self.authz_token, experimentModel.projectId)
+        job_details = self.request.airavata_client.getJobDetails(
+            self.authz_token, lookup_value)
         full_experiment = serializers.FullExperiment(
             experimentModel,
             project=project,
             outputDataProducts=outputDataProducts,
             inputDataProducts=inputDataProducts,
             applicationModule=applicationModule,
-            computeResource=compute_resource)
+            computeResource=compute_resource,
+            jobDetails=job_details)
         return full_experiment
 
 
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentSummary.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentSummary.vue
index 17d2634..7a327f7 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentSummary.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentSummary.vue
@@ -60,6 +60,25 @@
                                         {{ localFullExperiment.experimentStatusName }}
                                     </td>
                                 </tr>
+                                <tr v-if="localFullExperiment.jobDetails && localFullExperiment.jobDetails.length > 0">
+                                    <th scope="row">Job</th>
+                                    <td>
+                                        <table class="table">
+                                            <thead>
+                                                <th>Name</th>
+                                                <th>ID</th>
+                                                <th>Status</th>
+                                                <th>Creation Time</th>
+                                            </thead>
+                                            <tr v-for="(jobDetail, index) in localFullExperiment.jobDetails">
+                                                <td>{{ jobDetail.jobName }}</td>
+                                                <td>{{ jobDetail.jobId }}</td>
+                                                <td>{{ jobDetail.jobStatuses[0].jobState.name }}</td>
+                                                <td><span :title="jobDetail.creationTime.toString()">{{ jobCreationTimes[index] }}</span></td>
+                                            </tr>
+                                        </table>
+                                    </td>
+                                </tr>
                                 <!--  TODO: leave this out for now -->
                                 <!-- <tr>
                                     <th scope="row">Notification List</th>
@@ -148,6 +167,9 @@ export default {
         },
         experiment: function() {
             return this.localFullExperiment.experiment;
+        },
+        jobCreationTimes: function() {
+            return this.localFullExperiment.jobDetails.map(jobDetail => moment(jobDetail.creationTime).fromNow());
         }
     },
     methods: {

-- 
To stop receiving notification emails like this one, please contact
machristie@apache.org.