airavata-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From machris...@apache.org
Subject [airavata-django-portal] 25/28: AIRAVATA-2876 WIP ApplicationDeploymentEditor
Date Tue, 11 Sep 2018 17:12:13 GMT
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 ff4151f413a8d72923962accae651ca025561b01
Author: Marcus Christie <machrist@iu.edu>
AuthorDate: Fri Sep 7 15:59:23 2018 -0400

    AIRAVATA-2876 WIP ApplicationDeploymentEditor
---
 .../applications/ApplicationDeploymentEditor.vue   | 100 ++++++++++++++++++++-
 .../applications/ApplicationModuleEditor.vue       |  24 ++---
 django_airavata/apps/api/serializers.py            |  39 ++++----
 .../api/static/django_airavata_api/js/index.js     |   7 +-
 .../js/models/ApplicationDeploymentDescription.js  |  46 ++++++++--
 .../django_airavata_api/js/models/CommandObject.js |  20 +++++
 .../js/models/ParallelismType.js                   |  12 +++
 .../django_airavata_api/js/models/SetEnvPath.js    |  21 +++++
 .../django_airavata_api/js/service_config.js       |   2 +-
 django_airavata/apps/api/views.py                  |  21 ++++-
 10 files changed, 236 insertions(+), 56 deletions(-)

diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentEditor.vue
b/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentEditor.vue
index c619990..b778577 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentEditor.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationDeploymentEditor.vue
@@ -1,11 +1,57 @@
 <template>
-  <div>Application Deployment Editor</div>
+  <div>
+    <div class="row">
+      <div class="col">
+        <h1 class="h4 mb-4">
+          {{ name }}
+        </h1>
+        <b-form-group label="Application Executable Path" label-for="executable-path">
+          <b-form-input id="executable-path" type="text" v-model="data.executablePath"
required></b-form-input>
+        </b-form-group>
+        <b-form-group label="Application Parallelism Type" label-for="parallelism-type">
+          <b-form-select id="parallelism-type" v-model="data.parallelism" :options="parallelismTypeOptions"
/>
+        </b-form-group>
+        <b-form-group label="Application Deployment Description" label-for="deployment-description">
+          <b-form-textarea id="deployment-description" v-model="data.appDeploymentDescription"
:rows="3"></b-form-textarea>
+        </b-form-group>
+        <b-card title="Module Load Commands">
+          <b-input-group v-for="moduleLoadCmd in data.moduleLoadCmds" :key="moduleLoadCmd.key"
class="mb-1">
+            <b-form-input type="text" v-model="moduleLoadCmd.command" required ref="moduleLoadCmdInputs"
/>
+            <b-input-group-append>
+              <b-button variant="secondary" @click="deleteModuleLoadCmd(moduleLoadCmd)">
+                <i class="fa fa-trash"></i>
+                <span class="sr-only">Delete</span>
+              </b-button>
+            </b-input-group-append>
+          </b-input-group>
+          <b-button variant="secondary" @click="addModuleLoadCmd">Add Module Load Command</b-button>
+        </b-card>
+      </div>
+    </div>
+    <div class="row mb-4">
+      <div class="col">
+        <b-button variant="primary" @click="save">
+          Save
+        </b-button>
+        <b-button variant="secondary" @click="cancel">
+          Cancel
+        </b-button>
+      </div>
+    </div>
+  </div>
 </template>
 
 <script>
+import { models, services } from "django-airavata-api";
+import vmodel_mixin from "../commons/vmodel_mixin";
+
 export default {
   name: "application-deployment-editor",
+  mixins: [vmodel_mixin],
   props: {
+    value: {
+      type: models.ApplicationDescriptionDefinition
+    },
     id: {
       type: String,
       required: true
@@ -14,6 +60,58 @@ export default {
       type: String,
       required: true
     }
+  },
+  data() {
+    return {
+      computeResource: null
+    };
+  },
+  computed: {
+    name() {
+      if (this.computeResource) {
+        return this.computeResource.hostName;
+      } else {
+        return this.data.computeHostId.substring(0, 10);
+      }
+    },
+    parallelismTypeOptions() {
+      return models.ParallelismType.values.map(parType => {
+        return {
+          value: parType,
+          text: parType.name
+        };
+      });
+    }
+  },
+  created() {
+    services.ComputeResourceService.retrieve({
+      lookup: this.data.computeHostId
+    }).then(computeResource => (this.computeResource = computeResource));
+  },
+  methods: {
+    save() {
+      this.$emit("save");
+    },
+    cancel() {
+      this.$emit("cancel");
+    },
+    addModuleLoadCmd() {
+      if (!this.data.moduleLoadCmds) {
+        this.data.moduleLoadCmds = [];
+      }
+      this.data.moduleLoadCmds.push(new models.CommandObject());
+      this.$nextTick(() =>
+        this.$refs.moduleLoadCmdInputs[
+          this.$refs.moduleLoadCmdInputs.length - 1
+        ].focus()
+      );
+    },
+    deleteModuleLoadCmd(moduleLoadCmd) {
+      const index = this.data.moduleLoadCmds.findIndex(
+        cmd => cmd.key === moduleLoadCmd.key
+      );
+      this.data.moduleLoadCmds.splice(index, 1);
+    }
   }
 };
 </script>
diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationModuleEditor.vue
b/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationModuleEditor.vue
index 092fdc9..b6d08a7 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationModuleEditor.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/applications/ApplicationModuleEditor.vue
@@ -6,13 +6,13 @@
           Application Details
         </h1>
         <b-form-group label="Application Name" label-for="application-name">
-          <b-form-input id="application-name" type="text" v-model="appModule.appModuleName"
required @input="emitChanged"></b-form-input>
+          <b-form-input id="application-name" type="text" v-model="data.appModuleName"
required></b-form-input>
         </b-form-group>
         <b-form-group label="Application Version" label-for="application-version">
-          <b-form-input id="application-version" type="text" v-model="appModule.appModuleVersion"
@input="emitChanged"></b-form-input>
+          <b-form-input id="application-version" type="text" v-model="data.appModuleVersion"></b-form-input>
         </b-form-group>
         <b-form-group label="Application Description" label-for="application-description">
-          <b-form-textarea id="application-description" v-model="appModule.appModuleDescription"
:rows="3" @input="emitChanged"></b-form-textarea>
+          <b-form-textarea id="application-description" v-model="data.appModuleDescription"
:rows="3"></b-form-textarea>
         </b-form-group>
       </div>
     </div>
@@ -31,35 +31,23 @@
 
 <script>
 import { models } from "django-airavata-api";
+import vmodel_mixin from "../commons/vmodel_mixin";
 
 export default {
   name: "application-module-editor",
+  mixins: [vmodel_mixin],
   props: {
     value: {
-      type: models.ApplicationModule,
-      required: true
+      type: models.ApplicationModule
     }
   },
-  data: function() {
-    return {
-      appModule: this.value.clone()
-    };
-  },
   methods: {
-    emitChanged() {
-      this.$emit("input", this.appModule);
-    },
     save() {
       this.$emit("save");
     },
     cancel() {
       this.$emit("cancel");
     }
-  },
-  watch: {
-    value: function(newValue) {
-      this.appModule = newValue.clone();
-    }
   }
 };
 </script>
diff --git a/django_airavata/apps/api/serializers.py b/django_airavata/apps/api/serializers.py
index cefabd9..9f91207 100644
--- a/django_airavata/apps/api/serializers.py
+++ b/django_airavata/apps/api/serializers.py
@@ -313,29 +313,6 @@ class ApplicationInterfaceDescriptionSerializer(
         return validated_data
 
 
-class CommandObjectSerializer(CustomSerializer):
-    command = serializers.CharField()
-    commandOrder = serializers.IntegerField()
-
-    def create(self, validated_data):
-        return CommandObject(**validated_data)
-
-    def update(self, instance, validated_data):
-        raise Exception("Not implemented")
-
-
-class SetEnvPathsSerializer(CustomSerializer):
-    name=serializers.CharField(required=False)
-    value=serializers.CharField(required=False)
-    envPathOrder=serializers.IntegerField(required=False)
-
-    def create(self, validated_data):
-        return SetEnvPaths(**validated_data)
-
-    def update(self, instance, validated_data):
-        raise Exception("Not implemented")
-
-
 class ApplicationDeploymentDescriptionSerializer(
         thrift_utils.create_serializer_class(
             ApplicationDeploymentDescription)):
@@ -357,6 +334,22 @@ class ApplicationDeploymentDescriptionSerializer(
             request.authz_token, appDeployment.appDeploymentId,
             ResourcePermissionType.WRITE)
 
+    def to_representation(self, instance):
+        rep = super().to_representation(instance)
+        if rep['moduleLoadCmds'] is not None:
+            rep['moduleLoadCmds'].sort(
+                key=lambda cmd: cmd['commandOrder'])
+        return rep
+
+    def to_internal_value(self, data):
+        validated_data = super().to_internal_value(data)
+        # Update application input order based on order in array
+        module_load_cmds = validated_data.get('moduleLoadCmds', [])
+        if module_load_cmds is not None:
+            for i in range(len(module_load_cmds)):
+                module_load_cmds[i]['commandOrder'] = i
+        return validated_data
+
 
 class ComputeResourceDescriptionSerializer(thrift_utils.create_serializer_class(ComputeResourceDescription)):
     pass
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/index.js b/django_airavata/apps/api/static/django_airavata_api/js/index.js
index 6546388..8c9a497 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/index.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/index.js
@@ -7,6 +7,7 @@ import ApplicationModule from './models/ApplicationModule'
 import BaseModel from './models/BaseModel'
 import BatchQueue from './models/BatchQueue'
 import BatchQueueResourcePolicy from './models/BatchQueueResourcePolicy'
+import CommandObject from './models/CommandObject'
 import ComputeResourcePolicy from './models/ComputeResourcePolicy'
 import DataType from './models/DataType'
 import Experiment from './models/Experiment'
@@ -18,13 +19,14 @@ import GroupPermission from './models/GroupPermission'
 import GroupResourceProfile from './models/GroupResourceProfile'
 import InputDataObjectType from './models/InputDataObjectType'
 import OutputDataObjectType from './models/OutputDataObjectType'
+import ParallelismType from './models/ParallelismType'
 import Project from './models/Project'
 import ResourcePermissionType from './models/ResourcePermissionType'
+import SetEnvPath from './models/SetEnvPath'
 import SharedEntity from './models/SharedEntity'
 import SummaryType from './models/SummaryType'
 import UserPermission from './models/UserPermission'
 
-import ApplicationDeploymentService from './services/ApplicationDeploymentService'
 import ExperimentService from './services/ExperimentService'
 import ExperimentSearchService from './services/ExperimentSearchService'
 import FullExperimentService from './services/FullExperimentService'
@@ -57,6 +59,7 @@ exports.models = {
   BaseModel,
   BatchQueue,
   BatchQueueResourcePolicy,
+  CommandObject,
   ComputeResourcePolicy,
   DataType,
   Experiment,
@@ -68,8 +71,10 @@ exports.models = {
   GroupResourceProfile,
   InputDataObjectType,
   OutputDataObjectType,
+  ParallelismType,
   Project,
   ResourcePermissionType,
+  SetEnvPath,
   SharedEntity,
   SummaryType,
   UserPermission,
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationDeploymentDescription.js
b/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationDeploymentDescription.js
index f983455..812d540 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationDeploymentDescription.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/ApplicationDeploymentDescription.js
@@ -1,4 +1,7 @@
 import BaseModel from './BaseModel'
+import ParallelismType from './ParallelismType';
+import CommandObject from './CommandObject';
+import SetEnvPath from './SetEnvPath';
 
 
 const FIELDS = [
@@ -6,15 +9,42 @@ const FIELDS = [
   'appModuleId',
   'computeHostId',
   'executablePath',
-  'parallelism',
+  {
+    name: 'parallelism',
+    type: ParallelismType,
+    default: ParallelismType.SERIAL,
+  },
   'appDeploymentDescription',
-  // TODO: map these
-  // 'moduleLoadCmds',
-  // 'libPrependPaths',
-  // 'libAppendPaths',
-  // 'setEnvironment',
-  // 'preJobCommands',
-  // 'postJobCommands',
+  {
+    name: 'moduleLoadCmds',
+    type: CommandObject,
+    list: true,
+  },
+  {
+    name: 'libPrependPaths',
+    type: SetEnvPath,
+    list: true,
+  },
+  {
+    name: 'libAppendPaths',
+    type: SetEnvPath,
+    list: true,
+  },
+  {
+    name: 'setEnvironment',
+    type: SetEnvPath,
+    list: true,
+  },
+  {
+    name: 'preJobCommands',
+    type: CommandObject,
+    list: true,
+  },
+  {
+    name: 'postJobCommands',
+    type: CommandObject,
+    list: true,
+  },
   'defaultQueueName',
   'defaultNodeCount',
   'defaultCPUCount',
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/CommandObject.js
b/django_airavata/apps/api/static/django_airavata_api/js/models/CommandObject.js
new file mode 100644
index 0000000..60347b0
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/CommandObject.js
@@ -0,0 +1,20 @@
+import BaseModel from './BaseModel'
+import uuidv4 from 'uuid/v4'
+
+
+const FIELDS = [
+  'command',
+  'commandOrder',
+];
+
+export default class CommandObject extends BaseModel {
+
+  constructor(data = {}) {
+    super(FIELDS, data);
+    this._key = data.key ? data.key : uuidv4();
+  }
+
+  get key() {
+    return this._key;
+  }
+}
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/ParallelismType.js
b/django_airavata/apps/api/static/django_airavata_api/js/models/ParallelismType.js
new file mode 100644
index 0000000..c7a6043
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/ParallelismType.js
@@ -0,0 +1,12 @@
+import BaseEnum from './BaseEnum'
+
+export default class ParallelismType extends BaseEnum {
+}
+ParallelismType.init([
+  "SERIAL",
+  "MPI",
+  "OPENMP",
+  "OPENMP_MPI",
+  "CCM",
+  "CRAY_MPI"
+]);
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/SetEnvPath.js b/django_airavata/apps/api/static/django_airavata_api/js/models/SetEnvPath.js
new file mode 100644
index 0000000..88165c7
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/SetEnvPath.js
@@ -0,0 +1,21 @@
+import BaseModel from './BaseModel'
+import uuidv4 from 'uuid/v4'
+
+
+const FIELDS = [
+  'name',
+  'value',
+  'envPathOrder',
+];
+
+export default class SetEnvPath extends BaseModel {
+
+  constructor(data = {}) {
+    super(FIELDS, data);
+    this._key = data.key ? data.key : uuidv4();
+  }
+
+  get key() {
+    return this._key;
+  }
+}
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/service_config.js b/django_airavata/apps/api/static/django_airavata_api/js/service_config.js
index a737ea2..f7b7408 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/service_config.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/service_config.js
@@ -95,7 +95,7 @@ export default {
   "ComputeResources": {
     url: "/api/compute-resources",
     viewSet: [{
-      name: "list"
+      name: "retrieve"
     }, {
       name: "names",
       url: "/api/compute-resources/all_names/",
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index 63966bc..3ca84de 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -4,6 +4,7 @@ from django.conf import settings
 from django.contrib.auth.decorators import login_required
 from django.core.exceptions import ObjectDoesNotExist
 from django.http import FileResponse, Http404, JsonResponse
+from django.urls import reverse
 from rest_framework import mixins
 from rest_framework import status
 from rest_framework.decorators import detail_route
@@ -521,18 +522,30 @@ class ComputeResourceViewSet(mixins.RetrieveModelMixin,
     lookup_value_regex = '[^/]+'
 
     def get_instance(self, lookup_value, format=None):
-        return self.request.airavata_client.getComputeResource(self.authz_token, lookup_value)
+        return self.request.airavata_client.getComputeResource(
+            self.authz_token, lookup_value)
 
     @list_route()
     def all_names(self, request, format=None):
         """Return a map of compute resource names keyed by resource id."""
-        return Response(request.airavata_client.getAllComputeResourceNames(request.authz_token))
+        return Response(
+            request.airavata_client.getAllComputeResourceNames(
+                request.authz_token))
 
     @list_route()
     def all_names_list(self, request, format=None):
         """Return a list of compute resource names keyed by resource id."""
-        all_names = request.airavata_client.getAllComputeResourceNames(request.authz_token)
-        return Response([{'host_id': host_id, 'host': host} for host_id, host in all_names.items()])
+        all_names = request.airavata_client.getAllComputeResourceNames(
+            request.authz_token)
+        return Response([
+            {
+                'host_id': host_id,
+                'host': host,
+                'url': request.build_absolute_uri(
+                    reverse('django_airavata_api:compute-resource-detail',
+                            args=[host_id]))
+            } for host_id, host in all_names.items()
+        ])
 
     @detail_route()
     def queues(self, request, compute_resource_id, format=None):


Mime
View raw message