You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by nc...@apache.org on 2016/02/11 14:47:08 UTC

[08/17] ambari git commit: AMBARI-14983. Auto-start services: Show list of Services/Component with status indicator (Zhe (Joe) Wang via srimanth)

AMBARI-14983. Auto-start services: Show list of Services/Component with status indicator (Zhe (Joe) Wang via srimanth)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/364ee026
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/364ee026
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/364ee026

Branch: refs/heads/branch-dev-patch-upgrade
Commit: 364ee0269f1fecfd58e7bdfca846270850db040f
Parents: 0d52ebc
Author: Srimanth Gunturi <sg...@hortonworks.com>
Authored: Wed Feb 10 12:38:42 2016 -0800
Committer: Srimanth Gunturi <sg...@hortonworks.com>
Committed: Wed Feb 10 12:38:48 2016 -0800

----------------------------------------------------------------------
 .../main/admin/service_auto_start.js            | 161 ++++++++++++++++++-
 ambari-web/app/routes/main.js                   |   8 +
 ambari-web/app/styles/application.less          |   5 +
 .../templates/main/admin/service_auto_start.hbs |  46 +++++-
 .../service_auto_start/component_auto_start.hbs |  19 +++
 ambari-web/app/utils/ajax/ajax.js               |  21 +++
 ambari-web/app/views.js                         |   1 +
 .../app/views/main/admin/service_auto_start.js  |  14 +-
 .../service_auto_start/component_auto_start.js  |  57 +++++++
 9 files changed, 319 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/364ee026/ambari-web/app/controllers/main/admin/service_auto_start.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/service_auto_start.js b/ambari-web/app/controllers/main/admin/service_auto_start.js
index fd288ed..4071292 100644
--- a/ambari-web/app/controllers/main/admin/service_auto_start.js
+++ b/ambari-web/app/controllers/main/admin/service_auto_start.js
@@ -21,6 +21,11 @@ var App = require('app');
 App.MainAdminServiceAutoStartController = Em.Controller.extend({
   name: 'mainAdminServiceAutoStartController',
 
+  clusterConfigs: null,
+  componentsConfigs: [],
+  isSaveDisabled: true,
+  valueChanged: false,
+
   loadClusterConfig: function () {
     return App.ajax.send({
       name: 'config.tags.site',
@@ -31,6 +36,161 @@ App.MainAdminServiceAutoStartController = Em.Controller.extend({
     });
   },
 
+  loadComponentsConfigs: function () {
+    return App.ajax.send({
+      name: 'components.get_category',
+      sender: this,
+      success: 'loadComponentsConfigsSuccess'
+    });
+  },
+
+  loadComponentsConfigsSuccess: function (data) {
+    this.set('componentsConfigs', data.items);
+  },
+
+  tabs: function() {
+    var services = {};
+    var tabs = [];
+    this.get('componentsConfigs').forEach(function(component) {
+      var serviceComponentInfo = component.ServiceComponentInfo;
+      if (serviceComponentInfo.category === "MASTER" || serviceComponentInfo.category === "SLAVE") {
+        var componentRecovery = Ember.Object.create({
+          display_name: App.format.role(serviceComponentInfo.component_name),
+          component_name: serviceComponentInfo.component_name,
+          //recovery_enabled: serviceComponentInfo.recovery_enabled === 'true',
+          recovery_enabled: false,
+          valueChanged: false,
+          service_name: serviceComponentInfo.service_name
+        });
+        if (services[serviceComponentInfo.service_name]) {
+          services[serviceComponentInfo.service_name].get('componentRecovery').push(componentRecovery);
+          services[serviceComponentInfo.service_name].set('enabledComponents', services[serviceComponentInfo.service_name].get('enabledComponents') + (componentRecovery.get('recovery_enabled') ? 1 : 0));
+          services[serviceComponentInfo.service_name].set('totalComponents', services[serviceComponentInfo.service_name].get('totalComponents') + 1);
+        } else {
+          services[serviceComponentInfo.service_name] = Ember.Object.create({
+            service_name: serviceComponentInfo.service_name,
+            display_name: App.format.role(serviceComponentInfo.service_name),
+            headingClass: "." + serviceComponentInfo.service_name,
+            isActive: false,
+            componentRecovery: [componentRecovery],
+            enabledComponents: componentRecovery.recovery_enabled ? 1 : 0,
+            totalComponents: 1,
+            indicator: function() {
+              var percentage = this.get('enabledComponents') / this.get('totalComponents');
+              var indicator = "icon-adjust";
+              if (percentage === 1) {
+                indicator = "icon-circle";
+              } else if (percentage === 0) {
+                indicator = "icon-circle-blank";
+              }
+              return indicator;
+            }.property('enabledComponents', 'totalComponents')
+          });
+        }
+      }
+    });
+    for (var service in services ) {
+      tabs.push(services[service]);
+    }
+    if (tabs.length) {
+      tabs[0].set('isActive', true);
+    }
+    return tabs;
+  }.property('componentsConfigs'),
+
+  checkValuesChange: function () {
+    var valuesChanged = this.get('valueChanged');
+    this.get('tabs').forEach(function (service) {
+      service.get('componentRecovery').forEach(function (component) {
+        valuesChanged = valuesChanged || component.get('valueChanged');
+      });
+    });
+    this.set('isSaveDisabled', !valuesChanged);
+  }.observes('valueChanged'),
+
+  doReload: function () {
+    window.location.reload();
+  },
+
+  /**
+   * If some configs are changed and user navigates away or select another config-group, show this popup with propose to save changes
+   * @param {object} transitionCallback - callback with action to change configs view
+   * @return {App.ModalPopup}
+   * @method showSavePopup
+   */
+  showSavePopup: function (transitionCallback) {
+    var self = this;
+    return App.ModalPopup.show({
+      header: Em.I18n.t('dashboard.configHistory.info-bar.save.popup.title'),
+      footerClass: Em.View.extend({
+        templateName: require('templates/main/service/info/save_popup_footer'),
+      }),
+      primary: Em.I18n.t('common.save'),
+      secondary: Em.I18n.t('common.cancel'),
+      onSave: function () {
+        //save cluster setting
+        if (self.get('valueChanged')) {
+          self.saveClusterConfigs(self.get('clusterConfigs'));
+        }
+        //save component settings
+        var enabledComponents = [];
+        var disabledComponents = [];
+        self.get('tabs').forEach(function (service) {
+          service.get('componentRecovery').forEach(function (component) {
+            if (component.get('valueChanged')) {
+              if (component.get('recoveryEnabled')) {
+                enabledComponents.push(component.get('component_name'));
+              } else {
+                disabledComponents.push(component.get('component_name'));
+              }
+            }
+          });
+        });
+        if (enabledComponents.length){
+          App.ajax.send({
+            name: 'components.update',
+            sender: this,
+            data: {
+              ServiceComponentInfo: {
+                recovery_enabled: "true"
+              },
+              query: 'ServiceComponentInfo/component_name.in(' + enabledComponents.join(',') + ')'
+            }
+          });
+        }
+        if (disabledComponents.length){
+          App.ajax.send({
+            name: 'components.update',
+            sender: this,
+            data: {
+              ServiceComponentInfo: {
+                recovery_enabled: "false"
+              },
+              query: 'ServiceComponentInfo/component_name.in(' + disabledComponents.join(',') + ')'
+            }
+          });
+        }
+        if (typeof transitionCallback === 'function') {
+          transitionCallback();
+        } else {
+          self.doReload();
+        }
+        this.hide();
+      },
+      onDiscard: function () {
+        if (typeof transitionCallback === 'function') {
+          transitionCallback();
+        } else {
+          self.doReload();
+        }
+        this.hide();
+      },
+      onCancel: function () {
+        this.hide();
+      }
+    });
+  },
+
   saveClusterConfigs: function (clusterConfigs) {
     return App.ajax.send({
       name: 'admin.save_configs',
@@ -41,5 +201,4 @@ App.MainAdminServiceAutoStartController = Em.Controller.extend({
       }
     });
   }
-
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/364ee026/ambari-web/app/routes/main.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/main.js b/ambari-web/app/routes/main.js
index cbaf34d..891bf34 100644
--- a/ambari-web/app/routes/main.js
+++ b/ambari-web/app/routes/main.js
@@ -525,6 +525,14 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
       connectOutlets: function (router) {
         router.set('mainAdminController.category', "serviceAutoStart");
         router.get('mainAdminController').connectOutlet('mainAdminServiceAutoStart');
+      },
+      exitRoute: function (router, context, callback) {
+        var controller = router.get('mainAdminServiceAutoStartController');
+        if (!controller.get('isSaveDisabled')) {
+          controller.showSavePopup(callback);
+        } else {
+          callback();
+        }
       }
     }),
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/364ee026/ambari-web/app/styles/application.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less
index a1969db..6c5d4d0 100644
--- a/ambari-web/app/styles/application.less
+++ b/ambari-web/app/styles/application.less
@@ -3807,6 +3807,11 @@ table.graphs {
   .bootstrap-switch {
     margin-left: 20px;
   }
+
+  .nav i {
+    margin-top: 0;
+    color: @green;
+  }
 }
 
 .admin-user-settings {

http://git-wip-us.apache.org/repos/asf/ambari/blob/364ee026/ambari-web/app/templates/main/admin/service_auto_start.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/admin/service_auto_start.hbs b/ambari-web/app/templates/main/admin/service_auto_start.hbs
index b5c1032..5d9b67c 100644
--- a/ambari-web/app/templates/main/admin/service_auto_start.hbs
+++ b/ambari-web/app/templates/main/admin/service_auto_start.hbs
@@ -24,14 +24,48 @@
     {{t admin.serviceAutoStart.header.text}}
   </div>
   <br/>
-  <div class="cluster-switcher">
-    <p>{{t admin.serviceAutoStart.body.text}}
-        {{view Ember.Checkbox checkedBinding="view.switcherValue"}}
-    </p>
+  <div class="cluster-switcher row-fluid">
+      <div class="span4">
+        {{t admin.serviceAutoStart.body.text}}
+      </div>
+      <div class="span4">
+          {{view Ember.Checkbox checkedBinding="view.switcherValue"}}
+      </div>
+      <div class="pull-right operations-button pull-right">
+          <button class="btn" {{action doReload target="controller"}} {{bindAttr disabled="controller.isSaveDisabled"}}>{{t common.discard}}</button>
+          <button class="btn btn-success" {{action showSavePopup target="controller"}} {{bindAttr disabled="controller.isSaveDisabled"}}>{{t common.save}}</button>
+      </div>
   </div>
     {{#if view.switcherValue}}
-        <div>
+        <div class="tabs-left">
             <hr>
+            <ul class="nav nav-tabs">
+                {{#each tab in controller.tabs}}
+                    <li {{bindAttr class="tab.isActive:active"}}>
+                        <a href="#" data-toggle="tab" {{bindAttr data-target="tab.headingClass"}}>
+                            {{tab.display_name}}
+                            <i {{bindAttr class=":pull-right tab.indicator"}}>
+                            </i>
+                        </a>
+                    </li>
+                {{/each}}
+            </ul>
+            <div class="tab-content">
+                {{#each tab in controller.tabs}}
+                    <div {{bindAttr class=":tab-pane tab.isActive:active tab.service_name :row-fluid"}}>
+                        {{#each component in tab.componentRecovery}}
+                            <div class="row-fluid">
+                                <div class="span4">
+                                    {{component.display_name}}
+                                </div>
+                                <div class="span8">
+                                    {{view App.MainAdminServiceAutoStartComponentView recoveryEnabledBinding="component.recovery_enabled" componentBinding="component" tabBinding="tab"}}
+                                </div>
+                            </div>
+                        {{/each}}
+                    </div>
+                {{/each}}
+            </div>
         </div>
     {{/if}}
-</div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/364ee026/ambari-web/app/templates/main/admin/service_auto_start/component_auto_start.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/admin/service_auto_start/component_auto_start.hbs b/ambari-web/app/templates/main/admin/service_auto_start/component_auto_start.hbs
new file mode 100644
index 0000000..56af5ad
--- /dev/null
+++ b/ambari-web/app/templates/main/admin/service_auto_start/component_auto_start.hbs
@@ -0,0 +1,19 @@
+{{!
+* 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 Ember.Checkbox checkedBinding="view.recoveryEnabled"}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/364ee026/ambari-web/app/utils/ajax/ajax.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js
index 8b89365..ce6a196 100644
--- a/ambari-web/app/utils/ajax/ajax.js
+++ b/ambari-web/app/utils/ajax/ajax.js
@@ -2340,6 +2340,27 @@ var urls = {
     'real': '/clusters/{clusterName}/components?fields=host_components/HostRoles/host_name,ServiceComponentInfo/component_name,ServiceComponentInfo/started_count{urlParams}&minimal_response=true',
     'mock': ''
   },
+  'components.get_category': {
+    'real': '/clusters/{clusterName}/components?fields=ServiceComponentInfo/component_name,ServiceComponentInfo/service_name,ServiceComponentInfo/category,ServiceComponentInfo/recovery_enabled&minimal_response=true',
+    'mock': ''
+  },
+  'components.update': {
+    'real': '/clusters/{clusterName}/components?{urlParams}',
+    'mock': '',
+    'type': 'PUT',
+    'format': function (data) {
+      return {
+        data: JSON.stringify({
+          RequestInfo: {
+            query: data.query
+          },
+          Body: {
+            ServiceComponentInfo: data.ServiceComponentInfo
+          }
+        })
+      }
+    }
+  },
   'hosts.all.install': {
     'real': '/hosts?minimal_response=true',
     'mock': ''

http://git-wip-us.apache.org/repos/asf/ambari/blob/364ee026/ambari-web/app/views.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js
index 570f6cd..a4008f7 100644
--- a/ambari-web/app/views.js
+++ b/ambari-web/app/views.js
@@ -141,6 +141,7 @@ require('views/main/host/metrics/processes');
 require('views/main/host/addHost/step4_view');
 require('views/main/admin');
 require('views/main/admin/service_auto_start');
+require('views/main/admin/service_auto_start/component_auto_start');
 require('views/main/admin/highAvailability/nameNode/wizard_view');
 require('views/main/admin/highAvailability/progress_view');
 require('views/main/admin/highAvailability/nameNode/rollback_view');

http://git-wip-us.apache.org/repos/asf/ambari/blob/364ee026/ambari-web/app/views/main/admin/service_auto_start.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/admin/service_auto_start.js b/ambari-web/app/views/main/admin/service_auto_start.js
index 2d3ae16..dcbbfc9 100644
--- a/ambari-web/app/views/main/admin/service_auto_start.js
+++ b/ambari-web/app/views/main/admin/service_auto_start.js
@@ -28,7 +28,7 @@ App.MainAdminServiceAutoStartView = Em.View.extend({
    */
   switcherValue: false,
 
-  clusterConfigs: null,
+  savedRecoveryEnabled: false,
 
   didInsertElement: function () {
     var self = this;
@@ -41,12 +41,14 @@ App.MainAdminServiceAutoStartView = Em.View.extend({
         }
       ];
       App.router.get('configurationController').getConfigsByTags(tag).done(function (data) {
-        self.set('clusterConfigs', data[0].properties);
-        self.set('switcherValue', self.get('clusterConfigs.recovery_enabled') === 'true');
+        self.set('controller.clusterConfigs', data[0].properties);
+        self.set('switcherValue', data[0].properties.recovery_enabled === 'true');
+        self.set('savedRecoveryEnabled', self.get('switcherValue'));
         // plugin should be initiated after applying binding for switcherValue
         Em.run.later('sync', function() {
           self.initSwitcher();
         }.bind(self), 10);
+        self.get('controller').loadComponentsConfigs();
       });
     });
   },
@@ -58,8 +60,8 @@ App.MainAdminServiceAutoStartView = Em.View.extend({
    */
   updateClusterConfigs: function (state){
     this.set('switcherValue', state);
-    this.set('clusterConfigs.recovery_enabled', '' + state);
-    this.get('controller').saveClusterConfigs(this.get('clusterConfigs'));
+    this.set('controller.clusterConfigs.recovery_enabled', '' + state);
+    this.set('controller.valueChanged', this.get('savedRecoveryEnabled') !== state);
   },
 
   /**
@@ -70,7 +72,7 @@ App.MainAdminServiceAutoStartView = Em.View.extend({
   initSwitcher: function () {
     var self = this;
     if (this.$()) {
-      var switcher = this.$("input:eq(0)").bootstrapSwitch({
+      this.$("input:eq(0)").bootstrapSwitch({
         onText: Em.I18n.t('common.enabled'),
         offText: Em.I18n.t('common.disabled'),
         offColor: 'default',

http://git-wip-us.apache.org/repos/asf/ambari/blob/364ee026/ambari-web/app/views/main/admin/service_auto_start/component_auto_start.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/admin/service_auto_start/component_auto_start.js b/ambari-web/app/views/main/admin/service_auto_start/component_auto_start.js
new file mode 100644
index 0000000..cc910b8
--- /dev/null
+++ b/ambari-web/app/views/main/admin/service_auto_start/component_auto_start.js
@@ -0,0 +1,57 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+App.MainAdminServiceAutoStartComponentView = Em.View.extend({
+  templateName: require('templates/main/admin/service_auto_start/component_auto_start'),
+
+  recoveryEnabled: false,
+  savedRecoveryEnabled: false,
+  tab: null,
+  component: null,
+
+  didInsertElement: function () {
+    this.set('savedRecoveryEnabled', this.get('recoveryEnabled'));
+    this.initSwitcher();
+  },
+
+  /**
+   * Init switcher plugin.
+   *
+   * @method initSwitcher
+   */
+  initSwitcher: function () {
+    var self = this;
+    if (this.$()) {
+      this.$("input:eq(0)").bootstrapSwitch({
+        onText: Em.I18n.t('common.enabled'),
+        offText: Em.I18n.t('common.disabled'),
+        offColor: 'default',
+        onColor: 'success',
+        handleWidth: Math.max(Em.I18n.t('common.enabled').length, Em.I18n.t('common.disabled').length) * 8,
+        onSwitchChange: function (event, state) {
+          self.set('tab.enabledComponents', self.get('tab.enabledComponents') + (state ? 1 : -1));
+          self.set('recoveryEnabled', state);
+          self.set('component.valueChanged', self.get('savedRecoveryEnabled') !== state);
+          self.get('parentView.controller').checkValuesChange();
+        }
+      });
+    }
+  }
+});
\ No newline at end of file