YARN-6419. Support to launch new native-service from new YARN UI. Contributed by Akhil PB.
Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/c90220ee Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/c90220ee Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/c90220ee Branch: refs/heads/yarn-native-services Commit: c90220ee08494403470b916496c8532c6c26085d Parents: 2fe0602 Author: Sunil G <sun...@apache.org> Authored: Wed May 3 12:30:55 2017 +0530 Committer: Sunil G <sun...@apache.org> Committed: Tue May 30 20:46:30 2017 +0530 ---------------------------------------------------------------------- .../main/webapp/app/adapters/restabstract.js | 50 ++++ .../main/webapp/app/adapters/yarn-servicedef.js | 31 +++ .../webapp/app/components/breadcrumb-bar.js | 1 + .../webapp/app/components/deploy-service.js | 167 +++++++++++ .../app/components/fileconfig-viewer-dialog.js | 36 +++ .../main/webapp/app/components/info-tooltip.js | 44 +++ .../app/components/service-component-table.js | 56 ++++ .../app/components/service-config-table.js | 89 ++++++ .../app/components/service-fileconfig-table.js | 112 ++++++++ .../main/webapp/app/components/upload-config.js | 54 ++++ .../app/controllers/yarn-deploy-service.js | 69 +++++ .../main/webapp/app/models/yarn-servicedef.js | 278 +++++++++++++++++++ .../src/main/webapp/app/router.js | 1 + .../webapp/app/routes/yarn-deploy-service.js | 27 ++ .../src/main/webapp/app/services/hosts.js | 4 + .../src/main/webapp/app/styles/app.css | 164 +++++++++++ .../main/webapp/app/templates/application.hbs | 2 + .../app/templates/components/breadcrumb-bar.hbs | 4 +- .../app/templates/components/deploy-service.hbs | 157 +++++++++++ .../components/fileconfig-viewer-dialog.hbs | 53 ++++ .../app/templates/components/info-tooltip.hbs | 20 ++ .../components/service-component-table.hbs | 113 ++++++++ .../components/service-config-table.hbs | 130 +++++++++ .../components/service-fileconfig-table.hbs | 152 ++++++++++ .../app/templates/components/upload-config.hbs | 44 +++ .../app/templates/yarn-deploy-service.hbs | 33 +++ .../main/webapp/app/templates/yarn-services.hbs | 4 + .../src/main/webapp/app/utils/info-seeder.js | 26 ++ .../src/main/webapp/config/configs.env | 7 + .../src/main/webapp/config/default-config.js | 7 +- .../components/deploy-service-test.js | 43 +++ .../components/fileconfig-viewer-dialog-test.js | 43 +++ .../integration/components/info-tooltip-test.js | 43 +++ .../components/service-component-table-test.js | 43 +++ .../components/service-config-table-test.js | 43 +++ .../components/service-fileconfig-table-test.js | 43 +++ .../components/upload-config-test.js | 43 +++ .../tests/unit/adapters/yarn-servicedef-test.js | 30 ++ .../controllers/yarn-deploy-service-test.js | 30 ++ .../tests/unit/models/yarn-servicedef-test.js | 30 ++ .../unit/routes/yarn-deploy-service-test.js | 29 ++ 41 files changed, 2352 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/restabstract.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/restabstract.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/restabstract.js new file mode 100644 index 0000000..df409d6 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/restabstract.js @@ -0,0 +1,50 @@ +/** + * 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 DS from 'ember-data'; +import Ember from 'ember'; + +export default DS.RESTAdapter.extend({ + address: null, //Must be set by inheriting classes + restNameSpace: null, //Must be set by inheriting classes + serverName: null, //Must be set by inheriting classes + + headers: { + Accept: 'application/json' + }, + + host: Ember.computed("address", function() { + var address = this.get("address"); + return this.get(`hosts.${address}`); + }), + + namespace: Ember.computed("restNameSpace", function() { + var nameSpace = this.get("restNameSpace"); + return this.get(`env.app.namespaces.${nameSpace}`); + }), + + ajax(url, method, options) { + options = options || {}; + options.crossDomain = true; + options.xhrFields = { + withCredentials: true + }; + options.targetServer = this.get('serverName'); + return this._super(url, method, options); + } +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-servicedef.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-servicedef.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-servicedef.js new file mode 100644 index 0000000..c362f5e --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-servicedef.js @@ -0,0 +1,31 @@ +/** + * 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 RESTAbstractAdapter from './restabstract'; + +export default RESTAbstractAdapter.extend({ + address: "dashWebAddress", + restNameSpace: "dashService", + serverName: "DASH", + + deployService(request) { + var url = this.buildURL(); + return this.ajax(url, "POST", {data: request}); + } +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/breadcrumb-bar.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/breadcrumb-bar.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/breadcrumb-bar.js index 44edb8e..b8d974a 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/breadcrumb-bar.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/breadcrumb-bar.js @@ -21,6 +21,7 @@ import Ember from 'ember'; export default Ember.Component.extend({ breadcrumbs: null, + hideRefresh: false, actions:{ refresh: function () { http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/deploy-service.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/deploy-service.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/deploy-service.js new file mode 100644 index 0000000..90e10e5 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/deploy-service.js @@ -0,0 +1,167 @@ +/** + * 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'; + +export default Ember.Component.extend({ + viewType: 'standard', + savedStandardTemplates: null, + savedJsonTemplates: null, + savedTemplateName: '', + serviceDef: null, + customServiceDef: '', + serviceResp: null, + isLoading: false, + + actions: { + showSaveTemplateModal() { + this.$('#saveListModal').modal('show'); + }, + + deployService() { + this.set('serviceResp', null); + if (this.get('isStandardViewType')) { + this.sendAction("deployServiceDef", this.get('serviceDef')); + } else { + try { + var parsed = JSON.parse(this.get('customServiceDef')); + this.sendAction("deployServiceJson", parsed); + } catch (err) { + this.set('serviceResp', {type: 'error', message: 'Invalid JSON: ' + err.message}); + throw err; + } + } + }, + + updateViewType(type) { + this.set('viewType', type); + }, + + addToSavedList() { + this.unselectAllSavedList(); + if (this.get('isStandardViewType')) { + this.get('savedStandardTemplates').addObject({ + name: this.get('savedTemplateName'), + defId: this.get('serviceDef.id'), + active: true + }); + this.set('serviceDef.isCached', true); + } else { + this.get('savedJsonTemplates').addObject({ + name: this.get('savedTemplateName'), + custom: this.get('customServiceDef'), + active: true + }); + } + this.$('#saveListModal').modal('hide'); + this.set('savedTemplateName', ''); + }, + + updateServiceDef(def) { + this.selectActiveListItem(def); + if (this.get('isStandardViewType')) { + this.set('serviceDef', this.getStore().peekRecord('yarn-servicedef', def.defId)); + } else { + this.set('customServiceDef', def.custom); + } + }, + + clearConfigs() { + this.unselectAllSavedList(); + this.set('serviceResp', null); + if (this.get('isStandardViewType')) { + var oldDef = this.get('serviceDef'); + var def = oldDef.createNewServiceDef(); + this.set('serviceDef', def); + if (!oldDef.get('isCached')) { + oldDef.deleteRecord(); + } + } else { + this.set('customServiceDef', ''); + } + }, + + removeFromSavedList(list) { + if (list.active) { + this.send('clearConfigs'); + } + if (this.get('isStandardViewType')) { + this.get('savedStandardTemplates').removeObject(list); + } else { + this.get('savedJsonTemplates').removeObject(list); + } + }, + + clearServiceResponse() { + this.set('serviceResp', null); + } + }, + + didInsertElement() { + var self = this; + self.$().find('.modal').on('shown.bs.modal', function() { + self.$().find('.modal.in').find('input.form-control:first').focus(); + }); + }, + + selectActiveListItem(item) { + this.unselectAllSavedList(); + Ember.set(item, 'active', true); + }, + + unselectAllSavedList() { + this.get('getSavedList').forEach(function(item) { + Ember.set(item, 'active', false); + }); + }, + + getSavedList: Ember.computed('viewType', function() { + if (this.get('isStandardViewType')) { + return this.get('savedStandardTemplates'); + } else { + return this.get('savedJsonTemplates'); + } + }), + + getStore: function() { + return this.get('serviceDef.store'); + }, + + isStandardViewType: Ember.computed.equal('viewType', 'standard'), + + isCustomViewType: Ember.computed.equal('viewType', 'custom'), + + isValidTemplateName: Ember.computed.notEmpty('savedTemplateName'), + + isValidServiceDef: Ember.computed('serviceDef.name', 'serviceDef.queue', 'serviceDef.serviceComponents.[]', function () { + return this.get('serviceDef').isValidServiceDef(); + }), + + isValidCustomServiceDef: Ember.computed.notEmpty('customServiceDef'), + + enableSaveOrDeployBtn: Ember.computed('isValidServiceDef', 'isValidCustomServiceDef', 'viewType', 'isLoading', function() { + if (this.get('isLoading')) { + return false; + } + if (this.get('isStandardViewType')) { + return this.get('isValidServiceDef'); + } else { + return this.get('isValidCustomServiceDef'); + } + }) +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/fileconfig-viewer-dialog.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/fileconfig-viewer-dialog.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/fileconfig-viewer-dialog.js new file mode 100644 index 0000000..d4912768 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/fileconfig-viewer-dialog.js @@ -0,0 +1,36 @@ +/** + * 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'; + +export default Ember.Component.extend({ + dialogId: "fileconfig_viewer_dialog", + title: "File Configuration Properties", + props: null, + customProps: Ember.computed('props', function() { + var custom = []; + var props = this.get('props'); + for (var pro in props) { + custom.push({ + name: pro, + value: props[pro] + }); + } + return custom; + }) +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/info-tooltip.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/info-tooltip.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/info-tooltip.js new file mode 100644 index 0000000..605b611 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/info-tooltip.js @@ -0,0 +1,44 @@ +/** + * 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 InfoSeeder from 'yarn-ui/utils/info-seeder'; + +export default Ember.Component.extend({ + classNames: ['tooltip', 'info-tooltip'], + elementId: 'info_tooltip_wrapper', + + didInsertElement() { + var $tooltip = Ember.$('#info_tooltip_wrapper'); + Ember.$('body').on('mouseenter', '.info-icon', function() { + var $elem = Ember.$(this); + var info = InfoSeeder[$elem.data('info')]; + var offset = $elem.offset(); + $tooltip.show(); + $tooltip.find("#tooltip_content").text(info); + $tooltip.offset({top: offset.top + 20, left: offset.left - 10}); + }).on('mouseleave', '.info-icon', function() { + $tooltip.find("#tooltip_content").text(''); + $tooltip.hide(); + }); + }, + + WillDestroyElement() { + Ember.$('body').off('hover'); + } +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/service-component-table.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/service-component-table.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/service-component-table.js new file mode 100644 index 0000000..5a9ae30 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/service-component-table.js @@ -0,0 +1,56 @@ +/** + * 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'; + +export default Ember.Component.extend({ + serviceDef: null, + currentComponent: null, + duplicateNameError: false, + + actions: { + showAddComponentModal() { + var newComp = this.get('serviceDef').createNewServiceComponent(); + this.set('currentComponent', newComp); + this.set('duplicateNameError', false); + this.$('#addComponentModal').modal('show'); + }, + + addNewComponent() { + this.set('duplicateNameError', false); + if (this.isCurrentNameDuplicate()) { + this.set('duplicateNameError', true); + return; + } + this.get('serviceDef.serviceComponents').addObject(this.get('currentComponent')); + this.$('#addComponentModal').modal('hide'); + }, + + removeComponent(component) { + this.get('serviceDef.serviceComponents').removeObject(component); + } + }, + + isCurrentNameDuplicate() { + var currName = this.get('currentComponent.name'); + var item = this.get('serviceDef.serviceComponents').findBy('name', currName); + return !Ember.isNone(item); + }, + + isValidCurrentComponent: Ember.computed.and('currentComponent', 'currentComponent.name', 'currentComponent.cpus', 'currentComponent.memory', 'currentComponent.numOfContainers', 'currentComponent.artifactId', 'currentComponent.launchCommand') +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/service-config-table.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/service-config-table.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/service-config-table.js new file mode 100644 index 0000000..b0a78dd --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/service-config-table.js @@ -0,0 +1,89 @@ +/** + * 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'; + +export default Ember.Component.extend({ + serviceDef: null, + currentConfig: null, + serviceConfigJson: '', + + actions: { + showNewConfigurationModal() { + var newConfig = this.get('serviceDef').createNewServiceConfig(); + this.set('currentConfig', newConfig); + this.$('#addConfigurationModal').modal('show'); + if (this.get('isNonEmptyComponents') && this.get('currentConfig.componentName') === '') { + this.set('currentConfig.componentName', this.get('componentNames.firstObject')); + } + }, + + removeConfiguration(config) { + this.get('serviceDef.serviceConfigs').removeObject(config); + }, + + configTypeChanged(type) { + this.set('currentConfig.type', type); + if (type === 'quicklink') { + this.set('currentConfig.scope', 'service'); + this.set('currentConfig.componentName', ''); + } + }, + + addNewConfiguration() { + this.get('serviceDef.serviceConfigs').addObject(this.get('currentConfig')); + this.$('#addConfigurationModal').modal('hide'); + }, + + showServiceConfigUploadModal() { + this.set('serviceConfigJson', ''); + this.$("#service_config_upload_modal").modal('show'); + }, + + uploadServiceConfig(json) { + this.get('serviceDef').convertJsonServiceConfigs(json); + this.$("#service_config_upload_modal").modal('hide'); + }, + + configScopeChanged(scope) { + this.set('currentConfig.scope', scope); + }, + + scopeComponentChanged(name) { + this.set('currentConfig.componentName', name); + } + }, + + isNonEmptyComponents: Ember.computed('serviceDef.serviceComponents.length', function() { + return this.get('serviceDef.serviceComponents.length') > 0; + }), + + isNotQuicklink: Ember.computed('currentConfig.type', function() { + return this.get('currentConfig.type') !== "quicklink"; + }), + + componentNames: Ember.computed('serviceDef.serviceComponents.[]', function() { + var names = []; + this.get('serviceDef.serviceComponents').forEach(function(cmp) { + names.push(cmp.get('name')); + }); + return names; + }), + + isValidCurrentConfig: Ember.computed.and('currentConfig', 'currentConfig.name', 'currentConfig.value') +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/service-fileconfig-table.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/service-fileconfig-table.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/service-fileconfig-table.js new file mode 100644 index 0000000..7c06152 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/service-fileconfig-table.js @@ -0,0 +1,112 @@ +/** + * 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'; + +export default Ember.Component.extend({ + serviceDef: null, + currentFileConfig: null, + fileConfigJson: '', + fileConfigProps: '', + propertyViewer: null, + parseError: '', + + actions: { + showNewConfigFileModal() { + var newFile = this.get('serviceDef').createNewFileConfig(); + this.set('currentFileConfig', newFile); + this.set('fileConfigProps', ''); + this.set('parseError', ''); + this.$('#addFileConfigModal').modal('show'); + if (this.get('isNonEmptyComponents') && this.get('currentFileConfig.componentName') === '') { + this.set('currentFileConfig.componentName', this.get('componentNames.firstObject')); + } + }, + + removeFileConfiguration(file) { + this.get('serviceDef.fileConfigs').removeObject(file); + }, + + addNewFileConfig() { + this.set('parseError', ''); + var props = this.get('fileConfigProps'); + if (props) { + try { + var parsed = JSON.parse(props); + this.set('currentFileConfig.props', parsed); + } catch (err) { + this.set('parseError', `Invalid JSON: ${err.message}`); + throw err; + } + } + this.get('serviceDef.fileConfigs').addObject(this.get('currentFileConfig')); + this.$('#addFileConfigModal').modal('hide'); + }, + + showFileConfigUploadModal() { + this.set('fileConfigJson', ''); + this.$("#service_file_config_upload_modal").modal('show'); + }, + + uploadFileConfig(json) { + this.get('serviceDef').convertJsonFileConfigs(json); + this.$("#service_file_config_upload_modal").modal('hide'); + }, + + configScopeChanged(scope) { + this.set('currentFileConfig.scope', scope); + }, + + scopeComponentChanged(name) { + this.set('currentFileConfig.componentName', name); + }, + + configTypeChanged(type) { + this.set('currentFileConfig.type', type); + if (type === "TEMPLATE") { + this.set('currentFileConfig.props', null); + this.set('fileConfigProps', ''); + } + }, + + showFileConfigPropertyViewer(props) { + this.set('propertyViewer', props); + this.$("#file_config_properties_viewer").modal('show'); + } + }, + + isNonEmptyComponents: Ember.computed('serviceDef.serviceComponents.length', function() { + return this.get('serviceDef.serviceComponents.length') > 0; + }), + + componentNames: Ember.computed('serviceDef.serviceComponents.[]', function() { + var names = []; + this.get('serviceDef.serviceComponents').forEach(function(cmp) { + names.push(cmp.get('name')); + }); + return names; + }), + + isValidCurrentFileConfig: Ember.computed('currentFileConfig', 'currentFileConfig.srcFile', 'currentFileConfig.destFile', 'fileConfigProps', function() { + return this.get('currentFileConfig') && this.get('currentFileConfig.destFile') && (this.get('currentFileConfig.srcFile') || this.get('fileConfigProps')); + }), + + isConfigTypeHadoopXml: Ember.computed('currentFileConfig.type', function() { + return this.get('currentFileConfig.type') === 'HADOOP_XML'; + }) +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/upload-config.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/upload-config.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/upload-config.js new file mode 100644 index 0000000..2f9dc9c --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/upload-config.js @@ -0,0 +1,54 @@ +/** + * 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'; + +export default Ember.Component.extend({ + dialogId: "config_upload_modal", + title: "Upload Configuration", + configJson: '', + parseErrorMsg: '', + + actions: { + uploadConfig() { + var json = this.get('configJson'); + try { + JSON.parse(json); + this.upateParseResults(""); + } catch (ex) { + this.upateParseResults("Invalid JSON: " + ex.message); + throw ex; + } + if (!this.get('parseErrorMsg')) { + this.sendAction("uploadConfig", json); + } + } + }, + + didInsertElement() { + this.$('#' + this.get('dialogId')).on('shown.bs.modal', function() { + this.upateParseResults(""); + }.bind(this)); + }, + + isValidConfigJson: Ember.computed.notEmpty('configJson'), + + upateParseResults(message) { + this.set('parseErrorMsg', message); + } +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-deploy-service.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-deploy-service.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-deploy-service.js new file mode 100644 index 0000000..25d575f --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-deploy-service.js @@ -0,0 +1,69 @@ +/** + * 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'; + +export default Ember.Controller.extend({ + breadcrumbs: [{ + text: "Home", + routeName: 'application' + }, { + text: "Services", + routeName: 'yarn-services', + }, { + text: "New Service", + routeName: 'yarn-deploy-service', + }], + + savedStandardTemplates: [], + savedJsonTemplates: [], + serviceResponse: null, + isLoading: false, + + actions: { + deployServiceDef(serviceDef) { + var defjson = serviceDef.getServiceJSON(); + this.deployServiceApp(defjson); + }, + + deployServiceJson(json) { + this.deployServiceApp(json); + } + }, + + gotoServices() { + Ember.run.later(this, function() { + this.set('serviceResponse', null); + this.transitionToRoute('yarn-services'); + }, 1000); + }, + + deployServiceApp(requestJson) { + var self = this; + var adapter = this.store.adapterFor('yarn-servicedef'); + this.set('isLoading', true); + adapter.deployService(requestJson).then(function() { + self.set('serviceResponse', {message: 'Service has been accepted successfully. Redirecting to services in a second.', type: 'success'}); + self.gotoServices(); + }, function(errmsg) { + self.set('serviceResponse', {message: errmsg, type: 'error'}); + }).finally(function() { + self.set('isLoading', false); + }); + } +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-servicedef.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-servicedef.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-servicedef.js new file mode 100644 index 0000000..0439fb4 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-servicedef.js @@ -0,0 +1,278 @@ +/** + * 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 DS from 'ember-data'; +import Ember from 'ember'; + +export default DS.Model.extend({ + name: DS.attr('string', {defaultValue: ''}), + queue: DS.attr('string', {defaultValue: ''}), + lifetime: DS.attr('string', {defaultValue: ''}), + isCached: DS.attr('boolean', {defaultValue: false}), + + serviceComponents: DS.attr({defaultValue: function() { + return Ember.A(); + }}), + + serviceConfigs: DS.attr({defaultValue: function() { + return Ember.A(); + }}), + + fileConfigs: DS.attr({defaultValue: function() { + return Ember.A(); + }}), + + quicklinks: DS.attr({defaultValue: function() { + return {}; + }}), + + clear() { + this.set('name', ''); + this.set('queue', ''); + this.set('lifetime', ''); + this.get('serviceComponents').clear(); + this.get('serviceConfigs').clear(); + this.get('fileConfigs').clear(); + this.set('quicklinks', {}); + }, + + isValidServiceDef() { + return this.get('name') !== '' && this.get('queue') !== '' && this.get('serviceComponents.length') > 0; + }, + + createNewServiceComponent() { + return Ember.Object.create({ + name: '', + numOfContainers: '', + cpus: '', + memory: '', + artifactId: '', + artifactType: 'DOCKER', + launchCommand: '', + dependencies: [], + uniqueComponentSupport: false, + configuration: null + }); + }, + + createNewServiceConfig(name, value) { + var Config = Ember.Object.extend({ + name: name || '', + value: value || '', + type: 'property', // property OR env OR quicklink + scope: 'service', // service OR component + componentName: '', + capitalizedType: Ember.computed('type', function() { + return Ember.String.capitalize(this.get('type')); + }), + formattedScope: Ember.computed('scope', 'componentName', function() { + if (this.get('scope') !== 'service') { + return this.get('componentName') + ' [Component]'; + } + return Ember.String.capitalize(this.get('scope')); + }) + }); + return Config.create(); + }, + + createNewFileConfig(src, dest) { + var FileConfig = Ember.Object.extend({ + type: 'TEMPLATE', // HADOOP_XML OR TEMPLATE + srcFile: src || '', + destFile: dest || '', + scope: 'service', // service OR component + componentName: '', + props: null, + formattedScope: Ember.computed('scope', 'componentName', function() { + if (this.get('scope') !== 'service') { + return this.get('componentName') + ' [Component]'; + } + return Ember.String.capitalize(this.get('scope')); + }) + }); + return FileConfig.create(); + }, + + getServiceJSON() { + return this.serializeServiceDef(); + }, + + serializeServiceDef() { + var json = { + name: "", + queue: "", + lifetime: "-1", + components: [], + configuration: { + properties: {}, + env: {}, + files: [] + }, + quicklinks: {} + }; + + var components = this.get('serviceComponents'); + var configs = this.get('serviceConfigs'); + var fileConfigs = this.get('fileConfigs'); + + json['name'] = this.get('name'); + json['queue'] = this.get('queue'); + + if (this.get('lifetime')) { + json['lifetime'] = this.get('lifetime'); + } + + components.forEach(function(component) { + json.components.push(this.serializeComponent(component)); + }.bind(this)); + + configs.forEach(function(config) { + let conf = this.serializeConfiguration(config); + if (conf.scope === "service") { + if (conf.type === "property") { + json.configuration.properties[conf.name] = conf.value; + } else if (conf.type === "env") { + json.configuration.env[conf.name] = conf.value; + } else if (conf.type === "quicklink") { + json.quicklinks[conf.name] = conf.value; + } + } else if (conf.scope === "component") { + let requiredCmp = json.components.findBy('name', conf.componentName); + if (requiredCmp) { + requiredCmp.configuration = requiredCmp.configuration || {}; + requiredCmp.configuration.properties = requiredCmp.configuration.properties || {}; + requiredCmp.configuration.env = requiredCmp.configuration.env || {}; + if (conf.type === "property") { + requiredCmp.configuration.properties[conf.name] = conf.value; + } else if (conf.type === "env") { + requiredCmp.configuration.env[conf.name] = conf.value; + } + } + } + }.bind(this)); + + fileConfigs.forEach(function(file) { + let scope = file.get('scope'); + if (scope === "service") { + json.configuration.files.push(this.serializeFileConfig(file)); + } else if (scope === "component") { + let requiredCmp = json.components.findBy('name', file.get('componentName')); + if (requiredCmp) { + requiredCmp.configuration = requiredCmp.configuration || {}; + requiredCmp.configuration.files = requiredCmp.configuration.files || []; + requiredCmp.configuration.files.push(this.serializeFileConfig(file)); + } + } + }.bind(this)); + + return json; + }, + + serializeComponent(record) { + var json = {}; + json['name'] = record.get('name'); + json['number_of_containers'] = record.get('numOfContainers'); + json['launch_command'] = record.get('launchCommand'); + json['dependencies'] = []; + json['artifact'] = { + id: record.get('artifactId'), + type: record.get('artifactType') + }; + json['resource'] = { + cpus: record.get('cpus'), + memory: record.get('memory') + }; + if (record.get('uniqueComponentSupport')) { + json['unique_component_support'] = "true"; + } + if (record.get('configuration')) { + json['configuration'] = record.get('configuration'); + } + return json; + }, + + serializeConfiguration(config) { + var json = {}; + json["type"] = config.get('type'); + json["scope"] = config.get('scope'); + json["componentName"] = config.get('componentName'); + json["name"] = config.get('name'); + json["value"] = config.get('value'); + return json; + }, + + serializeFileConfig(file) { + var json = {}; + json["type"] = file.get('type'); + json["dest_file"] = file.get('destFile'); + json["src_file"] = file.get('srcFile'); + if (file.get('type') === "HADOOP_XML" && file.get('props')) { + json["props"] = file.get('props'); + } + return json; + }, + + createNewServiceDef() { + return this.get('store').createRecord('yarn-servicedef', { + id: 'yarn_servicedef_' + Date.now() + }); + }, + + convertJsonServiceConfigs(json) { + var parsedJson = JSON.parse(json); + if (parsedJson.properties) { + for (let prop in parsedJson.properties) { + if (parsedJson.properties.hasOwnProperty(prop)) { + let newPropObj = this.createNewServiceConfig(prop, parsedJson.properties[prop]); + this.get('serviceConfigs').addObject(newPropObj); + } + } + } + if (parsedJson.env) { + for (let envprop in parsedJson.env) { + if (parsedJson.env.hasOwnProperty(envprop)) { + let newEnvObj = this.createNewServiceConfig(envprop, parsedJson.env[envprop]); + newEnvObj.set('type', 'env'); + this.get('serviceConfigs').addObject(newEnvObj); + } + } + } + }, + + convertJsonFileConfigs(json) { + var parsedJson = JSON.parse(json); + if (parsedJson.files) { + parsedJson.files.forEach(function(file) { + let newFileObj = this.createNewFileConfig(file.src_file, file.dest_file); + this.get('fileConfigs').addObject(newFileObj); + }.bind(this)); + } + }, + + cloneServiceDef() { + var clone = this.createNewServiceDef(); + clone.set('name', this.get('name')); + clone.set('queue', this.get('queue')); + clone.set('lifetime', this.get('lifetime')); + clone.get('serviceComponents', this.get('serviceComponents')); + clone.get('serviceConfigs', this.get('serviceConfigs')); + clone.get('fileConfigs', this.get('fileConfigs')); + clone.set('quicklinks', this.get('quicklinks')); + return clone; + } +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/router.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/router.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/router.js index 9013142..9b3424b 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/router.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/router.js @@ -48,6 +48,7 @@ Router.map(function() { this.route('yarn-container-log', { path: '/yarn-container-log/:node_id/:node_addr/:container_id/:filename' }); + this.route('yarn-deploy-service'); this.route('cluster-overview'); this.route('yarn-app', function() { this.route('info', {path: '/:app_id/info'}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-deploy-service.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-deploy-service.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-deploy-service.js new file mode 100644 index 0000000..05ef600 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-deploy-service.js @@ -0,0 +1,27 @@ +/** + * 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'; + +export default Ember.Route.extend({ + model() { + return this.store.createRecord('yarn-servicedef', { + id: 'yarn_servicedef_' + Date.now() + }); + } +}); http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/services/hosts.js ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/services/hosts.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/services/hosts.js index 807844e..9359530 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/services/hosts.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/services/hosts.js @@ -75,4 +75,8 @@ export default Ember.Service.extend({ rmWebAddress: Ember.computed(function () { return this.normalizeURL(this.get("env.app.hosts.rmWebAddress")); }), + + dashWebAddress: Ember.computed(function () { + return this.normalizeURL(this.get("env.app.hosts.dashWebAddress")); + }) }); http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/app.css ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/app.css b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/app.css index 8b8ea56..d246f2d 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/app.css +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/styles/app.css @@ -397,3 +397,167 @@ div.attempt-info-panel table > tbody > tr > td:last-of-type { width: 14px; display: inline-block; } + +.deploy-service textarea { + border-radius: 5px !important; + resize: none; + word-wrap: break-word; +} + +.deploy-service .loading-state { + opacity: 0.5; +} + +.deploy-service .loading-state img { + width: 80px; + height: 80px; + margin: 40px auto; + left: 50% !important; + position: absolute; + z-index: 9999; +} + +.align-center { + text-align: center !important; +} + +.bold-text { + font-weight: bold !important; +} + +.deploy-service .saved-list { + min-height: 600px; +} + +.deploy-service .glyphicon { + cursor: pointer; +} + +.deploy-service .remove-icon:hover { + color: #d9534f; +} + +.deploy-service .savedlist-column { + padding-top: 10px; +} + +.deploy-service .definition-column { + padding-top: 10px; + border-left: 1px solid #ddd; +} + +.deploy-service .content-area { + padding: 15px 0px; + border-top: 1px solid #ddd; +} + +.deploy-service .custom-json-area { + padding: 10px 0; + margin-top: -26px; +} + +.deploy-service-modal .modal-dialog { + width: 400px; +} + +.deploy-service-modal .form-group { + margin-bottom: 5px; +} + +.deploy-service .action-btns { + text-align: right; + padding-bottom: 15px; + padding-right: 0; +} + +table.table-custom-action > thead > tr > th:last-of-type, table.table-custom-action > tbody > tr > td:last-of-type { + width: 50px !important; +} + +.deploy-service .toggle-btn.active { + color: #fff; + background-color: #337ab7; + border-color: #337ab7; + text-shadow: none; +} + +.deploy-service .service-resp { + word-wrap: break-word; +} + +table.table-custom-bordered { + border: 1px solid #ddd !important; + border-radius: 3px !important; +} + +table.table-custom-bordered > thead > tr > th, table.table-custom-bordered > tbody > tr > td { + border-bottom: 1px solid #ddd !important; + border-right: 1px solid #ddd !important; +} + +table.table-custom-striped > thead > tr, .table-custom-striped > tbody > tr:nth-of-type(even) { + background-color: #f9f9f9 !important; +} + +.deploy-service label.required:after, .deploy-service-modal label.required:after { + content: '*'; + color: #d9534f; +} + +.deploy-service .form-group.shrink-height { + margin-bottom: -8px; +} + +table.fix-table-overflow { + table-layout: fixed; +} + +table.fix-table-overflow > tbody > tr > td:last-of-type { + overflow: hidden; + text-overflow: ellipsis; +} + +div.tooltip.info-tooltip { + font: 14px sans-serif !important; + background: lightsteelblue; + word-wrap: break-word; + position: absolute; + text-align: justify; + border-radius: 3px; + z-index: 9999; + padding: 10px; + display: none; + min-width: 200px; + max-width: 500px; + opacity: 1; + top: 10px; + left: 0; +} + +div.tooltip.info-tooltip > span.top-arrow { + color: lightsteelblue; + position: absolute; + top: -10px; + left: 10px; +} + +span.info-icon { + color: #337ab7 !important; +} + +div.service-action-mask { + position: absolute; + opacity: 0.5; + z-index: 9999; + width: 100%; + height: 100%; +} + +div.service-action-mask img { + position: absolute; + width: 80px; + height: 80px; + margin: 40px auto; + left: 45% !important; + z-index: 9999; +} http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/application.hbs ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/application.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/application.hbs index e988e0c..a08ff72 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/application.hbs +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/application.hbs @@ -92,3 +92,5 @@ </div> </div> </div> + +{{info-tooltip}} http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/breadcrumb-bar.hbs ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/breadcrumb-bar.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/breadcrumb-bar.hbs index 24acbd9..54229cc 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/breadcrumb-bar.hbs +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/breadcrumb-bar.hbs @@ -18,5 +18,7 @@ <div class="col-md-12 container-fluid breadcrumb-bar"> {{em-breadcrumbs items=breadcrumbs}} - <button type="button" class="btn btn-sm btn-primary refresh" {{action "refresh"}}>Refresh</button> + {{#unless hideRefresh}} + <button type="button" class="btn btn-sm btn-primary refresh" {{action "refresh"}}>Refresh</button> + {{/unless}} </div> http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/deploy-service.hbs ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/deploy-service.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/deploy-service.hbs new file mode 100644 index 0000000..a098ec3 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/deploy-service.hbs @@ -0,0 +1,157 @@ +{{! + * 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. +}} + +<div class="container-fluid deploy-service"> + {{#if serviceResp}} + <div class="row"> + <div class="col-md-12"> + <div class="panel panel-default service-resp"> + <div class="panel-body {{if (eq serviceResp.type 'error') 'bg-danger' 'bg-success'}}"> + <span class="glyphicon glyphicon-remove pull-right remove-icon" {{action "clearServiceResponse"}}></span> + <strong class="{{if (eq serviceResp.type 'error') 'text-danger' 'text-success'}}">{{serviceResp.message}}</strong> + </div> + </div> + </div> + </div> + {{/if}} + <div class="panel panel-default {{if isLoading 'loading-state'}}"> + {{#if isLoading}} + <img src="assets/images/spinner.gif" alt="Loading..."> + {{/if}} + <div class="row"> + <div class="col-md-12"> + <div class="col-md-2 savedlist-column"> + <label>Saved Templates</label> + <div class="panel panel-default saved-list"> + <ul class="list-group"> + {{#each getSavedList as |list|}} + <a href="#" class="list-group-item {{if list.active 'active'}}" {{action "updateServiceDef" list}}> + {{list.name}} + <span class="glyphicon glyphicon-remove pull-right remove-icon" {{action "removeFromSavedList" list}}></span> + </a> + {{else}} + <li class="list-group-item align-center">No saved templates</li> + {{/each}} + </ul> + </div> + </div> + + <div class="col-md-10 definition-column"> + <label>Service Definition</label> + <div class="btn-group pull-right" data-toggle="buttons"> + <label class="btn btn-default btn-sm toggle-btn active" {{action "updateViewType" "standard"}}> + <input type="radio" name="custom" checked><b>Standard</b> + </label> + <label class="btn btn-default btn-sm toggle-btn" {{action "updateViewType" "custom"}}> + <input type="radio" name="custom"><b>Custom</b> + </label> + </div> + + <div class="col-md-12 content-area"> + {{#if isStandardViewType}} + + <div class="row"> + <div class="col-md-4"> + <div class="form-group shrink-height"> + <label class="required">Service Name</label> + <span class="glyphicon glyphicon-info-sign info-icon" data-info="serviceName"></span> + {{input type="text" class="form-control" placeholder="Service Name" value=serviceDef.name}} + </div> + <br> + </div> + </div> + + <div class="row"> + <div class="col-md-4"> + <div class="form-group shrink-height"> + <label class="required">Queue Name</label> + <span class="glyphicon glyphicon-info-sign info-icon" data-info="queueName"></span> + {{input type="text" class="form-control" placeholder="Queue Name" value=serviceDef.queue}} + </div> + <br> + </div> + </div> + + <div class="row"> + <div class="col-md-4"> + <div class="form-group"> + <label>Service Lifetime</label> + <span class="glyphicon glyphicon-info-sign info-icon" data-info="lifetime"></span> + {{input type="number" min="0" class="form-control" placeholder="Service Lifetime (Seconds)" value=serviceDef.lifetime}} + </div> + <br> + </div> + </div> + + <div class="row"> + {{service-component-table serviceDef=serviceDef applicationCtrl=applicationCtrl}} + </div> + + <div class="row"> + {{service-config-table serviceDef=serviceDef}} + </div> + + <div class="row"> + {{service-fileconfig-table serviceDef=serviceDef}} + </div> + {{/if}} + + {{#if isCustomViewType}} + <div class="form-group custom-json-area"> + {{textarea class="form-control" rows="29" cols="120" value=customServiceDef placeholder="Service JSON configuration here..."}} + </div> + {{/if}} + </div> + + <div class="col-md-12 action-btns"> + <button class="btn btn-default btn-sm" {{action "clearConfigs"}} disabled={{if isLoading "disabled"}}> + Reset + </button> + <button class="btn btn-primary btn-sm" disabled={{unless enableSaveOrDeployBtn "disabled"}} {{action "showSaveTemplateModal"}}> + Save + </button> + <button class="btn btn-success btn-sm" disabled={{unless enableSaveOrDeployBtn "disabled"}} {{action "deployService"}}> + Deploy + </button> + </div> + </div> + </div> + </div> + </div> +</div> + +<div class="modal fade deploy-service-modal" tabindex="-1" role="dialog" id="saveListModal"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title">Save Template As</h4> + </div> + <div class="modal-body"> + <div class="form-group"> + <label>Template Name</label> + {{input type="text" class="form-control" id="templateNameInput" value=savedTemplateName}} + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="button" class="btn btn-primary" {{action "addToSavedList"}} disabled={{unless isValidTemplateName "disabled"}}>Add</button> + </div> + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/fileconfig-viewer-dialog.hbs ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/fileconfig-viewer-dialog.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/fileconfig-viewer-dialog.hbs new file mode 100644 index 0000000..1420340 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/fileconfig-viewer-dialog.hbs @@ -0,0 +1,53 @@ +{{! + * 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. +}} + +<div class="modal fade" tabindex="-1" role="dialog" id="{{dialogId}}"> + <div class="modal-dialog" role="document" style="width: 700px;"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title bold-text">{{title}}</h4> + </div> + <div class="modal-body" style="padding: 0;"> + <table class="table table-hover table-custom-bordered table-custom-striped fix-table-overflow" style="max-width: 700px;"> + <thead> + <tr> + <th>Name</th> + <th>Value</th> + </tr> + </thead> + <tbody> + {{#each customProps as |prop|}} + <tr> + <td>{{prop.name}}</td> + <td title="{{prop.value}}">{{prop.value}}</td> + </tr> + {{else}} + <tr> + <td colspan="2">No data available</td> + </tr> + {{/each}} + </tbody> + </table> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + </div> + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/info-tooltip.hbs ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/info-tooltip.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/info-tooltip.hbs new file mode 100644 index 0000000..faba135 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/info-tooltip.hbs @@ -0,0 +1,20 @@ +{{! + * 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. +}} + +<span class="glyphicon glyphicon-triangle-top top-arrow"></span> +<div id="tooltip_content"></div> http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/service-component-table.hbs ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/service-component-table.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/service-component-table.hbs new file mode 100644 index 0000000..8f3904d --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/service-component-table.hbs @@ -0,0 +1,113 @@ +{{! + * 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. +}} + +<div class="col-md-12"> + <div class="form-group"> + <label>Service Components</label> + <span class="glyphicon glyphicon-info-sign info-icon" data-info="components"></span> + <button class="btn btn-primary btn-xs pull-right" {{action "showAddComponentModal"}}> + <span class="glyphicon glyphicon-plus"></span> + </button> + <div class="panel panel-default"> + <table class="table table-hover table-custom-bordered table-custom-striped table-custom-action"> + <thead> + <tr> + <th>Component Name</th> + <th>CPU</th> + <th>Memory</th> + <th># Containers</th> + <th>Artifact Id</th> + <th>Launch Command</th> + <th></th> + </tr> + </thead> + <tbody> + {{#each serviceDef.serviceComponents as |component|}} + <tr> + <td>{{component.name}}</td> + <td>{{component.cpus}}</td> + <td>{{component.memory}}</td> + <td>{{component.numOfContainers}}</td> + <td>{{component.artifactId}}</td> + <td>{{component.launchCommand}}</td> + <td class="align-center"> + <span class="glyphicon glyphicon-remove remove-icon" {{action "removeComponent" component}}></span> + </td> + </tr> + {{else}} + <tr class="align-center"> + <td colspan="7">No data available</td> + </tr> + {{/each}} + </tbody> + </table> + </div> + </div> +</div> + +<div class="modal fade deploy-service-modal" tabindex="-1" role="dialog" id="addComponentModal"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title">Add Component</h4> + </div> + <div class="modal-body"> + {{#if duplicateNameError}} + <div class="alert alert-danger alert-dismissible" role="alert"> + <strong>Component name already exists</strong> + </div> + {{/if}} + <div class="form-group"> + <label class="required">Component Name</label> + {{input type="text" class="form-control" value=currentComponent.name}} + </div> + <div class="form-group"> + <label class="required">CPU</label> + {{input type="number" min="0" class="form-control" value=currentComponent.cpus}} + </div> + <div class="form-group"> + <label class="required">Memory</label> + {{input type="number" min="0" class="form-control" value=currentComponent.memory}} + </div> + <div class="form-group"> + <label class="required"># Containers</label> + {{input type="number" min="0" class="form-control" value=currentComponent.numOfContainers}} + </div> + <div class="form-group"> + <label class="required">Artifact Id</label> + {{input type="text" class="form-control" value=currentComponent.artifactId}} + </div> + <div class="form-group"> + <label class="required">Launch Command</label> + {{input type="text" class="form-control" value=currentComponent.launchCommand}} + </div> + <div class="form-group"> + <label class="checkbox-inline"> + {{input type="checkbox" checked=currentComponent.uniqueComponentSupport}} + Unique Component Support + </label> + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="button" class="btn btn-primary" {{action "addNewComponent"}} disabled={{unless isValidCurrentComponent "disabled"}}>Add</button> + </div> + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/service-config-table.hbs ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/service-config-table.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/service-config-table.hbs new file mode 100644 index 0000000..46a66ee --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/service-config-table.hbs @@ -0,0 +1,130 @@ +{{! + * 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. +}} + +<div class="col-md-12"> + <div class="form-group"> + <label>Service Configurations</label> + <span class="glyphicon glyphicon-info-sign info-icon" data-info="configurations"></span> + <button class="btn btn-primary btn-xs pull-right" {{action "showNewConfigurationModal"}}> + <span class="glyphicon glyphicon-plus"></span> + </button> + <button class="btn btn-primary btn-xs pull-right" style="margin-right: 5px;" {{action "showServiceConfigUploadModal"}}> + <span class="glyphicon glyphicon-open"></span> + </button> + <div class="panel panel-default"> + <table class="table table-hover table-custom-bordered table-custom-striped table-custom-action"> + <thead> + <tr> + <th>Name</th> + <th>Value</th> + <th>Type</th> + <th>Scope</th> + <th></th> + </tr> + </thead> + <tbody> + {{#each serviceDef.serviceConfigs as |config|}} + <tr> + <td>{{config.name}}</td> + <td>{{config.value}}</td> + <td>{{config.capitalizedType}}</td> + <td>{{config.formattedScope}}</td> + <td> + <span class="glyphicon glyphicon-remove remove-icon" {{action "removeConfiguration" config}}></span> + </td> + </tr> + {{else}} + <tr class="align-center"> + <td colspan="5">No data available</td> + </tr> + {{/each}} + </tbody> + </table> + </div> + </div> +</div> + +<div class="modal fade deploy-service-modal" tabindex="-1" role="dialog" id="addConfigurationModal"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title bold-text">Add Configuration</h4> + </div> + <div class="modal-body"> + <div class="form-group"> + <label class="required">Name</label> + {{input type="text" class="form-control" value=currentConfig.name}} + </div> + <div class="form-group"> + <label class="required">Value</label> + {{input type="text" class="form-control" value=currentConfig.value}} + </div> + <div class="form-group"> + <label class="required">Type</label> + <div> + <label class="radio-inline"> + <input type="radio" name="type" value="property" checked={{eq currentConfig.type "property"}} onchange={{action "configTypeChanged" "property"}}>Property + </label> + <label class="radio-inline"> + <input type="radio" name="type" value="env" checked={{eq currentConfig.type "env"}} onchange={{action "configTypeChanged" "env"}}>Env + </label> + <label class="radio-inline"> + <input type="radio" name="type" value="quicklink" checked={{eq currentConfig.type "quicklink"}} onchange={{action "configTypeChanged" "quicklink"}}>Quicklink + </label> + </div> + </div> + {{#if isNotQuicklink}} + <div class="form-group"> + <label class="required">Scope</label> + <div> + <label class="radio-inline"> + <input type="radio" name="scope" value="service" checked={{eq currentConfig.scope "service"}} onchange={{action "configScopeChanged" "service"}}>Service + </label> + {{#if isNonEmptyComponents}} + <label class="radio-inline"> + <input type="radio" name="scope" value="component" checked={{eq currentConfig.scope "component"}} onchange={{action "configScopeChanged" "component"}}>Component + </label> + {{/if}} + </div> + </div> + {{#if (eq currentConfig.scope "component")}} + <div class="form-group"> + <select class="form-control" onchange={{action "scopeComponentChanged" value="target.value"}}> + {{#each componentNames as |name|}} + <option value="{{name}}" selected={{eq currentConfig.componentName name}}>{{name}}</option> + {{/each}} + </select> + </div> + {{/if}} + {{/if}} + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="button" class="btn btn-primary" {{action "addNewConfiguration"}} disabled={{unless isValidCurrentConfig "disabled"}}>Add</button> + </div> + </div> + </div> +</div> + +{{upload-config + dialogId="service_config_upload_modal" + title="Upload Service Configurations" + configJson=serviceConfigJson + uploadConfig="uploadServiceConfig" +}} http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/service-fileconfig-table.hbs ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/service-fileconfig-table.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/service-fileconfig-table.hbs new file mode 100644 index 0000000..97442c6 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/service-fileconfig-table.hbs @@ -0,0 +1,152 @@ +{{! + * 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. +}} + +<div class="col-md-12"> + <div class="form-group"> + <label>File Configurations</label> + <span class="glyphicon glyphicon-info-sign info-icon" data-info="fileConfigs"></span> + <button class="btn btn-primary btn-xs pull-right" {{action "showNewConfigFileModal"}}> + <span class="glyphicon glyphicon-plus"></span> + </button> + <button class="btn btn-primary btn-xs pull-right" style="margin-right: 5px;" {{action "showFileConfigUploadModal"}}> + <span class="glyphicon glyphicon-open"></span> + </button> + <div class="panel panel-default"> + <table class="table table-hover table-custom-bordered table-custom-striped table-custom-action"> + <thead> + <tr> + <th>Source File</th> + <th>Properties</th> + <th>Destination File</th> + <th>Type</th> + <th>Scope</th> + <th></th> + </tr> + </thead> + <tbody> + {{#each serviceDef.fileConfigs as |file|}} + <tr> + <td> + {{#if file.srcFile}} + {{file.srcFile}} + {{else}} + <span>N/A</span> + {{/if}} + </td> + <td> + {{#if file.props}} + <a href="#" {{action "showFileConfigPropertyViewer" file.props}}>View Properties</a> + {{else}} + <span>N/A</span> + {{/if}} + </td> + <td>{{file.destFile}}</td> + <td>{{file.type}}</td> + <td>{{file.formattedScope}}</td> + <td class="align-center"> + <span class="glyphicon glyphicon-remove remove-icon" {{action "removeFileConfiguration" file}}></span> + </td> + </tr> + {{else}} + <tr class="align-center"> + <td colspan="6">No data available</td> + </tr> + {{/each}} + </tbody> + </table> + </div> + </div> +</div> + +<div class="modal fade deploy-service-modal" tabindex="-1" role="dialog" id="addFileConfigModal"> + <div class="modal-dialog" role="document" style="width: 500px;"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title bold-text">Add File Configuration</h4> + </div> + <div class="modal-body"> + {{#if parseError}} + <div class="alert alert-danger alert-dismissible" role="alert"> + <strong>{{parseError}}</strong> + </div> + {{/if}} + <div class="form-group"> + <label class="required">Type</label> + <div> + <label class="radio-inline"> + <input type="radio" name="type" value="TEMPLATE" checked={{eq currentFileConfig.type "TEMPLATE"}} onchange={{action "configTypeChanged" "TEMPLATE"}}>TEMPLATE + </label> + <label class="radio-inline"> + <input type="radio" name="type" value="HADOOP_XML" checked={{eq currentFileConfig.type "HADOOP_XML"}} onchange={{action "configTypeChanged" "HADOOP_XML"}}>HADOOP_XML + </label> + </div> + </div> + <div class="form-group"> + <label class={{unless isConfigTypeHadoopXml "required"}}>Source File</label> + {{input type="text" class="form-control" value=currentFileConfig.srcFile}} + </div> + {{#if isConfigTypeHadoopXml}} + <div class="form-group"> + <label>Properties</label> <span>(Source File and/or Properties are required)</span> + {{textarea class="form-control" rows="15" value=fileConfigProps placeholder="Configuration file properties here..."}} + </div> + {{/if}} + <div class="form-group"> + <label class="required">Destination File</label> + {{input type="text" class="form-control" value=currentFileConfig.destFile}} + </div> + <div class="form-group"> + <label class="required">Scope</label> + <div> + <label class="radio-inline"> + <input type="radio" name="scope" value="service" checked={{eq currentFileConfig.scope "service"}} onchange={{action "configScopeChanged" "service"}}>Service + </label> + {{#if isNonEmptyComponents}} + <label class="radio-inline"> + <input type="radio" name="scope" value="component" checked={{eq currentFileConfig.scope "component"}} onchange={{action "configScopeChanged" "component"}}>Component + </label> + {{/if}} + </div> + </div> + {{#if (eq currentFileConfig.scope "component")}} + <div class="form-group"> + <select class="form-control" onchange={{action "scopeComponentChanged" value="target.value"}}> + {{#each componentNames as |name|}} + <option value="{{name}}" selected={{eq currentFileConfig.componentName name}}>{{name}}</option> + {{/each}} + </select> + </div> + {{/if}} + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="button" class="btn btn-primary" {{action "addNewFileConfig"}} disabled={{unless isValidCurrentFileConfig "disabled"}}>Add</button> + </div> + </div> + </div> +</div> + +{{upload-config + dialogId="service_file_config_upload_modal" + title="Upload File Configurations" + configJson=fileConfigJson + uploadConfig="uploadFileConfig" +}} + +{{fileconfig-viewer-dialog dialogId="file_config_properties_viewer" props=propertyViewer}} http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/upload-config.hbs ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/upload-config.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/upload-config.hbs new file mode 100644 index 0000000..045fb0f --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/upload-config.hbs @@ -0,0 +1,44 @@ +{{! + * 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. +}} + +<div class="modal fade" tabindex="-1" role="dialog" id="{{dialogId}}"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title bold-text">{{title}}</h4> + </div> + <div class="modal-body"> + <div class="form-group"> + {{textarea class="form-control" rows="20" cols="100" value=configJson placeholder="JSON Configuration Here..."}} + </div> + {{#if isParseError}} + <div class="panel panel-default"> + <div class="panel-body bg-danger"> + <strong>{{parseErrorMsg}}</strong> + </div> + </div> + {{/if}} + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="button" class="btn btn-primary" {{action "uploadConfig"}} disabled={{unless isValidConfigJson "disabled"}}>Upload</button> + </div> + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/hadoop/blob/c90220ee/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-deploy-service.hbs ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-deploy-service.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-deploy-service.hbs new file mode 100644 index 0000000..98bc917 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-deploy-service.hbs @@ -0,0 +1,33 @@ +{{! + * 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. +}} + +{{breadcrumb-bar breadcrumbs=breadcrumbs hideRefresh=true}} + +<div class="col-md-12 container-fluid"> + <div class="row"> + {{deploy-service + savedStandardTemplates=savedStandardTemplates + savedJsonTemplates=savedJsonTemplates + serviceDef=model + serviceResp=serviceResponse + isLoading=isLoading + deployServiceDef="deployServiceDef" + deployServiceJson="deployServiceJson" + }} + </div> +</div> --------------------------------------------------------------------- To unsubscribe, e-mail: common-commits-unsubscr...@hadoop.apache.org For additional commands, e-mail: common-commits-h...@hadoop.apache.org