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

ambari git commit: AMBARI-13277. Provide an option to not start services in Install / Add Hosts / Add Service Wizard (akovalenko)

Repository: ambari
Updated Branches:
  refs/heads/branch-2.1 3f678191a -> 380481aeb


AMBARI-13277. Provide an option to not start services in Install / Add Hosts / Add Service Wizard (akovalenko)


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

Branch: refs/heads/branch-2.1
Commit: 380481aebe85b3a9cfb3570982bc770e0fa2bc9c
Parents: 3f67819
Author: Aleksandr Kovalenko <ak...@hortonworks.com>
Authored: Wed Sep 30 17:55:05 2015 +0300
Committer: Aleksandr Kovalenko <ak...@hortonworks.com>
Committed: Wed Sep 30 17:55:24 2015 +0300

----------------------------------------------------------------------
 ambari-web/app/assets/test/tests.js             |  2 +-
 ambari-web/app/config.js                        |  3 +-
 ambari-web/app/controllers.js                   |  1 +
 ambari-web/app/controllers/experimental.js      | 60 +++++++++++++
 .../app/controllers/wizard/step10_controller.js |  3 +-
 .../app/controllers/wizard/step9_controller.js  | 55 ++++++++----
 ambari-web/app/messages.js                      |  4 +-
 ambari-web/app/router.js                        |  8 +-
 ambari-web/app/routes/installer.js              | 64 +++++++-------
 ambari-web/app/routes/main.js                   | 62 ++++++-------
 ambari-web/app/templates/experimental.hbs       |  6 +-
 ambari-web/app/views/experimental.js            | 27 +-----
 ambari-web/app/views/wizard/step9_view.js       |  2 +-
 .../test/controllers/experimental_test.js       | 92 ++++++++++++++++++++
 .../test/controllers/wizard/step9_test.js       | 23 ++++-
 ambari-web/test/views/experimental_test.js      | 92 --------------------
 16 files changed, 295 insertions(+), 209 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/380481ae/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 6869817..432e6fd 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -107,6 +107,7 @@ var files = ['test/init_model_test',
   'test/controllers/application_test',
   'test/controllers/main_test',
   'test/controllers/login_controller_test',
+  'test/controllers/experimental_test',
   'test/controllers/wizard_test',
   'test/controllers/wizard/slave_component_groups_controller',
   'test/controllers/wizard/step0_test',
@@ -280,7 +281,6 @@ var files = ['test/init_model_test',
   'test/views/wizard/step9/hostLogPopupBody_view_test',
   'test/views/wizard/step10_view_test',
   'test/views/application_test',
-  'test/views/experimental_test',
   'test/views/installer_test',
   'test/views/login_test',
   'test/models/service/flume_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/380481ae/ambari-web/app/config.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/config.js b/ambari-web/app/config.js
index ff35875..d33239a 100644
--- a/ambari-web/app/config.js
+++ b/ambari-web/app/config.js
@@ -74,7 +74,8 @@ App.supports = {
   opsDuringRollingUpgrade: false,
   customizedWidgetLayout: false,
   enhancedConfigs: true,
-  showPageLoadTime: false
+  showPageLoadTime: false,
+  skipComponentStartAfterInstall: false
 };
 
 if (App.enableExperimental) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/380481ae/ambari-web/app/controllers.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers.js b/ambari-web/app/controllers.js
index 652142d..12f1753 100644
--- a/ambari-web/app/controllers.js
+++ b/ambari-web/app/controllers.js
@@ -23,6 +23,7 @@ require('controllers/application');
 require('controllers/login_controller');
 require('controllers/wizard');
 require('controllers/installer');
+require('controllers/experimental');
 require('controllers/global/background_operations_controller');
 require('controllers/main');
 require('controllers/main/dashboard');

http://git-wip-us.apache.org/repos/asf/ambari/blob/380481ae/ambari-web/app/controllers/experimental.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/experimental.js b/ambari-web/app/controllers/experimental.js
new file mode 100644
index 0000000..d338622
--- /dev/null
+++ b/ambari-web/app/controllers/experimental.js
@@ -0,0 +1,60 @@
+/**
+ * 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.ExperimentalController = Em.Controller.extend(App.UserPref, {
+  name: 'experimentalController',
+  supports: function () {
+    var supports = [];
+    Em.keys(App.get('supports')).forEach(function (sup) {
+      supports.push(Ember.Object.create({
+        name: sup,
+        selected: App.get('supports')[sup]
+      }));
+    });
+    return supports;
+  }.property('App.supports'),
+
+
+  loadSupports: function () {
+    return this.getUserPref('user-pref-' + App.router.get('loginName') + '-supports');
+  },
+
+  getUserPrefSuccessCallback: function (response, request, data) {
+    if (response) {
+      App.set('supports', response);
+    }
+  },
+
+  doSave: function () {
+    var supports = this.get('supports');
+    supports.forEach(function(s){
+      var propName = 'App.supports.' + s.get('name');
+      var propValue = s.get('selected');
+      console.log(">>>>>>>> " + propName + " = "+ propValue);
+      Ember.set(propName, propValue);
+    });
+    this.postUserPref('user-pref-' + App.router.get('loginName') + '-supports', App.get('supports')).complete(function(){
+      App.router.transitionTo('root.index');
+    });
+  },
+
+  doCancel: function () {
+    App.router.transitionTo('root.index');
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/380481ae/ambari-web/app/controllers/wizard/step10_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard/step10_controller.js b/ambari-web/app/controllers/wizard/step10_controller.js
index f0395ea..ca1badb 100644
--- a/ambari-web/app/controllers/wizard/step10_controller.js
+++ b/ambari-web/app/controllers/wizard/step10_controller.js
@@ -106,7 +106,8 @@ App.WizardStep10Controller = Em.Controller.extend({
       return ['warning', 'failed'].contains(host.status);
     });
     if (succeededHosts.length) {
-      var successStatement = Em.I18n.t('installer.step10.servicesSummary').format(succeededHosts.length) + ((succeededHosts.length > 1) ? Em.I18n.t('installer.step8.hosts') : Em.I18n.t('installer.step8.host'));
+      var successMessage = this.get('content.cluster.status') === 'START_SKIPPED' ? Em.I18n.t('installer.step10.installed') : Em.I18n.t('installer.step10.installedAndStarted');
+      var successStatement = successMessage.format(succeededHosts.length) + ((succeededHosts.length > 1) ? Em.I18n.t('installer.step8.hosts') : Em.I18n.t('installer.step8.host'));
       this.get('clusterInfo').findProperty('id', 1).get('status').pushObject(Em.Object.create({
         id: 1,
         color: 'text-success',

http://git-wip-us.apache.org/repos/asf/ambari/blob/380481ae/ambari-web/app/controllers/wizard/step9_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard/step9_controller.js b/ambari-web/app/controllers/wizard/step9_controller.js
index abfb56a..f44abc2 100644
--- a/ambari-web/app/controllers/wizard/step9_controller.js
+++ b/ambari-web/app/controllers/wizard/step9_controller.js
@@ -106,7 +106,7 @@ App.WizardStep9Controller = Em.Controller.extend(App.ReloadPopupMixin, {
    * @type {bool}
    */
   isSubmitDisabled: function () {
-    var validStates = ['STARTED', 'START FAILED'];
+    var validStates = ['STARTED', 'START FAILED', 'START_SKIPPED'];
     var controllerName = this.get('content.controllerName');
     if (controllerName == 'addHostController' || controllerName == 'addServiceController') {
       validStates.push('INSTALL FAILED');
@@ -616,7 +616,7 @@ App.WizardStep9Controller = Em.Controller.extend(App.ReloadPopupMixin, {
   onSuccessPerHost: function (actions, contentHost) {
     var status = this.get('content.cluster.status');
     if (actions.everyProperty('Tasks.status', 'COMPLETED') && 
-        (status === 'INSTALLED' || status === 'STARTED') ) {
+        (status === 'INSTALLED' || status === 'STARTED') || App.get('supports.skipComponentStartAfterInstall')) {
       contentHost.set('status', 'success');
     }
   },
@@ -690,6 +690,7 @@ App.WizardStep9Controller = Em.Controller.extend(App.ReloadPopupMixin, {
     var completedActions = 0;
     var queuedActions = 0;
     var inProgressActions = 0;
+    var installProgressFactor = App.get('supports.skipComponentStartAfterInstall') ? 100 : 33;
     actions.forEach(function (action) {
       completedActions += +(['COMPLETED', 'FAILED', 'ABORTED', 'TIMEDOUT'].contains(action.Tasks.status));
       queuedActions += +(action.Tasks.status === 'QUEUED');
@@ -703,7 +704,7 @@ App.WizardStep9Controller = Em.Controller.extend(App.ReloadPopupMixin, {
      */
     switch (this.get('content.cluster.status')) {
       case 'PENDING':
-        progress = actionsPerHost ? (Math.ceil(((queuedActions * 0.09) + (inProgressActions * 0.35) + completedActions ) / actionsPerHost * 33)) : 33;
+        progress = actionsPerHost ? (Math.ceil(((queuedActions * 0.09) + (inProgressActions * 0.35) + completedActions ) / actionsPerHost * installProgressFactor)) : installProgressFactor;
         break;
       case 'INSTALLED':
         progress = actionsPerHost ? (33 + Math.floor(((queuedActions * 0.09) + (inProgressActions * 0.35) + completedActions ) / actionsPerHost * 67)) : 100;
@@ -841,24 +842,38 @@ App.WizardStep9Controller = Em.Controller.extend(App.ReloadPopupMixin, {
         this.get('hosts').forEach(function (host) {
           host.set('progress', '100');
         });
-        this.isAllComponentsInstalled().done(function(){
+        this.isAllComponentsInstalled().done(function () {
           self.changeParseHostInfo(false);
         });
         return;
       } else {
-        this.set('progress', '34');
-        if (this.get('content.controllerName') === 'installerController') {
-          this.isAllComponentsInstalled().done(function(){
-            self.saveInstalledHosts(self);
-            self.changeParseHostInfo(true);
+        if (App.get('supports.skipComponentStartAfterInstall')) {
+          clusterStatus.status = 'START_SKIPPED';
+          clusterStatus.isCompleted = true;
+          this.saveClusterStatus(clusterStatus);
+          this.get('hosts').forEach(function (host) {
+            host.set('status', 'success');
+            host.set('message', Em.I18n.t('installer.step9.host.status.success'));
+            host.set('progress', '100');
           });
-          return;
+          this.set('progress', '100');
+          self.saveInstalledHosts(self);
+          this.changeParseHostInfo(true);
         } else {
-          this.launchStartServices(function () {
-            self.saveInstalledHosts(self);
-            self.changeParseHostInfo(true);
-          });
-          return;
+          this.set('progress', '34');
+          if (this.get('content.controllerName') === 'installerController') {
+            this.isAllComponentsInstalled().done(function () {
+              self.saveInstalledHosts(self);
+              self.changeParseHostInfo(true);
+            });
+            return;
+          } else {
+            this.launchStartServices(function () {
+              self.saveInstalledHosts(self);
+              self.changeParseHostInfo(true);
+            });
+            return;
+          }
         }
       }
     }
@@ -924,7 +939,7 @@ App.WizardStep9Controller = Em.Controller.extend(App.ReloadPopupMixin, {
           _host.set('isNoTasksForInstall', true);
           _host.set('status', 'pending');
         }
-        if (this.get('content.cluster.status') === 'INSTALLED' || this.get('content.cluster.status') === 'FAILED') {
+        if (this.get('content.cluster.status') === 'INSTALLED' || this.get('content.cluster.status') === 'FAILED' || App.get('supports.skipComponentStartAfterInstall')) {
           _host.set('progress', '100');
           _host.set('status', 'success');
         }
@@ -1151,9 +1166,13 @@ App.WizardStep9Controller = Em.Controller.extend(App.ReloadPopupMixin, {
       this.set('progress', '100');
       this.saveClusterStatus(clusterStatus);
     } else if (this.get('content.cluster.status') === 'PENDING' && this.get('isPolling')) {
-      this.launchStartServices();
+      if (App.get('supports.skipComponentStartAfterInstall')) {
+        this.set('progress', '100');
+        this.changeParseHostInfo(true);
+      } else {
+        this.launchStartServices();
+      }
     }
-
   },
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/380481ae/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 25c1672..2959bc1 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -812,6 +812,7 @@ Em.I18n.translations = {
   'installer.step9.header':'Install, Start and Test',
   'installer.step9.body':'Please wait while the selected services are installed and started.',
   'installer.step9.status.success':'Successfully installed and started the services.',
+  'installer.step9.status.skipStartSuccess':'Successfully installed the services.',
   'installer.step9.status.warning':'Installed and started the services with some warnings.',
   'installer.step9.status.failed':'Failed to install/start the services.',
   'installer.step9.status.start.services.failed':'Start all services API call failed.',
@@ -877,7 +878,8 @@ Em.I18n.translations = {
     'services to function properly (for example, HDFS and YARN/MapReduce need to be restarted after adding Oozie). After closing this ' +
     'wizard, please restart all services that have the restart indicator <i class="icon-refresh"></i> next to the service name.',
   'installer.step10.hostsSummary':'The cluster consists of {0} hosts',
-  'installer.step10.servicesSummary':'Installed and started services successfully on {0} new ',
+  'installer.step10.installedAndStarted':'Installed and started services successfully on {0} new ',
+  'installer.step10.installed':'Installed services successfully on {0} new ',
   'installer.step10.warnings':' warnings',
   'installer.step10.clusterState.installing':'Installing ',
   'installer.step10.clusterState.starting':'Starting ',

http://git-wip-us.apache.org/repos/asf/ambari/blob/380481ae/ambari-web/app/router.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/router.js b/ambari-web/app/router.js
index 9c248f1..5f11216 100644
--- a/ambari-web/app/router.js
+++ b/ambari-web/app/router.js
@@ -587,9 +587,11 @@ App.Router = Em.Router.extend({
       },
       connectOutlets: function (router, context) {
         if (App.isAccessible('upgrade_ONLY_ADMIN')) {
-          $('title').text(Em.I18n.t('app.name.subtitle.experimental'));
-          console.log('/experimental:connectOutlet');
-          router.get('applicationController').connectOutlet('experimental');
+          App.router.get('experimentalController').loadSupports().complete(function () {
+            $('title').text(Em.I18n.t('app.name.subtitle.experimental'));
+            console.log('/experimental:connectOutlet');
+            router.get('applicationController').connectOutlet('experimental');
+          });
         }
       }
     }),

http://git-wip-us.apache.org/repos/asf/ambari/blob/380481ae/ambari-web/app/routes/installer.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/installer.js b/ambari-web/app/routes/installer.js
index 90ca2f2..cc44345 100644
--- a/ambari-web/app/routes/installer.js
+++ b/ambari-web/app/routes/installer.js
@@ -31,39 +31,41 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
     router.getAuthenticated().done(function (loggedIn) {
       if (loggedIn) {
         var applicationController = router.get('applicationController');
-        applicationController.startKeepAlivePoller();
-        // check server/web client versions match
-        App.router.get('installerController').checkServerClientVersion().done(function () {
-
-          var name = 'Cluster Install Wizard';
-          $('title').text('Ambari - ' + name);
-          $('#main').addClass('install-wizard-content');
-
-          App.router.get('mainViewsController').loadAmbariViews();
-          if (App.isAccessible('ADMIN')) {
-            router.get('mainController').stopPolling();
-            console.log('In installer with successful authenticated');
-            console.log('current step=' + router.get('installerController.currentStep'));
-            Em.run.next(function () {
-              App.clusterStatus.updateFromServer().complete(function () {
-                var currentClusterStatus = App.clusterStatus.get('value');
-                //@TODO: Clean up  following states. Navigation should be done solely via currentStep stored in the localDb and API persist endpoint.
-                //       Actual currentStep value for the installer controller should always remain in sync with localdb and at persist store in the server.
-                if (currentClusterStatus) {
-                  if (self.get('installerStatuses').contains(currentClusterStatus.clusterState)) {
-                    self.redirectToInstaller(router, currentClusterStatus, true);
+        App.router.get('experimentalController').loadSupports().complete(function () {
+          applicationController.startKeepAlivePoller();
+          // check server/web client versions match
+          App.router.get('installerController').checkServerClientVersion().done(function () {
+
+            var name = 'Cluster Install Wizard';
+            $('title').text('Ambari - ' + name);
+            $('#main').addClass('install-wizard-content');
+
+            App.router.get('mainViewsController').loadAmbariViews();
+            if (App.isAccessible('ADMIN')) {
+              router.get('mainController').stopPolling();
+              console.log('In installer with successful authenticated');
+              console.log('current step=' + router.get('installerController.currentStep'));
+              Em.run.next(function () {
+                App.clusterStatus.updateFromServer().complete(function () {
+                  var currentClusterStatus = App.clusterStatus.get('value');
+                  //@TODO: Clean up  following states. Navigation should be done solely via currentStep stored in the localDb and API persist endpoint.
+                  //       Actual currentStep value for the installer controller should always remain in sync with localdb and at persist store in the server.
+                  if (currentClusterStatus) {
+                    if (self.get('installerStatuses').contains(currentClusterStatus.clusterState)) {
+                      self.redirectToInstaller(router, currentClusterStatus, true);
+                    }
+                    else {
+                      router.transitionTo('main.dashboard.index');
+                    }
                   }
-                  else {
-                    router.transitionTo('main.dashboard.index');
-                  }
-                }
+                });
               });
-            });
-          } else {
-            Em.run.next(function () {
-              App.router.transitionTo('main.views.index');
-            });
-          }
+            } else {
+              Em.run.next(function () {
+                App.router.transitionTo('main.views.index');
+              });
+            }
+          });
         });
       } else {
         console.log('In installer but its not authenticated');

http://git-wip-us.apache.org/repos/asf/ambari/blob/380481ae/ambari-web/app/routes/main.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/main.js b/ambari-web/app/routes/main.js
index f5f9889..7188248 100644
--- a/ambari-web/app/routes/main.js
+++ b/ambari-web/app/routes/main.js
@@ -28,42 +28,44 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
     router.getAuthenticated().done(function (loggedIn) {
       if (loggedIn) {
         var applicationController = App.router.get('applicationController');
-        applicationController.startKeepAlivePoller();
-        App.router.get('mainController').checkServerClientVersion().done(function () {
-          App.router.get('mainViewsController').loadAmbariViews();
-          App.router.get('clusterController').loadClusterName(false).done(function () {
-            if (App.get('testMode')) {
-              router.get('mainController').initialize();
-            } else {
-              if (router.get('clusterInstallCompleted')) {
-                App.router.get('clusterController').loadClientServerClockDistance().done(function () {
-                  App.router.get('clusterController').checkDetailedRepoVersion().done(function () {
-                    router.get('mainController').initialize();
+        App.router.get('experimentalController').loadSupports().complete(function () {
+          applicationController.startKeepAlivePoller();
+          App.router.get('mainController').checkServerClientVersion().done(function () {
+            App.router.get('mainViewsController').loadAmbariViews();
+            App.router.get('clusterController').loadClusterName(false).done(function () {
+              if (App.get('testMode')) {
+                router.get('mainController').initialize();
+              } else {
+                if (router.get('clusterInstallCompleted')) {
+                  App.router.get('clusterController').loadClientServerClockDistance().done(function () {
+                    App.router.get('clusterController').checkDetailedRepoVersion().done(function () {
+                      router.get('mainController').initialize();
+                    });
                   });
-                });
-              }
-              else {
-                Em.run.next(function () {
-                  App.clusterStatus.updateFromServer().complete(function () {
-                    var currentClusterStatus = App.clusterStatus.get('value');
-                    if (router.get('currentState.parentState.name') !== 'views'
-                      && currentClusterStatus && self.get('installerStatuses').contains(currentClusterStatus.clusterState)) {
-                      if (App.isAccessible('ADMIN')) {
-                        self.redirectToInstaller(router, currentClusterStatus, false);
-                      } else {
-                        Em.run.next(function () {
-                          App.router.transitionTo('main.views.index');
-                        });
+                }
+                else {
+                  Em.run.next(function () {
+                    App.clusterStatus.updateFromServer().complete(function () {
+                      var currentClusterStatus = App.clusterStatus.get('value');
+                      if (router.get('currentState.parentState.name') !== 'views'
+                          && currentClusterStatus && self.get('installerStatuses').contains(currentClusterStatus.clusterState)) {
+                        if (App.isAccessible('ADMIN')) {
+                          self.redirectToInstaller(router, currentClusterStatus, false);
+                        } else {
+                          Em.run.next(function () {
+                            App.router.transitionTo('main.views.index');
+                          });
+                        }
                       }
-                    }
+                    });
                   });
-                });
-                App.router.get('clusterController').set('isLoaded', true);
+                  App.router.get('clusterController').set('isLoaded', true);
+                }
               }
-            }
+            });
           });
+          // TODO: redirect to last known state
         });
-        // TODO: redirect to last known state
       } else {
         router.set('preferedPath', router.location.location.hash);
         Em.run.next(function () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/380481ae/ambari-web/app/templates/experimental.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/experimental.hbs b/ambari-web/app/templates/experimental.hbs
index a6354e8..2873679 100644
--- a/ambari-web/app/templates/experimental.hbs
+++ b/ambari-web/app/templates/experimental.hbs
@@ -39,7 +39,7 @@
         </tr>
       </thead>
       <tbody>
-		    {{#each support in view.supports}}
+		    {{#each support in controller.supports}}
 		      <tr>
 		        <td>{{support.name}}</td>
 		        <td>{{view Ember.Checkbox checkedBinding="support.selected"}}</td>
@@ -50,8 +50,8 @@
     </table>
     <div class="control-group" style="margin-bottom: 100px;">
 	    <div class="controls pull-right">
-	      <button class="btn" {{action doCancel target="view"}}>{{t form.cancel}}</button>
-	      <button class="btn btn-primary" {{action doSave target="view"}}>{{t common.save}}</button>
+	      <button class="btn" {{action doCancel target="controller"}}>{{t form.cancel}}</button>
+	      <button class="btn btn-primary" {{action doSave target="controller"}}>{{t common.save}}</button>
 	    </div>
 	  </div>
   {{else}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/380481ae/ambari-web/app/views/experimental.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/experimental.js b/ambari-web/app/views/experimental.js
index b2c8b0c..17d01be 100644
--- a/ambari-web/app/views/experimental.js
+++ b/ambari-web/app/views/experimental.js
@@ -18,30 +18,5 @@
 var App = require('app');
 
 App.ExperimentalView = Em.View.extend({
-  templateName: require('templates/experimental'),
-  supports: function () {
-    var supports = [];
-    Em.keys(App.get('supports')).forEach(function (sup) {
-      supports.push(Ember.Object.create({
-        name: sup,
-        selected: App.get('supports')[sup]
-      }));
-    });
-    return supports;
-  }.property('App.supports'),
-
-  doSave: function () {
-    var supports = this.get('supports');
-    supports.forEach(function(s){
-      var propName = 'App.supports.' + s.get('name');
-      var propValue = s.get('selected');
-      console.log(">>>>>>>> " + propName + " = "+ propValue);
-      Ember.set(propName, propValue);
-    });
-    App.router.transitionTo('root.index');
-  },
-
-  doCancel: function () {
-    App.router.transitionTo('root.index');
-  }
+  templateName: require('templates/experimental')
 });
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/380481ae/ambari-web/app/views/wizard/step9_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/wizard/step9_view.js b/ambari-web/app/views/wizard/step9_view.js
index 4344dae..7bcec87 100644
--- a/ambari-web/app/views/wizard/step9_view.js
+++ b/ambari-web/app/views/wizard/step9_view.js
@@ -269,7 +269,7 @@ App.WizardStep9View = App.TableView.extend({
     } else if (this.get('controller.status') === 'success') {
       console.log('TRACE: Inside success view step9');
       this.set('barColor', 'progress-success');
-      this.set('resultMsg', Em.I18n.t('installer.step9.status.success'));
+      this.set('resultMsg', this.get('controller.content.cluster.status') === 'START_SKIPPED' ? Em.I18n.t('installer.step9.status.skipStartSuccess') : Em.I18n.t('installer.step9.status.success'));
       this.set('resultMsgColor', 'alert-success');
     }
   }.observes('controller.status', 'controller.startCallFailed','isHostHeartbeatLost'),

http://git-wip-us.apache.org/repos/asf/ambari/blob/380481ae/ambari-web/test/controllers/experimental_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/experimental_test.js b/ambari-web/test/controllers/experimental_test.js
new file mode 100644
index 0000000..b6fd522
--- /dev/null
+++ b/ambari-web/test/controllers/experimental_test.js
@@ -0,0 +1,92 @@
+/**
+ * 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('controllers/experimental');
+
+var controller,
+  transition,
+  supports = {},
+  transitionStubbed = false,
+  controllerSupports = [
+    Em.Object.create({
+      name: 'sup0',
+      selected: true
+    }),
+    Em.Object.create({
+      name: 'sup1',
+      selected: false
+    })
+  ],
+  saveObject = {};
+
+describe('App.ExperimentalController', function () {
+
+  before(function () {
+    controllerSupports.forEach(function(item) {
+      supports[item.get('name')] = item.get('selected');
+    });
+    sinon.stub(App, 'get', function(k) {
+      if (k === 'supports') return supports;
+      return Em.get(App, k);
+    });
+  });
+
+  beforeEach(function () {
+    controller = App.ExperimentalController.create();
+  });
+
+  after(function () {
+    App.get.restore();
+  });
+
+  describe('#supports', function () {
+    it('should take data from App.supports', function () {
+      expect(controller.get('supports')).to.eql(controllerSupports);
+    });
+  });
+
+  describe('#doSave', function () {
+
+    before(function () {
+      sinon.stub(Ember, 'set', function (p, v) {
+        if (p.indexOf('App.supports.' != -1)) {
+          p = p.replace('App.supports.', '');
+          saveObject[p] = v;
+          return;
+        }
+        return Ember.set(p, v);
+      });
+      sinon.stub(App.router, 'transitionTo', Em.K);
+    });
+
+    after(function () {
+      Em.set.restore();
+      App.router.transitionTo.restore();
+    });
+
+    it('should pass data to App.supports', function () {
+      controller.set('supports', controllerSupports);
+      controller.doSave();
+      expect(saveObject).to.eql(supports);
+    });
+
+  });
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/380481ae/ambari-web/test/controllers/wizard/step9_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/wizard/step9_test.js b/ambari-web/test/controllers/wizard/step9_test.js
index 80982cb..96379d6 100644
--- a/ambari-web/test/controllers/wizard/step9_test.js
+++ b/ambari-web/test/controllers/wizard/step9_test.js
@@ -1,4 +1,4 @@
-/**
+  /**
  * 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
@@ -32,6 +32,7 @@ var c, obj;
 describe('App.InstallerStep9Controller', function () {
 
   beforeEach(function () {
+    App.set('supports.skipComponentStartAfterInstall', false);
     modelSetup.setupStackServiceComponent();
     c = App.WizardStep9Controller.create({
       content: {controllerName: ''},
@@ -74,16 +75,19 @@ describe('App.InstallerStep9Controller', function () {
   describe('#isSubmitDisabled', function () {
     var tests = Em.A([
       {controllerName: 'addHostController', state: 'STARTED', e: false},
+      {controllerName: 'addHostController', state: 'START_SKIPPED', e: false},
       {controllerName: 'addHostController', state: 'START FAILED', e: false},
       {controllerName: 'addHostController', state: 'INSTALL FAILED', e: false},
       {controllerName: 'addHostController', state: 'PENDING', e: true},
       {controllerName: 'addHostController', state: 'INSTALLED', e: true},
       {controllerName: 'addServiceController', state: 'STARTED', e: false},
+      {controllerName: 'addServiceController', state: 'START_SKIPPED', e: false},
       {controllerName: 'addServiceController', state: 'START FAILED', e: false},
       {controllerName: 'addServiceController', state: 'INSTALL FAILED', e: false},
       {controllerName: 'addServiceController', state: 'PENDING', e: true},
       {controllerName: 'addServiceController', state: 'INSTALLED', e: true},
       {controllerName: 'installerController', state: 'STARTED', e: false},
+      {controllerName: 'installerController', state: 'START_SKIPPED', e: false},
       {controllerName: 'installerController', state: 'START FAILED', e: false},
       {controllerName: 'installerController', state: 'INSTALL FAILED', e: true},
       {controllerName: 'installerController', state: 'INSTALLED', e: true},
@@ -911,6 +915,7 @@ describe('App.InstallerStep9Controller', function () {
           'IN_PROGRESS': 1
         },
         e: {progress: 17},
+        s: false,
         m: 'All types of status available. cluster status PENDING'
       },
       {
@@ -918,9 +923,18 @@ describe('App.InstallerStep9Controller', function () {
         host: Em.Object.create({progress: 0}),
         actions: {},
         e: {progress: 33},
+        s: false,
         m: 'No tasks available. cluster status PENDING'
       },
       {
+        cluster: {status: 'PENDING'},
+        host: Em.Object.create({progress: 0}),
+        actions: {},
+        e: {progress: 100},
+        s: true,
+        m: 'No tasks available. cluster status PENDING. skipComponentStartAfterInstall is true.'
+      },
+      {
         cluster: {status: 'INSTALLED'},
         host: Em.Object.create({progress: 0}),
         actions: {},
@@ -936,6 +950,7 @@ describe('App.InstallerStep9Controller', function () {
           'IN_PROGRESS': 1
         },
         e: {progress: 66},
+        s: false,
         m: 'All types of status available. cluster status INSTALLED'
       },
       {
@@ -943,6 +958,7 @@ describe('App.InstallerStep9Controller', function () {
         host: Em.Object.create({progress: 0}),
         actions: {},
         e: {progress: 100},
+        s: false,
         m: 'Cluster status is not PENDING or INSTALLED'
       },
       {
@@ -954,6 +970,7 @@ describe('App.InstallerStep9Controller', function () {
           'IN_PROGRESS': 1
         },
         e: {progress: 99},
+        s: false,
         m: '150 tasks on host'
       },
       {
@@ -965,6 +982,7 @@ describe('App.InstallerStep9Controller', function () {
           'IN_PROGRESS': 1
         },
         e: {progress: 99},
+        s: false,
         m: '500 tasks on host'
       },
       {
@@ -976,6 +994,7 @@ describe('App.InstallerStep9Controller', function () {
           'IN_PROGRESS': 0
         },
         e: {progress: 100},
+        s: false,
         m: '100 tasks, 100 completed'
       },
       {
@@ -987,6 +1006,7 @@ describe('App.InstallerStep9Controller', function () {
           'IN_PROGRESS': 0
         },
         e: {progress: 100},
+        s: false,
         m: '1 task, 1 completed'
       }
     ]);
@@ -1001,6 +1021,7 @@ describe('App.InstallerStep9Controller', function () {
           }
         }
         c.reopen({content: {cluster: {status: test.cluster.status}}});
+        App.set('supports.skipComponentStartAfterInstall', test.s);
         var progress = c.progressPerHost(actions, test.host);
         expect(progress).to.equal(test.e.progress);
         expect(test.host.progress).to.equal(test.e.progress.toString());

http://git-wip-us.apache.org/repos/asf/ambari/blob/380481ae/ambari-web/test/views/experimental_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/experimental_test.js b/ambari-web/test/views/experimental_test.js
deleted file mode 100644
index 7767fe1..0000000
--- a/ambari-web/test/views/experimental_test.js
+++ /dev/null
@@ -1,92 +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.
- */
-
-var App = require('app');
-
-require('views/experimental');
-
-var view,
-  transition,
-  supports = {},
-  transitionStubbed = false,
-  viewSupports = [
-    Em.Object.create({
-      name: 'sup0',
-      selected: true
-    }),
-    Em.Object.create({
-      name: 'sup1',
-      selected: false
-    })
-  ],
-  saveObject = {};
-
-describe('App.ExperimentalView', function () {
-
-  before(function () {
-    viewSupports.forEach(function(item) {
-      supports[item.get('name')] = item.get('selected');
-    });
-    sinon.stub(App, 'get', function(k) {
-      if (k === 'supports') return supports;
-      return Em.get(App, k);
-    });
-  });
-
-  beforeEach(function () {
-    view = App.ExperimentalView.create();
-  });
-
-  after(function () {
-    App.get.restore();
-  });
-
-  describe('#supports', function () {
-    it('should take data from App.supports', function () {
-      expect(view.get('supports')).to.eql(viewSupports);
-    });
-  });
-
-  describe('#doSave', function () {
-
-    before(function () {
-      sinon.stub(Ember, 'set', function (p, v) {
-        if (p.indexOf('App.supports.' != -1)) {
-          p = p.replace('App.supports.', '');
-          saveObject[p] = v;
-          return;
-        }
-        return Ember.set(p, v);
-      });
-      sinon.stub(App.router, 'transitionTo', Em.K);
-    });
-
-    after(function () {
-      Em.set.restore();
-      App.router.transitionTo.restore();
-    });
-
-    it('should pass data to App.supports', function () {
-      view.set('supports', viewSupports);
-      view.doSave();
-      expect(saveObject).to.eql(supports);
-    });
-
-  });
-
-});