Repository: ambari Updated Branches: refs/heads/trunk e17af8b29 -> 8b43080a0
AMBARI-19478. Need to handle unsupported configurations gracefully in workflow actions. (pallavkul via Padma Priya) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/8b43080a Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/8b43080a Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/8b43080a Branch: refs/heads/trunk Commit: 8b43080a0025f9146172005b20df3f3a170782fe Parents: e17af8b Author: pallavkul <[email protected]> Authored: Mon Jan 16 14:48:19 2017 +0530 Committer: pallavkul <[email protected]> Committed: Mon Jan 16 14:48:19 2017 +0530 ---------------------------------------------------------------------- .../resources/ui/app/components/sla-info.js | 1 + .../ui/app/components/workflow-action-editor.js | 9 +++++++ .../ui/app/domain/actionjob_hanlder.js | 28 +++++++++++++++++++- .../ui/app/domain/custom-mapping-handler.js | 28 ++++++++++++++++++++ .../resources/ui/app/domain/mapping-utils.js | 16 ++++++++--- .../ui/app/domain/workflow-json-importer.js | 3 +++ .../ui/app/domain/workflow-xml-generator.js | 5 ++++ .../src/main/resources/ui/app/styles/app.less | 12 +++++++++ .../components/workflow-action-editor.hbs | 11 ++++++++ 9 files changed, 108 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/8b43080a/contrib/views/wfmanager/src/main/resources/ui/app/components/sla-info.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/sla-info.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/sla-info.js index 7390205..bcc209b 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/components/sla-info.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/sla-info.js @@ -148,6 +148,7 @@ export default Ember.Component.extend(Validations, { this.$('input[name="nominalTime"]').datetimepicker({ useCurrent: false, showClose : true, + format: 'MM/DD/YYYY hh:mm A', defaultDate : this.get('slaInfo.nominalTime') }); this.sendAction('register','slaInfo', this); http://git-wip-us.apache.org/repos/asf/ambari/blob/8b43080a/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-action-editor.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-action-editor.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-action-editor.js index 8ee5a0a..8a3c7cf 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-action-editor.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/workflow-action-editor.js @@ -58,6 +58,15 @@ export default Ember.Component.extend( Ember.Evented,{ return this.get('actionIcons')[this.get('actionType')]; }), saveClicked : false, + containsUnsupportedProperties : Ember.computed('actionModel.unsupportedProperties', function(){ + return this.get('actionModel.unsupportedProperties') ? !Ember.isEmpty(Object.keys(this.get('actionModel.unsupportedProperties'))) : false; + }), + unsupportedPropertiesXml : Ember.computed('actionModel.unsupportedProperties', function(){ + if(this.get('containsUnsupportedProperties')){ + var x2js = new X2JS(); + return vkbeautify.xml(x2js.json2xml_str(this.get('actionModel.unsupportedProperties'))); + } + }), fileBrowser : Ember.inject.service('file-browser'), onDestroy : function(){ this.set('transition',{}); http://git-wip-us.apache.org/repos/asf/ambari/blob/8b43080a/contrib/views/wfmanager/src/main/resources/ui/app/domain/actionjob_hanlder.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/actionjob_hanlder.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/actionjob_hanlder.js index 99d96ac..0bb2fb8 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/actionjob_hanlder.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/actionjob_hanlder.js @@ -17,6 +17,7 @@ import Ember from 'ember'; import CommonUtils from "../utils/common-utils"; +import CustomMappingHandler from "../domain/custom-mapping-handler"; import {MappingMixin,ConfigurationMapper,PrepareMapper} from "../domain/mapping-utils"; var ActionJobHandler=Ember.Object.extend(MappingMixin,{ type:"actionJob", @@ -42,7 +43,15 @@ var ActionJobHandler=Ember.Object.extend(MappingMixin,{ nodeObj[this.get("actionType")]["_xmlns"]=schema; } } - this.handleMapping(nodeDomain,actionObj,this.mapping,nodeName); + var customMapping = CustomMappingHandler.getMapping(nodeName); + var mapping = this.mapping.copy(); + if(customMapping){ + Object.keys(customMapping).forEach((customProp)=>{ + var index = mapping.indexOf(mapping.findBy('xml',customMapping[customProp].prevSibling)); + mapping.insertAt(index+1, {xml:customProp,domain:customProp}); + }.bind(this)); + } + this.handleMapping(nodeDomain,actionObj,mapping,nodeName); }, /* jshint unused:vars */ validate(nodeDomain){ @@ -50,6 +59,23 @@ var ActionJobHandler=Ember.Object.extend(MappingMixin,{ }, handleImport(actionNode,json){ this.handleImportMapping(actionNode,json,this.mapping); + var customMapping = {}; + var x2js = new X2JS(); + var actionXml = x2js.json2xml({action:json}); + Object.keys(json).forEach((propKey)=>{ + if(!this.mapping.findBy('xml', propKey) && propKey !== '_xmlns'){ + var eltInXml = actionXml.getElementsByTagName(propKey)[0]; + var previousSiblingXml = eltInXml.previousSibling; + var prevSibling = previousSiblingXml ? Object.keys(x2js.xml_str2json(new XMLSerializer().serializeToString(previousSiblingXml)))[0] : undefined; + customMapping[propKey] = { + prevSibling : prevSibling, + mapping : {xml:propKey,domain:propKey} + }; + } + }); + if(!Ember.isEmpty(Object.keys(customMapping))){ + actionNode.customMapping = customMapping; + } } }); var JavaActionJobHandler=ActionJobHandler.extend({ http://git-wip-us.apache.org/repos/asf/ambari/blob/8b43080a/contrib/views/wfmanager/src/main/resources/ui/app/domain/custom-mapping-handler.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/custom-mapping-handler.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/custom-mapping-handler.js new file mode 100644 index 0000000..aa003e6 --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/custom-mapping-handler.js @@ -0,0 +1,28 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You under the Apache License, Version 2.0 +* (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import Ember from 'ember'; +import CommonUtils from "../utils/common-utils"; +export default Ember.Object.create({ + customMappingMap : new Map(), + setMapping(id, mapping){ + this.customMappingMap.set(id, mapping); + }, + getMapping(id){ + return this.customMappingMap.get(id); + }, +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/8b43080a/contrib/views/wfmanager/src/main/resources/ui/app/domain/mapping-utils.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/mapping-utils.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/mapping-utils.js index d4d8f50..1929ddf 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/mapping-utils.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/mapping-utils.js @@ -62,12 +62,20 @@ var MappingMixin= Ember.Mixin.create({ }, handleImportMapping(actionNode,json,mappings){ - var domain={}; + var domain={ + unsupportedProperties : {} + }; if (json._xmlns){ var version=CommonUtils.extractSchemaVersion(json._xmlns); //this.schemaVersions.setActionVersion(actionNode.actionType,version); } actionNode.set("domain",domain); + Object.keys(json).forEach((propKey)=>{ + if(!mappings.findBy('xml', propKey) && propKey !=='_xmlns'){ + domain.unsupportedProperties[propKey] = json[propKey]; + domain[propKey] = json[propKey]; + } + }); mappings.forEach(function(mapping){ if (!mapping.occurs) { mapping.occurs = "once"; @@ -210,13 +218,13 @@ var SLAMapper= Ember.Object.extend({ if (sla.nominalTime){ slaInfo[slaPrefix+":"+"nominal-time"]=sla.nominalTime; } - if (sla.shouldStart){ + if (sla.shouldStart && sla.shouldStart.time){ slaInfo[slaPrefix+":"+"should-start"]="${"+sla.shouldStart.time+ "*"+sla.shouldStart.unit+"}"; } - if (sla.shouldEnd){ + if (sla.shouldEnd && sla.shouldEnd.time){ slaInfo[slaPrefix+":"+"should-end"]="${"+sla.shouldEnd.time+ "*"+sla.shouldEnd.unit+"}"; } - if (sla.maxDuration){ + if (sla.maxDuration && sla.maxDuration.time){ slaInfo[slaPrefix+":"+"max-duration"]="${"+sla.maxDuration.time+ "*"+sla.maxDuration.unit+"}"; } if (sla.alertEvents){ http://git-wip-us.apache.org/repos/asf/ambari/blob/8b43080a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-json-importer.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-json-importer.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-json-importer.js index 527badf..656df4b 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-json-importer.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-json-importer.js @@ -61,6 +61,9 @@ var WorkflowJsonImporter= Ember.Object.extend({ node.set("domain",nodeJson.domain); node.set("errorMsgs",nodeJson.errorMsgs); node.set("errors",nodeJson.errors); + if(nodeJson.customMapping){ + node.set('customMapping', nodeJson.customMapping); + } nodeMap.set(node.id,node); if (nodeJson.transitions){ nodeJson.transitions.forEach(function(nodeTran){ http://git-wip-us.apache.org/repos/asf/ambari/blob/8b43080a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js index b9e4307..e30750f 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/domain/workflow-xml-generator.js @@ -18,6 +18,8 @@ import Ember from 'ember'; import {WorkflowXmlMapper} from '../domain/workflow_xml_mapper'; import {NodeVisitor} from '../domain/node-visitor'; +import CustomMappingHandler from "../domain/custom-mapping-handler"; + var WorkflowGenerator= Ember.Object.extend({ workflowMapper:null, x2js : new X2JS({useDoubleQuotes:true}), @@ -120,6 +122,9 @@ var WorkflowGenerator= Ember.Object.extend({ if (!self.ignoreErrors && !node.get("domain")){ this.workflowContext.addError({node : node, message : "Action Properties are empty"}); }else{ + if(node.customMapping){ + CustomMappingHandler.setMapping(node.name, node.customMapping); + } jobHandler.handle(node.get("domain"),nodeObj,node.get("name")); if (!self.ignoreErrors){ var errors=jobHandler.validate(node.get("domain")); http://git-wip-us.apache.org/repos/asf/ambari/blob/8b43080a/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.less ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.less b/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.less index dcf2905..bc0e419 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.less +++ b/contrib/views/wfmanager/src/main/resources/ui/app/styles/app.less @@ -1615,3 +1615,15 @@ input:invalid { .visibility-hidden { visibility: hidden; } + +.unsupported-elt-warning span{ + padding: 2px; +} +.unsupported-elt-warning .fa-exclamation-triangle{ + padding-right: 5px; + color: #f0ad4e; +} +.unsupported-xml{ + width: 100%; + min-height: 100px; +} http://git-wip-us.apache.org/repos/asf/ambari/blob/8b43080a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-action-editor.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-action-editor.hbs b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-action-editor.hbs index 069c052..b36578d 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-action-editor.hbs +++ b/contrib/views/wfmanager/src/main/resources/ui/app/templates/components/workflow-action-editor.hbs @@ -35,6 +35,9 @@ {{#decision-config actionModel=actionModel register="registerChild"}}{{/decision-config}} {{/if}} {{#if (eq nodeType 'action')}} + {{#if containsUnsupportedProperties}} + <span class="unsupported-elt-warning"> <p><a href='#unsupported-props'><i class="fa fa-exclamation-triangle" aria-hidden="true"></i>Action contains elements that are not currently supported by the designer.</a></p></span> + {{/if}} {{#if (eq actionType 'java')}} {{#java-action actionModel=actionModel transition=transition killNodes=killNodes openFileBrowser="openFileBrowser" register="registerChild" addKillNode="addKillNode" currentNode=currentNode credentials=credentials}}{{/java-action}} {{else if (eq actionType 'hive')}} @@ -62,6 +65,14 @@ {{else if (eq actionType 'sub-workflow')}} {{#sub-workflow actionModel=actionModel transition=transition killNodes=killNodes openFileBrowser="openFileBrowser" register="registerChild" addKillNode="addKillNode" currentNode=currentNode credentials=credentials}}{{/sub-workflow}} {{/if}} + {{#if containsUnsupportedProperties}} + <div id="unsupported-props" class=" panel panel-default"> + <div class="panel-heading">Unsupported Properties</div> + <div class="panel-body handlerPanel"> + {{textarea class="unsupported-xml" value=unsupportedPropertiesXml}} + </div> + </div> + {{/if}} {{/if}} {{#if (eq nodeType 'kill')}} <div class="form-group">
