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/08/16 13:19:42 UTC
[airavata-django-portal] 04/04: AIRAVATA-2727 Credential token
editor
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 6d6d0ac0a98e5dce7f161a599ef01a7380158d4f
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Wed Aug 15 15:31:19 2018 -0400
AIRAVATA-2727 Credential token editor
---
.../ComputePreference.vue | 31 +++++++++++++++++++++-
django_airavata/apps/api/serializers.py | 16 +++++++----
.../api/static/django_airavata_api/js/index.js | 3 +++
.../django_airavata_api/js/models/BaseEnum.js | 10 ++++---
.../django_airavata_api/js/models/BaseModel.js | 9 +++++--
.../js/models/CredentialSummary.js | 25 +++++++++++++++++
.../django_airavata_api/js/models/SummaryType.js | 9 +++++++
.../django_airavata_api/js/service_config.js | 10 ++++++-
django_airavata/apps/api/thrift_utils.py | 27 +++++++++++++++++--
django_airavata/apps/api/urls.py | 2 ++
django_airavata/apps/api/views.py | 10 +++++++
11 files changed, 137 insertions(+), 15 deletions(-)
diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputePreference.vue b/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputePreference.vue
index a92ec70..a43a971 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputePreference.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputePreference.vue
@@ -17,6 +17,15 @@
v-model="data.loginUserName">
</b-form-input>
</b-form-group>
+ <b-form-group label="SSH Credential" label-for="credential-store-token">
+ <b-form-select id="credential-store-token"
+ v-model="data.resourceSpecificCredentialStoreToken"
+ :options="credentialStoreTokenOptions">
+ <template slot="first">
+ <option :value="null"><em>Use this profile's default SSH credential</em></option>
+ </template>
+ </b-form-select>
+ </b-form-group>
<b-form-group label="Allocation Project Number" label-for="allocation-number">
<b-form-input id="allocation-number" type="text"
v-model="data.allocationProjectNumber">
@@ -116,6 +125,7 @@
} else if (!this.computeResourcePolicy) {
this.createDefaultComputeResourcePolicy(computeResourcePromise);
}
+ this.fetchCredentialSummaries();
},
data: function () {
return {
@@ -126,7 +136,22 @@
computeResource: {
batchQueues: [],
jobSubmissionInterfaces: []
- }
+ },
+ credentialSummaries: [],
+ }
+ },
+ computed: {
+ credentialStoreTokenOptions: function() {
+ const options = this.credentialSummaries
+ .filter(summary => summary.type === models.SummaryType.SSH)
+ .map(summary => {
+ return {
+ value: summary.token,
+ text: summary.description
+ }
+ });
+ options.sort((a, b) => a.text.toLowerCase().localeCompare(b.text.toLowerCase()));
+ return options;
}
},
mixins: [VModelMixin],
@@ -168,6 +193,10 @@
return this.computeResource = value;
});
},
+ fetchCredentialSummaries: function() {
+ return services.CredentialSummaryService.list()
+ .then(summaries => this.credentialSummaries = summaries);
+ },
save: function() {
let groupResourceProfile = this.localGroupResourceProfile.clone();
groupResourceProfile.mergeComputeResourcePreference(this.data, this.localComputeResourcePolicy, this.localBatchQueueResourcePolicies);
diff --git a/django_airavata/apps/api/serializers.py b/django_airavata/apps/api/serializers.py
index 3ccd9d8..a174565 100644
--- a/django_airavata/apps/api/serializers.py
+++ b/django_airavata/apps/api/serializers.py
@@ -15,13 +15,14 @@ from airavata.model.appcatalog.appdeployment.ttypes import (ApplicationDeploymen
SetEnvPaths)
from airavata.model.appcatalog.appinterface.ttypes import \
ApplicationInterfaceDescription
-from airavata.model.appcatalog.computeresource.ttypes \
- import (BatchQueue,
- ComputeResourceDescription)
+from airavata.model.appcatalog.computeresource.ttypes import (BatchQueue,
+ ComputeResourceDescription)
from airavata.model.appcatalog.groupresourceprofile.ttypes import \
GroupResourceProfile
from airavata.model.application.io.ttypes import (InputDataObjectType,
OutputDataObjectType)
+from airavata.model.credential.store.ttypes import (CredentialSummary,
+ SummaryType)
from airavata.model.data.replica.ttypes import (DataProductModel,
DataReplicaLocationModel)
from airavata.model.experiment.ttypes import (ExperimentModel,
@@ -32,8 +33,7 @@ from airavata.model.status.ttypes import ExperimentStatus
from airavata.model.user.ttypes import UserProfile
from airavata.model.workspace.ttypes import Project
-from . import datastore
-from . import thrift_utils
+from . import datastore, thrift_utils
log = logging.getLogger(__name__)
@@ -615,3 +615,9 @@ class SharedEntitySerializer(serializers.Serializer):
def get_isOwner(self, shared_entity):
request = self.context['request']
return shared_entity['owner'].userId == request.user.username
+
+
+class CredentialSummarySerializer(
+ thrift_utils.create_serializer_class(CredentialSummary)):
+ type = thrift_utils.ThriftEnumField(SummaryType)
+ persistedTime = UTCPosixTimestampDateTimeField()
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 49f08c1..0e3502b 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
@@ -17,6 +17,7 @@ import OutputDataObjectType from './models/OutputDataObjectType'
import Project from './models/Project'
import ResourcePermissionType from './models/ResourcePermissionType'
import SharedEntity from './models/SharedEntity'
+import SummaryType from './models/SummaryType'
import UserPermission from './models/UserPermission'
import ApplicationDeploymentService from './services/ApplicationDeploymentService'
@@ -60,6 +61,7 @@ exports.models = {
Project,
ResourcePermissionType,
SharedEntity,
+ SummaryType,
UserPermission,
}
@@ -67,6 +69,7 @@ exports.services = {
ApplicationDeploymentService,
ApplicationInterfaceService,
ApplicationModuleService,
+ CredentialSummaryService: ServiceFactory.service("CredentialSummaries"),
ExperimentService,
ExperimentSearchService,
FullExperimentService,
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/BaseEnum.js b/django_airavata/apps/api/static/django_airavata_api/js/models/BaseEnum.js
index bb11276..d6d9f07 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/BaseEnum.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/BaseEnum.js
@@ -1,13 +1,15 @@
export default class BaseEnum {
- constructor(name, value) {
+ // TODO: add parameter
+ constructor(name, value, writeName=false) {
this.name = name;
this.value = value;
+ this.writeName = writeName;
// immutable
Object.freeze(this);
}
toJSON() {
- return this.value;
+ return this.writeName ? this.name : this.value;
}
static byName(name) {
return this.values.find(x => x.name === name);
@@ -16,8 +18,8 @@ export default class BaseEnum {
return this.values.find(x => x.value === value);
}
// This must be called to initialize static methods on the Enum subclass
- static init(names) {
- const enums = names.map((name, index) => new this(name, index));
+ static init(names, writeName=false) {
+ const enums = names.map((name, index) => new this(name, index, writeName));
Object.freeze(enums);
Object.defineProperty(this, 'values', {get: function() { return enums;}});
this.values.forEach(v => this[v.name] = v);
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js b/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js
index 56cf29f..43cc5a6 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js
@@ -60,8 +60,13 @@ export default class BaseModel {
if (fieldValue instanceof BaseEnum){
return fieldValue;
}
- // Otherwise it is an integer that we need to convert to enum
- return modelClass.byValue(fieldValue);
+ if (typeof fieldValue === 'string') {
+ // convert by name if type is string
+ return modelClass.byName(fieldValue);
+ } else {
+ // Otherwise it is an integer that we need to convert to enum
+ return modelClass.byValue(fieldValue);
+ }
} else {
return new modelClass(fieldValue);
}
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/CredentialSummary.js b/django_airavata/apps/api/static/django_airavata_api/js/models/CredentialSummary.js
new file mode 100644
index 0000000..a85d89e
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/CredentialSummary.js
@@ -0,0 +1,25 @@
+import BaseModel from './BaseModel'
+import SummaryType from './SummaryType'
+
+const FIELDS = [
+ {
+ name: 'type',
+ type: SummaryType,
+ },
+ 'gatewayId',
+ 'username',
+ 'publicKey',
+ {
+ name: 'persistedTime',
+ type: Date,
+ },
+ 'token',
+ 'description',
+];
+
+export default class CredentialSummary extends BaseModel {
+
+ constructor(data = {}) {
+ super(FIELDS, data);
+ }
+}
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/SummaryType.js b/django_airavata/apps/api/static/django_airavata_api/js/models/SummaryType.js
new file mode 100644
index 0000000..7e01256
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/SummaryType.js
@@ -0,0 +1,9 @@
+import BaseEnum from './BaseEnum'
+
+export default class SummaryType extends BaseEnum {
+}
+SummaryType.init([
+ 'SSH',
+ 'PASSWD',
+ 'CERT',
+], true);
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 86074ed..6b62431 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
@@ -1,4 +1,5 @@
import ApplicationDeploymentDescription from './models/ApplicationDeploymentDescription'
+import CredentialSummary from './models/CredentialSummary'
import Group from './models/Group'
import GroupResourceProfile from './models/GroupResourceProfile'
import SharedEntity from './models/SharedEntity'
@@ -58,6 +59,13 @@ export default {
}],
modelClass: ApplicationDeploymentDescription,
},
+ "CredentialSummaries": {
+ url: "/api/credential-summaries/",
+ viewSet: [{
+ name: "list"
+ }],
+ modelClass: CredentialSummary,
+ },
"GroupResourceProfiles": {
url: "/api/group-resource-profiles/",
viewSet: true,
@@ -82,4 +90,4 @@ export default {
}],
modelClass: UserProfile,
},
-}
\ No newline at end of file
+}
diff --git a/django_airavata/apps/api/thrift_utils.py b/django_airavata/apps/api/thrift_utils.py
index dd4442a..bbff521 100644
--- a/django_airavata/apps/api/thrift_utils.py
+++ b/django_airavata/apps/api/thrift_utils.py
@@ -5,8 +5,10 @@ import copy
import datetime
from django.utils import six
-from rest_framework.serializers import CharField, BooleanField, DecimalField, IntegerField, Serializer, \
- DictField, SerializerMetaclass, ListField, DateTimeField
+from rest_framework.serializers import (BooleanField, CharField, DateTimeField,
+ DecimalField, DictField, Field,
+ IntegerField, ListField, Serializer,
+ SerializerMetaclass, ValidationError)
from thrift.Thrift import TType
# used to map apache thrift data types to django serializer fields
@@ -46,6 +48,27 @@ class UTCPosixTimestampDateTimeField(DateTimeField):
return int(datetime.datetime.utcnow().timestamp() * 1000)
+class ThriftEnumField(Field):
+
+ def __init__(self, enumClass, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.enumClass = enumClass
+
+ def to_representation(self, obj):
+ if obj is None:
+ return None
+ return self.enumClass._VALUES_TO_NAMES[obj]
+
+ def to_internal_value(self, data):
+ if self.allow_null and data is None:
+ return None
+ if data not in self.enumClass._NAMES_TO_VALUES:
+ raise ValidationError(
+ "Not an allowed name of enum {}".format(
+ self.enumClass.__name__))
+ return self.enumClass._NAMES_TO_VALUES.get(data, None)
+
+
def create_serializer(thrift_data_type, enable_date_time_conversion=False, **kwargs):
"""
Create django rest framework serializer based on the thrift data type
diff --git a/django_airavata/apps/api/urls.py b/django_airavata/apps/api/urls.py
index c6e9c56..5e4f0bf 100644
--- a/django_airavata/apps/api/urls.py
+++ b/django_airavata/apps/api/urls.py
@@ -26,6 +26,8 @@ router.register(r'shared-entities', views.SharedEntityViewSet,
base_name='shared-entity')
router.register(r'compute-resources', views.ComputeResourceViewSet,
base_name='compute-resource')
+router.register(r'credential-summaries', views.CredentialSummaryViewSet,
+ base_name='credential-summary')
app_name = 'django_airavata_api'
urlpatterns = [
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index a2f473c..f3b4359 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -869,3 +869,13 @@ class SharedEntityViewSet(mixins.RetrieveModelMixin,
self.request.airavata_client.revokeSharingOfResourceFromGroups(
self.authz_token, entity_id,
{group_id: permission_type for group_id in group_ids})
+
+
+class CredentialSummaryViewSet(mixins.ListModelMixin,
+ GenericAPIBackedViewSet):
+ serializer_class = serializers.CredentialSummarySerializer
+
+ def get_list(self):
+ # NOTE: only supported SummaryType is SSH for now
+ return self.request.airavata_client.getAllCredentialSummaryForGateway(
+ self.authz_token, SummaryType.SSH, settings.GATEWAY_ID)