You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by su...@apache.org on 2017/05/03 07:01:42 UTC
[2/2] hadoop git commit: YARN-6419. Support to launch new
native-service from new YARN UI. Contributed by Akhil PB.
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/e2384023
Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/e2384023
Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/e2384023
Branch: refs/heads/yarn-native-services
Commit: e2384023b1ee4006f740f9b71f26a870fb2ceedd
Parents: d23a97d
Author: Sunil G <su...@apache.org>
Authored: Wed May 3 12:30:55 2017 +0530
Committer: Sunil G <su...@apache.org>
Committed: Wed May 3 12:30:55 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-apps/services.js | 22 --
.../app/controllers/yarn-deploy-service.js | 69 +++++
.../main/webapp/app/models/yarn-servicedef.js | 278 +++++++++++++++++++
.../src/main/webapp/app/router.js | 2 +-
.../webapp/app/routes/yarn-apps/services.js | 33 ---
.../webapp/app/routes/yarn-deploy-service.js | 27 ++
.../src/main/webapp/app/services/hosts.js | 4 +
.../src/main/webapp/app/styles/app.css | 147 ++++++++++
.../main/webapp/app/templates/application.hbs | 4 +-
.../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 +++
.../src/main/webapp/app/templates/yarn-apps.hbs | 2 +-
.../webapp/app/templates/yarn-apps/services.hbs | 25 --
.../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 | 2 +
.../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 ++
.../unit/controllers/yarn-apps/services-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 ++
46 files changed, 2334 insertions(+), 114 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hadoop/blob/e2384023/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/e2384023/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/e2384023/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/e2384023/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/e2384023/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/e2384023/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/e2384023/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/e2384023/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/e2384023/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/e2384023/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/e2384023/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-apps/services.js
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-apps/services.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-apps/services.js
deleted file mode 100644
index 0b0be20..0000000
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/controllers/yarn-apps/services.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * 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 AppTableController from '../app-table-columns';
-
-export default AppTableController.extend({
-});
http://git-wip-us.apache.org/repos/asf/hadoop/blob/e2384023/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/e2384023/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/e2384023/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 a45861e..5710627 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
@@ -26,7 +26,6 @@ var Router = Ember.Router.extend({
Router.map(function() {
this.route('yarn-apps', function () {
this.route('apps');
- this.route('services');
});
this.route('yarn-services');
this.route('yarn-nodes', function(){
@@ -49,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', { path: '/yarn-app/:app_id' });
this.route('yarn-app-attempt', { path: '/yarn-app-attempt/:app_attempt_id'});
http://git-wip-us.apache.org/repos/asf/hadoop/blob/e2384023/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps/services.js
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps/services.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps/services.js
deleted file mode 100644
index 34ad1ad..0000000
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-apps/services.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * 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 Ember.RSVP.hash({
- apps: this.store.query('yarn-app', {
- applicationTypes: "org-apache-slider"
- }),
- });
- },
-
- unloadAll() {
- this.store.unloadAll('yarn-app');
- }
-});
http://git-wip-us.apache.org/repos/asf/hadoop/blob/e2384023/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/e2384023/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/e2384023/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 e3dfcd9..2a23993 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
@@ -314,3 +314,150 @@ div.attempt-info-panel table > tbody > tr > td:last-of-type {
overflow: hidden;
text-overflow: ellipsis;
}
+
+.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;
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/e2384023/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 a6d247b..e38fc39 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
@@ -46,7 +46,7 @@
<span class="sr-only">(current)</span>
{{/link-to}}
{{/link-to}}
- {{#link-to 'yarn-apps.apps' tagName="li" current-when="yarn-apps.apps yarn-apps.services"}}
+ {{#link-to 'yarn-apps.apps' tagName="li" current-when="yarn-apps.apps"}}
{{#link-to 'yarn-apps.apps' class="navigation-link"}}Applications
<span class="sr-only">(current)</span>
{{/link-to}}
@@ -88,3 +88,5 @@
</div>
</div>
</div>
+
+{{info-tooltip}}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/e2384023/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/e2384023/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/e2384023/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/e2384023/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/e2384023/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/e2384023/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/e2384023/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}}
---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org