AMBARI-7258 Slider View: FE - Make ganglia monitoring optional when creating app. (atkach)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/43a4283b Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/43a4283b Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/43a4283b Branch: refs/heads/branch-alerts-dev Commit: 43a4283bbd1c4cec6ae26b104ab99be43d93a1ff Parents: daefe5d Author: atkach <atk...@hortonworks.com> Authored: Thu Sep 11 17:34:18 2014 +0300 Committer: atkach <atk...@hortonworks.com> Committed: Thu Sep 11 17:34:18 2014 +0300 ---------------------------------------------------------------------- .../assets/data/resource/service_configs.json | 38 ++++++ .../ui/app/components/configSection.js | 4 + .../createAppWizard/step1_controller.js | 41 ++++++- .../createAppWizard/step3_controller.js | 123 +++++++++++++++++-- .../src/main/resources/ui/app/helpers/ajax.js | 9 ++ .../resources/ui/app/models/config_property.js | 44 +++++++ .../ui/app/templates/common/config.hbs | 37 ++++++ .../app/templates/components/configSection.hbs | 29 +++-- .../src/main/resources/ui/app/translations.js | 1 + .../ui/app/views/common/config_set_view.js | 56 +++++++++ 10 files changed, 358 insertions(+), 24 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/43a4283b/contrib/views/slider/src/main/resources/ui/app/assets/data/resource/service_configs.json ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/assets/data/resource/service_configs.json b/contrib/views/slider/src/main/resources/ui/app/assets/data/resource/service_configs.json new file mode 100644 index 0000000..f255bec --- /dev/null +++ b/contrib/views/slider/src/main/resources/ui/app/assets/data/resource/service_configs.json @@ -0,0 +1,38 @@ +{ + "items" : [ + { + "cluster_name" : "cl", + "configurations" : [ + { + "Config" : { + "cluster_name" : "cl" + }, + "type" : "ganglia-env", + "tag" : "version1410432304443", + "version" : 1, + "properties" : { + "rrdcached_timeout" : "3600", + "gmetad_user" : "nobody", + "rrdcached_base_dir" : "/var/lib/ganglia/rrds", + "rrdcached_write_threads" : "4", + "rrdcached_delay" : "1800", + "rrdcached_flush_timeout" : "7200", + "gmond_user" : "nobody", + "ganglia_runtime_dir" : "/var/run/ganglia/hdp", + "ganglia_custom_clusters": "'HBaseCluster1','7000','AccumuloCluster1','7001','HBaseCluster2','7002'" + }, + "properties_attributes" : { } + } + ], + "createtime" : 1410432307174, + "group_id" : -1, + "group_name" : "default", + "hosts" : [ ], + "is_current" : true, + "service_config_version" : 1, + "service_config_version_note" : "Initial configurations for Ganglia", + "service_name" : "GANGLIA", + "user" : "admin" + } + ] +} http://git-wip-us.apache.org/repos/asf/ambari/blob/43a4283b/contrib/views/slider/src/main/resources/ui/app/components/configSection.js ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/components/configSection.js b/contrib/views/slider/src/main/resources/ui/app/components/configSection.js index 43a2427..bcdff12 100644 --- a/contrib/views/slider/src/main/resources/ui/app/components/configSection.js +++ b/contrib/views/slider/src/main/resources/ui/app/components/configSection.js @@ -46,8 +46,12 @@ App.ConfigSectionComponent = Em.Component.extend({ /** * Filtered configs for current section + * @type {Array} */ sectionConfigs: Ember.computed.filter('config', function (item) { + if (item.isSet) { + return item.section === this.get('section'); + } if (this.get('isGeneral')) { return !item.name.match('^site.') && this.get('predefinedConfigNames').contains(item.name); } http://git-wip-us.apache.org/repos/asf/ambari/blob/43a4283b/contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/step1_controller.js ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/step1_controller.js b/contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/step1_controller.js index b267170..9faaa32 100644 --- a/contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/step1_controller.js +++ b/contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/step1_controller.js @@ -82,6 +82,7 @@ App.CreateAppWizardStep1Controller = Ember.Controller.extend({ */ loadStep: function () { this.loadGangliaHost(); + this.loadGangliaClusters(); this.initializeNewApp(); this.loadAvailableTypes(); }, @@ -100,7 +101,6 @@ App.CreateAppWizardStep1Controller = Ember.Controller.extend({ }, success: 'loadGangliaHostSuccessCallback' }); - }, /** @@ -116,6 +116,45 @@ App.CreateAppWizardStep1Controller = Ember.Controller.extend({ }, /** + * Load ganglia clusters + * @method loadGangliaClusters + */ + loadGangliaClusters: function () { + return App.ajax.send({ + name: 'service_current_configs', + sender: this, + data: { + serviceName: "GANGLIA", + urlPrefix: '/api/v1/' + }, + success: 'loadGangliaClustersSuccessCallback' + }); + }, + + /** + * Success callback for config property + * Save cluster to gangliaClusters + * @param {Object} data + * @method loadGangliaClustersSuccessCallback + */ + loadGangliaClustersSuccessCallback: function (data) { + var gangliaCustomClusters = []; + if (data.items[0]) { + //parse CSV string with cluster names and ports + Em.get(data.items[0].configurations[0].properties, 'ganglia_custom_clusters').replace(/\'/g, "").split(',').forEach(function(item, index){ + if (index % 2 === 0) { + gangliaCustomClusters.push({ + name: item + }) + } else { + gangliaCustomClusters[gangliaCustomClusters.length - 1].port = parseInt(item); + } + }); + App.set('gangliaClusters', gangliaCustomClusters); + } + }, + + /** * Initialize new App and set it to <code>newApp</code> * @method initializeNewApp */ http://git-wip-us.apache.org/repos/asf/ambari/blob/43a4283b/contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/step3_controller.js ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/step3_controller.js b/contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/step3_controller.js index 1018314..0377388 100644 --- a/contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/step3_controller.js +++ b/contrib/views/slider/src/main/resources/ui/app/controllers/createAppWizard/step3_controller.js @@ -31,6 +31,18 @@ App.CreateAppWizardStep3Controller = Ember.ObjectController.extend({ configs: Em.A(), /** + * predefined settings of configuration properties + */ + configSettings: { + 'site.global.ganglia_server_id': { + viewType: 'select' + }, + 'site.global.ganglia_server_port': { + readOnly: true + } + }, + + /** * Convert configs to array of unique section names * @type {Array} */ @@ -60,6 +72,31 @@ App.CreateAppWizardStep3Controller = Ember.ObjectController.extend({ configsObject: {}, /** + * config that describe configurations set + */ + configsSet: [ + { + trigger: {value: false, label: Em.I18n.t('configs.enable.metrics'), viewType: 'checkbox'}, + isSet: true, + section: 'global', + configNames: ["site.global.ganglia_server_host", "site.global.ganglia_server_id", "site.global.ganglia_server_port"], + configs: [], + dependencies: [ + { + name: 'App.gangliaClusters', + map: [], + mapFunction: function (origin, dependent) { + if (!origin || !dependent) return false; + dependent.set('value', this.map.findBy('name', origin.get('value')).port); + }, + origin: "site.global.ganglia_server_id", + dependent: "site.global.ganglia_server_port" + } + ] + } + ], + + /** * Load all data required for step * @method loadStep */ @@ -73,23 +110,71 @@ App.CreateAppWizardStep3Controller = Ember.ObjectController.extend({ * @param {bool} setDefaults * @method initConfigs */ - initConfigs: function(setDefaults) { - setDefaults = setDefaults === true ? setDefaults : false; - var configs = this.get('newAppConfigs') || {}, - c = Em.A(); + initConfigs: function (setDefaults) { + var newAppConfigs = this.get('newAppConfigs') || {}, + configs = Em.A(), + configsSet = $.extend(true, [], this.get('configsSet')), + allSetConfigs = {}, + configSettings = this.get('configSettings'), + gangliaClusters = App.get('gangliaClusters'); + + configsSet.forEach(function (item) { + item.configNames.forEach(function (configName) { + allSetConfigs[configName] = item; + }); + }); - Object.keys(configs).forEach(function (key) { - var label = (!!key.match('^site.'))?key.substr(5):key; - if(key === "site.global.ganglia_server_host" && setDefaults) { - configs[key] = App.get('gangliaHost') ? App.get('gangliaHost') : configs[key]; + Object.keys(newAppConfigs).forEach(function (key) { + var label = (!!key.match('^site.')) ? key.substr(5) : key; + var configSetting = (configSettings[key]) ? + $.extend({name: key, value: configs[key], label: label}, configSettings[key]) : + {name: key, value: configs[key], label: label}; + + if (key === "site.global.ganglia_server_host" && !!setDefaults && App.get('gangliaHost')) { + configSetting.value = App.get('gangliaHost'); + } + + if (key === "site.global.ganglia_server_id" && gangliaClusters) { + configSetting.options = gangliaClusters.mapProperty('name'); + configSetting.value = gangliaClusters.mapProperty('name')[0]; + } + if (key === "site.global.ganglia_server_port" && gangliaClusters) { + configSetting.value = gangliaClusters.mapProperty('port')[0]; + } + + if (allSetConfigs[key]) { + allSetConfigs[key].configs.push(App.ConfigProperty.create(configSetting)); + } else { + configs.push(App.ConfigProperty.create(configSetting)); } - c.push({name:key,value:configs[key],label:label}) }); - this.set('configs', c); + configsSet.forEach(function (configSet) { + if (configSet.configs.length === configSet.configNames.length) { + delete configSet.configNames; + configSet.trigger = App.ConfigProperty.create(configSet.trigger); + this.initConfigSetDependecies(configSet); + configs.unshift(configSet); + } + }, this); + + this.set('configs', configs); }.observes('newAppConfigs'), /** + * initialize dependecies map for config set by name + * configSet map changed by reference + * + * @param {object} configSet + * @method initConfigSetDependecies + */ + initConfigSetDependecies: function (configSet) { + configSet.dependencies.forEach(function (item) { + item.map = Em.get(item.name); + }) + }, + + /** * Clear all initial data * @method clearStep */ @@ -105,7 +190,7 @@ App.CreateAppWizardStep3Controller = Ember.ObjectController.extend({ validateConfigs: function () { var self = this; var result = true; - var configs = this.get('configs'); + var configs = this.addConfigSetProperties(this.get('configs')); var configsObject = {}; try { @@ -121,6 +206,22 @@ App.CreateAppWizardStep3Controller = Ember.ObjectController.extend({ }, /** + * add config properties from config sets to general configs array + * @param configs + * @return {Array} + */ + addConfigSetProperties: function (configs) { + var configSets = configs.filterBy('isSet'); + var newConfigs = []; + configs.filterBy('isSet').forEach(function (item) { + if (item.trigger.value) { + newConfigs.pushObjects(item.configs); + } + }); + return configs.filterBy('isSet', false).concat(newConfigs); + }, + + /** * Save converted configs to new App configs * @method saveConfigs */ http://git-wip-us.apache.org/repos/asf/ambari/blob/43a4283b/contrib/views/slider/src/main/resources/ui/app/helpers/ajax.js ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/helpers/ajax.js b/contrib/views/slider/src/main/resources/ui/app/helpers/ajax.js index f19f4eb..6d7e4a1 100644 --- a/contrib/views/slider/src/main/resources/ui/app/helpers/ajax.js +++ b/contrib/views/slider/src/main/resources/ui/app/helpers/ajax.js @@ -135,6 +135,15 @@ var urls = { } }, + 'service_current_configs': { + real: 'clusters/{clusterName}/configurations/service_config_versions?service_name={serviceName}&is_current=true', + mock: '/data/resource/service_configs.json', + headers: { + Accept : "text/plain; charset=utf-8", + "Content-Type": "text/plain; charset=utf-8" + } + }, + 'config.tags': { 'real': 'clusters/{clusterName}?fields=Clusters/desired_configs', headers: { http://git-wip-us.apache.org/repos/asf/ambari/blob/43a4283b/contrib/views/slider/src/main/resources/ui/app/models/config_property.js ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/models/config_property.js b/contrib/views/slider/src/main/resources/ui/app/models/config_property.js new file mode 100644 index 0000000..aa7bbc8 --- /dev/null +++ b/contrib/views/slider/src/main/resources/ui/app/models/config_property.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. + */ + + +/** + * Config property + * @type {object} + */ +App.ConfigProperty = Em.Object.extend({ + name: null, + value: null, + label: "", + viewType: null, + view: function () { + switch (this.get('viewType')) { + case 'checkbox': + return Em.Checkbox; + case 'select': + return Em.Select; + default: + return Em.TextField; + } + }.property('viewType'), + readOnly: false, + //used for config with "select" view + options: [], + //indicate whether it single config or set of configs + isSet: false +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/43a4283b/contrib/views/slider/src/main/resources/ui/app/templates/common/config.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/templates/common/config.hbs b/contrib/views/slider/src/main/resources/ui/app/templates/common/config.hbs new file mode 100644 index 0000000..348cae0 --- /dev/null +++ b/contrib/views/slider/src/main/resources/ui/app/templates/common/config.hbs @@ -0,0 +1,37 @@ +{{! +* 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="form-group"> + + <label class="col-sm-4 control-label">{{formatWordBreak config.label devider='.'}}</label> + + <div class="col-sm-6"> + {{view config.view + value=config.value + content=config.options + class="form-control" + disabled=config.readOnly + }} + </div> + + {{#if isCustom}} + <div class="col-sm-2"> + {{#bs-button clicked="deleteConfig" clickedParamBinding="config" type="danger"}}{{t common.delete}}{{/bs-button}} + </div> + {{/if}} +</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/43a4283b/contrib/views/slider/src/main/resources/ui/app/templates/components/configSection.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/templates/components/configSection.hbs b/contrib/views/slider/src/main/resources/ui/app/templates/components/configSection.hbs index b0d1db7..dca8f9d 100644 --- a/contrib/views/slider/src/main/resources/ui/app/templates/components/configSection.hbs +++ b/contrib/views/slider/src/main/resources/ui/app/templates/components/configSection.hbs @@ -19,19 +19,24 @@ {{#bs-panel heading=sectionLabel collapsible=true dismiss=false open=isGeneral }} <form class="form-horizontal" role="form"> {{#each config in sectionConfigs}} - <div class="form-group"> - <label class="col-sm-4 control-label">{{formatWordBreak config.label devider='.'}}</label> - <div class="col-sm-6"> - {{input value=config.value class="form-control"}} - </div> - {{#if isCustom}} - <div class="col-sm-2"> - {{#bs-button clicked="deleteConfig" clickedParamBinding="config"}} - <i {{bs-bind-tooltip content=tooltipRemove}} class="icon-minus-sign"></i>{{/bs-button}} - </div> - {{/if}} + {{#if config.isSet}} + {{#view "configSet" configSet=config}} + <div class="form-group"> + <label class="col-sm-4 control-label">{{formatWordBreak view.configSet.trigger.label devider='.'}}</label> - </div> + <div class="col-sm-6"> + {{view view.configSet.trigger.view + checked=view.configSet.trigger.value + }} + </div> + </div> + {{#each config in view.configs}} + {{partial "common/config"}} + {{/each}} + {{/view}} + {{else}} + {{partial "common/config"}} + {{/if}} {{/each}} </form> {{#if isCustom}} http://git-wip-us.apache.org/repos/asf/ambari/blob/43a4283b/contrib/views/slider/src/main/resources/ui/app/translations.js ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/translations.js b/contrib/views/slider/src/main/resources/ui/app/translations.js index 8957c29..056b21f 100644 --- a/contrib/views/slider/src/main/resources/ui/app/translations.js +++ b/contrib/views/slider/src/main/resources/ui/app/translations.js @@ -74,6 +74,7 @@ Em.I18n.translations = { 'configs.add_property': 'Add Property', 'configs.add_property.invalid_name': 'Config name should consists only of letters, numbers, \'-\', \'_\', \'.\' and first character should be a letter.', 'configs.add_property.name_exists': 'Config name already exists', + 'configs.enable.metrics': 'Enable Metrics', 'slider.apps.title': 'Slider Apps', 'slider.apps.create': 'Create App', http://git-wip-us.apache.org/repos/asf/ambari/blob/43a4283b/contrib/views/slider/src/main/resources/ui/app/views/common/config_set_view.js ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/views/common/config_set_view.js b/contrib/views/slider/src/main/resources/ui/app/views/common/config_set_view.js new file mode 100644 index 0000000..b421129 --- /dev/null +++ b/contrib/views/slider/src/main/resources/ui/app/views/common/config_set_view.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. + */ + +/** + * view that display set of configs united into group + * which can be excluded from/included into general config array via trigger(special config property) + * @type {Em.View} + */ +App.ConfigSetView = Ember.View.extend({ + + /** + * config set data + */ + configSet: null, + + /** + * configs which can be included/excluded + * @type {Array} + */ + configs: function () { + if (this.get('configSet.trigger.value')) { + return this.get('configSet.configs'); + } + return []; + }.property('configSet.trigger.value'), + + /** + * observe change of config values to resolve their dependecies + */ + changeConfigValues: function () { + var configs = this.get('configs'); + var dependecies = this.get('configSet.dependencies'); + + if (configs.length > 0) { + dependecies.forEach(function (item) { + var origin = configs.findBy('name', item.origin); + var dependent = configs.findBy('name', item.dependent); + item.mapFunction(origin, dependent); + }) + } + }.observes('configs.@each.value') +});