You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by at...@apache.org on 2015/05/13 17:04:58 UTC

[1/2] ambari git commit: AMBARI-11101 Apply property changes in Yarn when ranger-yarn-plugin is enabled. (atkach)

Repository: ambari
Updated Branches:
  refs/heads/trunk 27f566dd7 -> df3fca0fb


AMBARI-11101 Apply property changes in Yarn when ranger-yarn-plugin is enabled. (atkach)


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

Branch: refs/heads/trunk
Commit: 7edcfc4d6dac9088ad019c532916c64fe1754e73
Parents: 27f566d
Author: Andrii Tkach <at...@hortonworks.com>
Authored: Wed May 13 15:02:47 2015 +0300
Committer: Andrii Tkach <at...@hortonworks.com>
Committed: Wed May 13 18:04:37 2015 +0300

----------------------------------------------------------------------
 ambari-web/app/assets/test/tests.js             |  1 +
 .../configs/modification_handlers/hbase.js      |  8 +-
 .../utils/configs/modification_handlers/hdfs.js |  8 +-
 .../utils/configs/modification_handlers/hive.js |  6 --
 .../utils/configs/modification_handlers/knox.js |  6 --
 .../modification_handler.js                     |  6 ++
 .../configs/modification_handlers/storm.js      |  8 +-
 .../utils/configs/modification_handlers/yarn.js | 71 ++++++++++++++++++
 .../configs/service_configs_by_category_view.js |  7 +-
 .../modification_handler_test.js                | 78 ++++++++++++++++++++
 10 files changed, 163 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/7edcfc4d/ambari-web/app/assets/test/tests.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js
index eed4cc7..eeafa57 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -165,6 +165,7 @@ var files = ['test/init_model_test',
   'test/utils/ui_effects_test',
   'test/utils/updater_test',
   'test/utils/configs/config_property_helper_test',
+  'test/utils/configs/modification_handlers/modification_handler_test',
   'test/views/common/chart/linear_time_test',
   'test/views/common/configs/widgets/combo_config_widget_view_test',
   'test/views/common/configs/widgets/config_widget_view_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/7edcfc4d/ambari-web/app/utils/configs/modification_handlers/hbase.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/configs/modification_handlers/hbase.js b/ambari-web/app/utils/configs/modification_handlers/hbase.js
index b5a342f..f093507 100644
--- a/ambari-web/app/utils/configs/modification_handlers/hbase.js
+++ b/ambari-web/app/utils/configs/modification_handlers/hbase.js
@@ -21,12 +21,6 @@ require('utils/configs/modification_handlers/modification_handler');
 module.exports = App.ServiceConfigModificationHandler.create({
   serviceId : 'HBASE',
 
-  getConfig : function(allConfigs, configName, configFilename, configServiceName) {
-    return allConfigs.findProperty("serviceName", configServiceName).get("configs").find(function(config) {
-      return configName == config.get('name') && (configFilename == null || configFilename == config.get('filename'));
-    });
-  },
-
   updateConfigClasses : function(configClasses, authEnabled, affectedProperties, addOldValue) {
     if (configClasses != null) {
       var xaAuthCoProcessorClass = "com.xasecure.authorization.hbase.XaSecureAuthorizationCoprocessor";
@@ -91,7 +85,7 @@ module.exports = App.ServiceConfigModificationHandler.create({
       var newAuthEnabledValue = authEnabled ? "true" : "false";
       var newRpcProtectionValue = authEnabled ? "privacy" : "authentication";
 
-      // Add Hive-Ranger configs
+      // Add HBase-Ranger configs
       this.updateConfigClasses(configMasterClasses, authEnabled, affectedProperties, configAuthEnabled.get('value') == 'true');
       this.updateConfigClasses(configRegionClasses, authEnabled, affectedProperties, configAuthEnabled.get('value') == 'true');
       if (newRpcProtectionValue !== configRpcProtection.get('value')) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/7edcfc4d/ambari-web/app/utils/configs/modification_handlers/hdfs.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/configs/modification_handlers/hdfs.js b/ambari-web/app/utils/configs/modification_handlers/hdfs.js
index bff1ddd..bd18a48 100644
--- a/ambari-web/app/utils/configs/modification_handlers/hdfs.js
+++ b/ambari-web/app/utils/configs/modification_handlers/hdfs.js
@@ -21,12 +21,6 @@ require('utils/configs/modification_handlers/modification_handler');
 module.exports = App.ServiceConfigModificationHandler.create({
   serviceId : 'HDFS',
 
-  getConfig : function(allConfigs, configName, configFilename, configServiceName) {
-    return allConfigs.findProperty("serviceName", configServiceName).get("configs").find(function(config) {
-      return configName == config.get('name') && (configFilename == null || configFilename == config.get('filename'));
-    });
-  },
-
   getDependentConfigChanges : function(changedConfig, selectedServices, allConfigs, securityEnabled) {
     var affectedProperties = [];
     var newValue = changedConfig.get("value");
@@ -41,7 +35,7 @@ module.exports = App.ServiceConfigModificationHandler.create({
       var newDfsPermissionsEnabled = rangerPluginEnabled ? "true" : "true";
       var newAttributesProviderClass = 'org.apache.ranger.authorization.hadoop.RangerHdfsAuthorizer';
 
-      // Add Hive-Ranger configs
+      // Add HDFS-Ranger configs
       if (configDfsPermissionsEnabled != null && newDfsPermissionsEnabled !== configDfsPermissionsEnabled.get('value')) {
         affectedProperties.push({
           serviceName : "HDFS",

http://git-wip-us.apache.org/repos/asf/ambari/blob/7edcfc4d/ambari-web/app/utils/configs/modification_handlers/hive.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/configs/modification_handlers/hive.js b/ambari-web/app/utils/configs/modification_handlers/hive.js
index 092ef40..e34e488 100644
--- a/ambari-web/app/utils/configs/modification_handlers/hive.js
+++ b/ambari-web/app/utils/configs/modification_handlers/hive.js
@@ -21,12 +21,6 @@ require('utils/configs/modification_handlers/modification_handler');
 module.exports = App.ServiceConfigModificationHandler.create({
   serviceId : 'HIVE',
 
-  getConfig : function(allConfigs, configName, configFilename, configServiceName) {
-    return allConfigs.findProperty("serviceName", configServiceName).get("configs").find(function(config) {
-      return configName == config.get('name') && (configFilename == null || configFilename == config.get('filename'));
-    });
-  },
-
   getDependentConfigChanges : function(changedConfig, selectedServices, allConfigs, securityEnabled) {
     var affectedProperties = [];
     var newValue = changedConfig.get("value");

http://git-wip-us.apache.org/repos/asf/ambari/blob/7edcfc4d/ambari-web/app/utils/configs/modification_handlers/knox.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/configs/modification_handlers/knox.js b/ambari-web/app/utils/configs/modification_handlers/knox.js
index 3b0740c..482c535 100644
--- a/ambari-web/app/utils/configs/modification_handlers/knox.js
+++ b/ambari-web/app/utils/configs/modification_handlers/knox.js
@@ -21,12 +21,6 @@ require('utils/configs/modification_handlers/modification_handler');
 module.exports = App.ServiceConfigModificationHandler.create({
   serviceId : 'KNOX',
 
-  getConfig : function(allConfigs, configName, configFilename, configServiceName) {
-    return allConfigs.findProperty("serviceName", configServiceName).get("configs").find(function(config) {
-      return configName == config.get('name') && (configFilename == null || configFilename == config.get('filename'));
-    });
-  },
-
   getDependentConfigChanges : function(changedConfig, selectedServices, allConfigs, securityEnabled) {
     var affectedProperties = [];
     var newValue = changedConfig.get("value");

http://git-wip-us.apache.org/repos/asf/ambari/blob/7edcfc4d/ambari-web/app/utils/configs/modification_handlers/modification_handler.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/configs/modification_handlers/modification_handler.js b/ambari-web/app/utils/configs/modification_handlers/modification_handler.js
index 5b32cde..5ec6c8b 100644
--- a/ambari-web/app/utils/configs/modification_handlers/modification_handler.js
+++ b/ambari-web/app/utils/configs/modification_handlers/modification_handler.js
@@ -58,6 +58,12 @@ App.ServiceConfigModificationHandler = Em.Object.extend({
    */
   getDependentConfigChanges : function(changedConfig, selectedServices, allConfigs, securityEnabled) {
     return [];
+  },
+
+  getConfig: function(allConfigs, configName, configFilename, configServiceName) {
+    return allConfigs.findProperty('serviceName', configServiceName).get('configs').find(function(config) {
+      return configName == config.get('name') && (configFilename == null || configFilename == config.get('filename'));
+    });
   }
 
 });
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/7edcfc4d/ambari-web/app/utils/configs/modification_handlers/storm.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/configs/modification_handlers/storm.js b/ambari-web/app/utils/configs/modification_handlers/storm.js
index 3e27e3e..3dbe8be 100644
--- a/ambari-web/app/utils/configs/modification_handlers/storm.js
+++ b/ambari-web/app/utils/configs/modification_handlers/storm.js
@@ -21,12 +21,6 @@ require('utils/configs/modification_handlers/modification_handler');
 module.exports = App.ServiceConfigModificationHandler.create({
   serviceId : 'STORM',
 
-  getConfig : function(allConfigs, configName, configFilename, configServiceName) {
-    return allConfigs.findProperty("serviceName", configServiceName).get("configs").find(function(config) {
-      return configName == config.get('name') && (configFilename == null || configFilename == config.get('filename'));
-    });
-  },
-
   getDependentConfigChanges : function(changedConfig, selectedServices, allConfigs, securityEnabled) {
     var affectedProperties = [];
     var newValue = changedConfig.get("value");
@@ -42,7 +36,7 @@ module.exports = App.ServiceConfigModificationHandler.create({
         var newNimbusAuthorizer = authEnabled ? "com.xasecure.authorization.storm.authorizer.XaSecureStormAuthorizer"
             : "backtype.storm.security.auth.authorizer.SimpleACLAuthorizer";
 
-        // Add Hive-Ranger configs
+        // Add Storm-Ranger configs
         if (newNimbusAuthorizer !== configNimbusAuthorizer.get('value')) {
           affectedProperties.push({
             serviceName : "STORM",

http://git-wip-us.apache.org/repos/asf/ambari/blob/7edcfc4d/ambari-web/app/utils/configs/modification_handlers/yarn.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/configs/modification_handlers/yarn.js b/ambari-web/app/utils/configs/modification_handlers/yarn.js
new file mode 100644
index 0000000..55bb1a9
--- /dev/null
+++ b/ambari-web/app/utils/configs/modification_handlers/yarn.js
@@ -0,0 +1,71 @@
+/**
+ * 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');
+require('utils/configs/modification_handlers/modification_handler');
+
+module.exports = App.ServiceConfigModificationHandler.create({
+  serviceId: 'YARN',
+
+  getDependentConfigChanges: function (changedConfig, selectedServices, allConfigs, securityEnabled) {
+    var affectedProperties = [],
+      newValue = changedConfig.get('value'),
+      rangerPluginEnabledName = 'ranger-yarn-plugin-enabled',
+      affectedPropertyName = changedConfig.get('name');
+    if (affectedPropertyName == rangerPluginEnabledName) {
+      var configYarnAclEnable = this.getConfig(allConfigs, 'yarn.acl.enable', 'yarn-site.xml', 'YARN'),
+        configAuthorizationProviderClass = this.getConfig(allConfigs, 'yarn.authorization-provider', 'yarn-site.xml', 'YARN'),
+        isAuthorizationProviderClassNotSet = typeof configAuthorizationProviderClass === 'undefined',
+        rangerPluginEnabled = newValue == 'Yes',
+        newYarnAclEnable = 'true',
+        newAuthorizationProviderClass = 'org.apache.ranger.authorization.yarn.authorizer.RangerYarnAuthorizer';
+
+      // Add YARN-Ranger configs
+      if (rangerPluginEnabled) {
+        if (configYarnAclEnable != null && newYarnAclEnable !== configYarnAclEnable.get('value')) {
+          affectedProperties.push({
+            serviceName: 'YARN',
+            sourceServiceName: 'YARN',
+            propertyName: 'yarn.acl.enable',
+            propertyDisplayName: 'yarn.acl.enable',
+            newValue: newYarnAclEnable,
+            curValue: configYarnAclEnable.get('value'),
+            changedPropertyName: rangerPluginEnabledName,
+            removed: false,
+            filename: 'yarn-site.xml'
+          });
+        }
+        if (isAuthorizationProviderClassNotSet || newAuthorizationProviderClass !== configAuthorizationProviderClass.get('value')) {
+          affectedProperties.push({
+            serviceName: 'YARN',
+            sourceServiceName: 'YARN',
+            propertyName: 'yarn.authorization-provider',
+            propertyDisplayName: 'yarn.authorization-provider',
+            newValue: newAuthorizationProviderClass,
+            curValue: isAuthorizationProviderClassNotSet ? '': configAuthorizationProviderClass.get('value'),
+            changedPropertyName: rangerPluginEnabledName,
+            removed: false,
+            isNewProperty: isAuthorizationProviderClassNotSet,
+            filename: 'yarn-site.xml',
+            categoryName: 'Custom yarn-site'
+          });
+        }
+      }
+    }
+    return affectedProperties;
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/7edcfc4d/ambari-web/app/views/common/configs/service_configs_by_category_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/configs/service_configs_by_category_view.js b/ambari-web/app/views/common/configs/service_configs_by_category_view.js
index ae77abe..56f34bf 100644
--- a/ambari-web/app/views/common/configs/service_configs_by_category_view.js
+++ b/ambari-web/app/views/common/configs/service_configs_by_category_view.js
@@ -189,9 +189,10 @@ App.ServiceConfigsByCategoryView = Em.View.extend(App.UserPref, App.ConfigOverri
           this.hide();
         },
         onUndo: function () {
-          var affected = self.get("newAffectedProperties").objectAt(0);
-          self.get("controller.stepConfigs").findProperty("serviceName", affected.sourceServiceName).get("configs")
-          .findProperty("name", affected.changedPropertyName).set("value", $.trim(affected.curValue));
+          var affected = self.get("newAffectedProperties").objectAt(0),
+            changedProperty = self.get("controller.stepConfigs").findProperty("serviceName", affected.sourceServiceName)
+              .get("configs").findProperty("name", affected.changedPropertyName);
+          changedProperty.set('value', changedProperty.get('defaultValue'));
           self.get("controller").set("miscModalVisible", false);
           this.hide();
         },

http://git-wip-us.apache.org/repos/asf/ambari/blob/7edcfc4d/ambari-web/test/utils/configs/modification_handlers/modification_handler_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/configs/modification_handlers/modification_handler_test.js b/ambari-web/test/utils/configs/modification_handlers/modification_handler_test.js
new file mode 100644
index 0000000..c3af838
--- /dev/null
+++ b/ambari-web/test/utils/configs/modification_handlers/modification_handler_test.js
@@ -0,0 +1,78 @@
+/**
+ * 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');
+require('utils/configs/modification_handlers/modification_handler');
+
+describe('App.ServiceConfigModificationHandler', function () {
+
+  var handler = App.ServiceConfigModificationHandler.create();
+
+  describe('#getConfig', function () {
+
+    var allConfigs = [
+        Em.Object.create({
+          serviceName: 's',
+          configs: [
+            Em.Object.create({
+              name: 'c1',
+              filename: 'f1'
+            })
+          ]
+        })
+      ],
+      cases = [
+        {
+          configName: 'c0',
+          result: undefined,
+          title: 'property isn\'t defined'
+        },
+        {
+          configName: 'c1',
+          result: Em.Object.create({
+            name: 'c1',
+            filename: 'f1'
+          }),
+          title: 'property is defined, filename isn\'t passed'
+        },
+        {
+          configName: 'c1',
+          configFilename: 'f1',
+          result: Em.Object.create({
+            name: 'c1',
+            filename: 'f1'
+          }),
+          title: 'property is defined, filename is passed'
+        },
+        {
+          configName: 'c1',
+          configFilename: 'f2',
+          result: undefined,
+          title: 'property is defined, filenames don\'t match'
+        }
+      ];
+
+    cases.forEach(function (item) {
+      it(item.title, function () {
+        expect(handler.getConfig(allConfigs, item.configName, item.configFilename, 's')).to.eql(item.result);
+      });
+    });
+
+  });
+
+});


[2/2] ambari git commit: AMBARI-11102 Widgets: bugs + edits v6. (atkach)

Posted by at...@apache.org.
AMBARI-11102 Widgets: bugs + edits v6. (atkach)


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

Branch: refs/heads/trunk
Commit: df3fca0fb5b60d52bc7bbfb149e1a178f47d640c
Parents: 7edcfc4
Author: Andrii Tkach <at...@hortonworks.com>
Authored: Wed May 13 15:30:17 2015 +0300
Committer: Andrii Tkach <at...@hortonworks.com>
Committed: Wed May 13 18:04:38 2015 +0300

----------------------------------------------------------------------
 .../service/widgets/create/step3_controller.js  | 11 +----
 .../service/widgets/create/wizard_controller.js | 47 ++++++++++++++++++++
 .../main/service/widgets/edit_controller.js     | 38 ----------------
 .../app/mixins/common/widgets/widget_mixin.js   | 16 ++++++-
 ambari-web/app/routes/add_widget.js             | 23 +---------
 .../main/service/widgets/create/step3.hbs       |  8 +---
 6 files changed, 67 insertions(+), 76 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/df3fca0f/ambari-web/app/controllers/main/service/widgets/create/step3_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/widgets/create/step3_controller.js b/ambari-web/app/controllers/main/service/widgets/create/step3_controller.js
index 43bd968..f946b74 100644
--- a/ambari-web/app/controllers/main/service/widgets/create/step3_controller.js
+++ b/ambari-web/app/controllers/main/service/widgets/create/step3_controller.js
@@ -141,19 +141,12 @@ App.WidgetWizardStep3Controller = Em.Controller.extend({
   },
 
   cancel: function () {
-    var controller = App.router.get('widgetEditController');
+    var controller = App.router.get(this.get('content.controllerName'));
     controller.cancel();
   },
 
   complete: function () {
     App.router.send('complete', this.collectWidgetData());
-    var editController = App.router.get('widgetEditController');
-    editController.finish();
-    if (editController.get('popup')) {
-      editController.get('popup').hide();
-    }
-    var serviceName = editController.get('content.widgetService');
-    var service = App.Service.find().findProperty('serviceName', serviceName);
-    App.router.transitionTo('main.services.service', service);
+    App.router.get(this.get('content.controllerName')).finishWizard();
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/df3fca0f/ambari-web/app/controllers/main/service/widgets/create/wizard_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/widgets/create/wizard_controller.js b/ambari-web/app/controllers/main/service/widgets/create/wizard_controller.js
index 46bf60f..940f7c8 100644
--- a/ambari-web/app/controllers/main/service/widgets/create/wizard_controller.js
+++ b/ambari-web/app/controllers/main/service/widgets/create/wizard_controller.js
@@ -313,6 +313,53 @@ App.WidgetWizardController = App.WizardController.extend({
     this.saveTasksRequestIds(undefined);
   },
 
+  cancel: function () {
+    var self = this;
+    var step3Controller = App.router.get('widgetWizardStep3Controller');
+    return App.ModalPopup.show({
+      header: Em.I18n.t('common.warning'),
+      bodyClass: Em.View.extend({
+        template: Ember.Handlebars.compile('{{t alerts.saveChanges}}')
+      }),
+      primary: Em.I18n.t('common.save'),
+      secondary: Em.I18n.t('common.discard'),
+      third: Em.I18n.t('common.cancel'),
+      disablePrimary: function () {
+        return !(parseInt(self.get('currentStep')) === self.get('totalSteps') && !step3Controller.get('isSubmitDisabled'));
+      }.property(''),
+      onPrimary: function () {
+        App.router.send('complete', step3Controller.collectWidgetData());
+        this.onSecondary();
+      },
+      onSecondary: function () {
+        this.hide();
+        self.finishWizard();
+      },
+      onThird: function () {
+        this.hide();
+      }
+    });
+  },
+
+  /**
+   * finish wizard
+   */
+  finishWizard: function () {
+    this.finish();
+    this.get('popup').hide();
+    var serviceName = this.get('content.widgetService');
+    var service = App.Service.find().findProperty('serviceName', serviceName);
+    App.router.transitionTo('main.services.service', service);
+    if (!App.get('testMode')) {
+      App.clusterStatus.setClusterStatus({
+        clusterName: App.router.getClusterName(),
+        clusterState: 'DEFAULT',
+        localdb: App.db.data
+      });
+    }
+  },
+
+
   /**
    * Clear all temporary data
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/df3fca0f/ambari-web/app/controllers/main/service/widgets/edit_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/widgets/edit_controller.js b/ambari-web/app/controllers/main/service/widgets/edit_controller.js
index d57711f..1744974 100644
--- a/ambari-web/app/controllers/main/service/widgets/edit_controller.js
+++ b/ambari-web/app/controllers/main/service/widgets/edit_controller.js
@@ -145,44 +145,6 @@ App.WidgetEditController = App.WidgetWizardController.extend({
 
   },
 
-  cancel: function () {
-    var self = this;
-    var step3Controller = App.router.get('widgetWizardStep3Controller');
-    return App.ModalPopup.show({
-      header: Em.I18n.t('common.warning'),
-      bodyClass: Em.View.extend({
-        template: Ember.Handlebars.compile('{{t alerts.saveChanges}}')
-      }),
-      primary: Em.I18n.t('common.save'),
-      secondary: Em.I18n.t('common.discard'),
-      third: Em.I18n.t('common.cancel'),
-      disablePrimary: function () {
-        if (self.get('currentStep') == 2 && !step3Controller.get('isSubmitDisabled')) {
-          return false;
-        } else {
-          return true;
-        }
-      }.property(''),
-      onPrimary: function () {
-        if (self.get('currentStep') == 2) {
-          App.router.send('complete', step3Controller.collectWidgetData());
-        }
-        this.onSecondary();
-      },
-      onSecondary: function () {
-        this.hide();
-        self.finish();
-        self.get('popup').hide();
-        var serviceName = self.get('content.widgetService');
-        var service = App.Service.find().findProperty('serviceName', serviceName);
-        App.router.transitionTo('main.services.service', service);
-      },
-      onThird: function () {
-        this.hide();
-      }
-    });
-  },
-
   /**
    * Clear all temporary data
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/df3fca0f/ambari-web/app/mixins/common/widgets/widget_mixin.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/widgets/widget_mixin.js b/ambari-web/app/mixins/common/widgets/widget_mixin.js
index 94fe63f..a7a748a 100644
--- a/ambari-web/app/mixins/common/widgets/widget_mixin.js
+++ b/ambari-web/app/mixins/common/widgets/widget_mixin.js
@@ -353,7 +353,7 @@ App.WidgetMixin = Ember.Mixin.create({
    */
   onMetricsLoaded: function () {
     var self = this;
-    this.set('isLoaded', true);
+    if (!this.get('isLoaded')) this.set('isLoaded', true);
     this.drawWidget();
     clearTimeout(this.get('timeoutId'));
     this.set('timeoutId', setTimeout(function () {
@@ -373,6 +373,20 @@ App.WidgetMixin = Ember.Mixin.create({
   },
 
   /**
+   * initialize tooltips
+   */
+  initTooltip: function () {
+    var self = this;
+
+    if (this.get('isLoaded')) {
+      Em.run.next(function(){
+        App.tooltip(self.$(".corner-icon > .icon-copy"), {title: Em.I18n.t('common.clone')});
+        App.tooltip(self.$(".corner-icon > .icon-edit"), {title: Em.I18n.t('common.edit')});
+      });
+    }
+  }.observes('isLoaded'),
+
+  /**
    * calculate series datasets for graph widgets
    */
   calculateValues: function () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/df3fca0f/ambari-web/app/routes/add_widget.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/add_widget.js b/ambari-web/app/routes/add_widget.js
index 0333b99..8c427f4 100644
--- a/ambari-web/app/routes/add_widget.js
+++ b/ambari-web/app/routes/add_widget.js
@@ -34,27 +34,7 @@ module.exports = App.WizardRoute.extend({
         secondary: null,
 
         onClose: function () {
-          var self = this;
-          widgetWizardController.finish();
-          if (App.testMode) {
-            self.hide();
-            var serviceName = widgetWizardController.get('content.widgetService');
-            var service = App.Service.find().findProperty('serviceName', serviceName);
-            router.transitionTo('main.services.service', service);
-          }   else {
-            App.clusterStatus.setClusterStatus({
-              clusterName: App.router.getClusterName(),
-              clusterState: 'DEFAULT',
-              localdb: App.db.data
-            }, {
-              alwaysCallback: function () {
-                self.hide();
-                var serviceName = widgetWizardController.get('content.widgetService');
-                var service = App.Service.find().findProperty('serviceName', serviceName);
-                router.transitionTo('main.services.service', service);
-              }
-            });
-          }
+          widgetWizardController.cancel();
         },
 
         didInsertElement: function () {
@@ -158,7 +138,6 @@ module.exports = App.WizardRoute.extend({
     back: Em.Router.transitionTo('step2'),
     complete: function (router, context) {
       router.get('widgetWizardController').postWidgetDefinition(context);
-      router.get('widgetWizardController.popup').onClose();
     }
   })
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/df3fca0f/ambari-web/app/templates/main/service/widgets/create/step3.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/service/widgets/create/step3.hbs b/ambari-web/app/templates/main/service/widgets/create/step3.hbs
index 22f8526..45bdee6 100644
--- a/ambari-web/app/templates/main/service/widgets/create/step3.hbs
+++ b/ambari-web/app/templates/main/service/widgets/create/step3.hbs
@@ -48,11 +48,7 @@
 
   <div class="btn-area">
     <button id="add-widget-step3-back" class="btn" {{action back}}>&larr; {{t common.back}}</button>
-    {{#if controller.isEditController}}
-      <button id="add-widget-step3-save" class="btn btn-success pull-right" {{bindAttr disabled="isSubmitDisabled"}} {{action "complete" target="controller"}}>{{t common.save}}</button>
-      <button id="add-widget-step3-cancel" class="btn pull-right" {{action "cancel" target="controller"}}>{{t common.cancel}}</button>
-    {{else}}
-      <button id="add-widget-step3-complete" class="btn btn-success pull-right" {{bindAttr disabled="isSubmitDisabled"}} {{action "complete" target="controller"}}>{{t common.complete}}</button>
-    {{/if}}
+    <button id="add-widget-step3-save" class="btn btn-success pull-right" {{bindAttr disabled="isSubmitDisabled"}} {{action "complete" target="controller"}}>{{t common.save}}</button>
+    <button id="add-widget-step3-cancel" class="btn pull-right" {{action "cancel" target="controller"}}>{{t common.cancel}}</button>
   </div>
 </div>
\ No newline at end of file