Ver Fonte

AMBARI-2555. Security Wizard: Create separate page for principal/keytab. (Andrii Tkach via yusaku)

git-svn-id: https://svn.apache.org/repos/asf/incubator/ambari/trunk@1499803 13f79535-47bb-0310-9956-ffa450edef68
Yusaku Sako há 12 anos atrás
pai
commit
01404348d8

+ 1 - 0
ambari-web/app/controllers.js

@@ -40,6 +40,7 @@ require('controllers/main/admin/security/add/addSecurity_controller');
 require('controllers/main/admin/security/add/step1');
 require('controllers/main/admin/security/add/step1');
 require('controllers/main/admin/security/add/step2');
 require('controllers/main/admin/security/add/step2');
 require('controllers/main/admin/security/add/step3');
 require('controllers/main/admin/security/add/step3');
+require('controllers/main/admin/security/add/step4');
 require('controllers/main/admin/authentication');
 require('controllers/main/admin/authentication');
 require('controllers/main/service');
 require('controllers/main/service');
 require('controllers/main/service/item');
 require('controllers/main/service/item');

+ 5 - 1
ambari-web/app/controllers/main/admin/security/add/addSecurity_controller.js

@@ -22,7 +22,7 @@ App.AddSecurityController = App.WizardController.extend({
   name: 'addSecurityController',
   name: 'addSecurityController',
   securityEnabled: false,
   securityEnabled: false,
 
 
-  totalSteps: 3,
+  totalSteps: 4,
 
 
   content: Em.Object.create({
   content: Em.Object.create({
     services: [],
     services: [],
@@ -36,6 +36,7 @@ App.AddSecurityController = App.WizardController.extend({
   loadAllPriorSteps: function () {
   loadAllPriorSteps: function () {
     var step = this.get('currentStep');
     var step = this.get('currentStep');
     switch (step) {
     switch (step) {
+      case '4':
       case '3':
       case '3':
       case '2':
       case '2':
         this.loadServiceConfigs();
         this.loadServiceConfigs();
@@ -100,6 +101,9 @@ App.AddSecurityController = App.WizardController.extend({
           serviceName: _configProperties.get('serviceName'),
           serviceName: _configProperties.get('serviceName'),
           domain:  _configProperties.get('domain'),
           domain:  _configProperties.get('domain'),
           filename: _configProperties.get('filename'),
           filename: _configProperties.get('filename'),
+          unit: _configProperties.get('unit'),
+          components: _configProperties.get('components'),
+          component: _configProperties.get('component'),
           overrides: overridesArray
           overrides: overridesArray
         };
         };
         serviceConfigProperties.push(configProperty);
         serviceConfigProperties.push(configProperty);

+ 2 - 251
ambari-web/app/controllers/main/admin/security/add/step2.js

@@ -199,263 +199,14 @@ App.MainAdminSecurityAddStep2Controller = Em.Controller.extend({
     this.setHostsToConfig(zooKeeperService, 'zookeeperserver_hosts', 'ZOOKEEPER_SERVER');
     this.setHostsToConfig(zooKeeperService, 'zookeeperserver_hosts', 'ZOOKEEPER_SERVER');
   },
   },
 
 
-  showHostPrincipalKeytabList: function(){
-    App.ModalPopup.show({
-      self: this,
-      header: Em.I18n.t('admin.security.step2.popup.header'),
-      primary: Em.I18n.t('common.proceed'),
-      downloadCsv: Em.I18n.t('admin.security.step2.popup.downloadCSV'),
-      classNames: ['sixty-percent-width-modal'],
-      csvContent: [],
-      onDownloadCsv: function(){
-        var blob = new Blob([this.get('csvContent')], {type: "text/csv;charset=utf-8"});
-        saveAs(blob, "host-principal-keytab-list.csv");
-      },
-      onPrimary: function(){
-        this.hide();
-        App.router.send('next');
-      },
-      buildCsvContent: function(data){
-        this.set('csvContent', stringUtils.arrayToCSV(data));
-      },
-      bodyClass: Em.View.extend({
-        componentsToDisplay: ['NAMENODE', 'SECONDARY_NAMENODE', 'DATANODE', 'JOBTRACKER', 'ZOOKEEPER_SERVER', 'HIVE_SERVER', 'TASKTRACKER',
-        'OOZIE_SERVER', 'NAGIOS_SERVER', 'HBASE_MASTER', 'HBASE_REGIONSERVER'],
-        hostComponents: function(){
-          var componentsToDisplay = this.get('componentsToDisplay');
-          var configs = this.get('parentView.self.stepConfigs');
-          var hosts = App.Host.find();
-          var result = [];
-          hosts.forEach(function(host){
-            host.get('hostComponents').forEach(function(hostComponent){
-              if(componentsToDisplay.contains(hostComponent.get('componentName'))){
-                var serviceConfigs = configs.findProperty('serviceName', hostComponent.get('service.serviceName')).get('configs');
-                var principal, keytab;
-                serviceConfigs.forEach(function(config){
-                  if (config.get('component') && config.get('component') === hostComponent.get('componentName')) {
-                    if (config.get('name').substr(-15, 15) === '_principal_name') {
-                      principal = config.get('value').replace('_HOST', host.get('hostName')) + config.get('unit');
-                    } else if (config.get('name').substr(-7, 7) === '_keytab' || config.get('name').substr(-12, 12) === '_keytab_path') {
-                      keytab = config.get('value');
-                    }
-                  } else if (config.get('components') && config.get('components').contains(hostComponent.get('componentName'))) {
-                    if (config.get('name').substr(-15, 15) === '_principal_name') {
-                      principal = config.get('value').replace('_HOST', host.get('hostName')) + config.get('unit');
-                    } else if (config.get('name').substr(-7, 7) === '_keytab' || config.get('name').substr(-12, 12) === '_keytab_path') {
-                      keytab = config.get('value');
-                    }
-                  }
-                });
-
-                result.push({
-                  host: host.get('hostName'),
-                  component: hostComponent.get('displayName'),
-                  principal: principal,
-                  keytab: keytab
-                });
-              }
-            });
-          });
-          this.get('parentView').buildCsvContent(result);
-          return result;
-        }.property(),
-        template: Em.Handlebars.compile([
-          '<div class="alert alert-info">{{t admin.security.step2.popup.notice}}</div>',
-          '<div class="long-popup-list">',
-            '<table class="table table-bordered table-striped">',
-            '<thead>',
-              '<tr>',
-                '<th>{{t common.host}}</th>',
-                '<th>{{t common.component}}</th>',
-                '<th>{{t admin.security.step2.popup.table.principal}}</th>',
-                '<th>{{t admin.security.step2.popup.table.keytab}}</th>',
-              '</tr>',
-            '</thead>',
-            '<tbody>',
-            '{{#each hostComponent in view.hostComponents}}',
-              '<tr>',
-                '<td>{{hostComponent.host}}</td>',
-                '<td>{{hostComponent.component}}</td>',
-                '<td>{{hostComponent.principal}}</td>',
-                '<td>{{hostComponent.keytab}}</td>',
-              '</tr>',
-            '{{/each}}',
-            '</tbody>',
-            '</table>',
-          '</div>'
-        ].join(''))
-      }),
-      footerClass: Em.View.extend({
-        classNames: ['modal-footer'],
-        template: Em.Handlebars.compile([
-          '{{#if view.parentView.downloadCsv}}<a class="btn btn-info" {{action onDownloadCsv target="view.parentView"}}>{{view.parentView.downloadCsv}}</a>&nbsp;{{/if}}',
-          '{{#if view.parentView.secondary}}<a class="btn" {{action onSecondary target="view.parentView"}}>{{view.parentView.secondary}}</a>&nbsp;{{/if}}',
-          '{{#if view.parentView.primary}}<a class="btn btn-success" {{action onPrimary target="view.parentView"}}>{{view.parentView.primary}}</a>{{/if}}'
-        ].join(''))
-      })
-    });
-  },
-
   /**
   /**
    *  submit and move to step3
    *  submit and move to step3
    */
    */
 
 
   submit: function () {
   submit: function () {
     if (!this.get('isSubmitDisabled')) {
     if (!this.get('isSubmitDisabled')) {
-      if (App.supports.secureClusterProceedPopup) {
-        this.showHostPrincipalKeytabList();
-      } else {
-        App.router.send('next');
-      }
+      App.router.send('next');
     }
     }
-  },
+  }
 
 
-  doDownloadCsv: function(){
-      var blob = new Blob([this.buildCvsContent()], {type: "text/csv;charset=utf-8"});
-      saveAs(blob, "host-principal-keytab-list.csv");
-    },
-    
-    buildCvsContent: function() {
-      var configs = this.get('stepConfigs');
-      var hosts = App.Host.find();
-      var result = [];
-      var componentsToDisplay = ['NAMENODE', 'SECONDARY_NAMENODE', 'DATANODE', 'JOBTRACKER', 'ZOOKEEPER_SERVER', 'HIVE_SERVER', 'TASKTRACKER',
-                                 'OOZIE_SERVER', 'NAGIOS_SERVER', 'HBASE_MASTER', 'HBASE_REGIONSERVER'];
-      var securityUsers = App.router.get('mainAdminSecurityController').get('serviceUsers');
-      if (!securityUsers || securityUsers.length < 1) { // Page could be refreshed in middle
-        if (App.testMode) {
-          securityUsers.pushObject({id: 'puppet var', name: 'hdfs_user', value: 'hdfs'});
-          securityUsers.pushObject({id: 'puppet var', name: 'mapred_user', value: 'mapred'});
-          securityUsers.pushObject({id: 'puppet var', name: 'hbase_user', value: 'hbase'});
-          securityUsers.pushObject({id: 'puppet var', name: 'hive_user', value: 'hive'});
-          securityUsers.pushObject({id: 'puppet var', name: 'smokeuser', value: 'ambari-qa'});
-        } else {
-          App.router.get('mainAdminSecurityController').setSecurityStatus();
-          securityUsers = App.router.get('mainAdminSecurityController').get('serviceUsers');
-        }
-      }
-      var isHbaseInstalled = App.Service.find().findProperty('serviceName', 'HBASE');
-      var generalConfigs = configs.findProperty('serviceName', 'GENERAL').configs;
-      var realm = generalConfigs.findProperty('name', 'kerberos_domain').get('value');
-      var smokeUserId = securityUsers.findProperty('name', 'smokeuser').value;
-      var hdfsUserId = securityUsers.findProperty('name', 'hdfs_user').value;
-      var hbaseUserId = securityUsers.findProperty('name', 'hbase_user').value;
-      var mapredUserId = securityUsers.findProperty('name', 'mapred_user').value;
-      var hiveUserId = securityUsers.findProperty('name', 'hive_user').value;
-      var zkUserId = securityUsers.findProperty('name', 'zk_user').value;
-      var oozieUserId = securityUsers.findProperty('name', 'oozie_user').value;
-      var nagiosUserId = securityUsers.findProperty('name', 'nagios_user').value;
-      var hadoopGroupId = securityUsers.findProperty('name', 'user_group').value;
-      
-      var smokeUser = smokeUserId + '@' + realm;
-      var hdfsUser = hdfsUserId + '@' + realm;
-      var hbaseUser = hbaseUserId + '@' + realm;
-      var smokeUserKeytabPath = generalConfigs.findProperty('name', 'smokeuser_keytab').get('value');
-      var hdfsUserKeytabPath = generalConfigs.findProperty('name', 'keytab_path').get('value') + "/hdfs.headless.keytab";
-      var hbaseUserKeytabPath = generalConfigs.findProperty('name', 'keytab_path').get('value') + "/hbase.headless.keytab";
-      var httpPrincipal = generalConfigs.findProperty('name', 'hadoop_http_principal_name');
-      var httpKeytabPath = generalConfigs.findProperty('name', 'hadoop_http_keytab').get('value');
-      var componentToOwnerMap = {
-          'NAMENODE': hdfsUserId,
-          'SECONDARY_NAMENODE': hdfsUserId,
-          'DATANODE': hdfsUserId,
-          'TASKTRACKER': mapredUserId,
-          'JOBTRACKER': mapredUserId,
-          'ZOOKEEPER_SERVER': zkUserId,
-          'HIVE_SERVER': hiveUserId,
-          'OOZIE_SERVER': oozieUserId,
-          'NAGIOS_SERVER': nagiosUserId,
-          'HBASE_MASTER': hbaseUserId,
-          'HBASE_REGIONSERVER': hbaseUserId
-      };
-      
-      var addedPrincipalsHost = {}; //Keys = host_principal, Value = 'true'
-      
-      hosts.forEach(function(host){
-        result.push({
-          host: host.get('hostName'),
-          component: Em.I18n.t('admin.addSecurity.user.smokeUser'),
-          principal: smokeUser,
-          keytab: smokeUserKeytabPath,
-          owner: smokeUserId,
-          group: hadoopGroupId,
-          acl: '440'
-        });
-        result.push({
-          host: host.get('hostName'),
-          component: Em.I18n.t('admin.addSecurity.user.hdfsUser'),
-          principal: hdfsUser,
-          keytab: hdfsUserKeytabPath,
-          owner: hdfsUserId,
-          group: hadoopGroupId,
-          acl: '440'
-        });
-        if (isHbaseInstalled) {
-          result.push({
-            host: host.get('hostName'),
-            component: Em.I18n.t('admin.addSecurity.user.hbaseUser'),
-            principal: hbaseUser,
-            keytab: hbaseUserKeytabPath,
-            owner: hbaseUserId,
-            group: hadoopGroupId,
-            acl: '440'
-          });
-        }
-        if(host.get('hostComponents').someProperty('componentName', 'NAMENODE') || 
-          host.get('hostComponents').someProperty('componentName', 'SECONDARY_NAMENODE') ||
-          host.get('hostComponents').someProperty('componentName', 'WEBHCAT_SERVER') ||
-          host.get('hostComponents').someProperty('componentName', 'OOZIE_SERVER')){
-          result.push({
-            host: host.get('hostName'),
-            component: Em.I18n.t('admin.addSecurity.user.httpUser'),
-            principal: httpPrincipal.get('value').replace('_HOST', host.get('hostName')) + httpPrincipal.get('unit'),
-            keytab: httpKeytabPath,
-            owner: 'root',
-            group: hadoopGroupId,
-            acl: '440'
-          });
-        }
-        host.get('hostComponents').forEach(function(hostComponent){
-          if(componentsToDisplay.contains(hostComponent.get('componentName'))){
-            var serviceConfigs = configs.findProperty('serviceName', hostComponent.get('service.serviceName')).get('configs');
-            var principal, keytab;
-            serviceConfigs.forEach(function(config){
-              if (config.get('component') && config.get('component') === hostComponent.get('componentName')) {
-                if (config.get('name').endsWith('_principal_name')) {
-                  principal = config.get('value').replace('_HOST', host.get('hostName')) + config.get('unit');
-                } else if (config.get('name').endsWith('_keytab') || config.get('name').endsWith('_keytab_path')) {
-                  keytab = config.get('value');
-                }
-              } else if (config.get('components') && config.get('components').contains(hostComponent.get('componentName'))) {
-                if (config.get('name').endsWith('_principal_name')) {
-                  principal = config.get('value').replace('_HOST', host.get('hostName')) + config.get('unit');
-                } else if (config.get('name').endsWith('_keytab') || config.get('name').endsWith('_keytab_path')) {
-                  keytab = config.get('value');
-                }
-              }
-            });
-            
-   
-            var key = host.get('hostName') + "--" + principal;
-            if (!addedPrincipalsHost[key]) {
-              var owner = componentToOwnerMap[hostComponent.get('componentName')];
-              if(!owner){
-                owner = '';
-              }
-              result.push({
-                host: host.get('hostName'),
-                component: hostComponent.get('displayName'),
-                principal: principal,
-                keytab: keytab,
-                owner: owner,
-                group: hadoopGroupId,
-                acl: '400'
-              });
-              addedPrincipalsHost[key] = true;
-            }
-          }
-        });
-      });
-      return stringUtils.arrayToCSV(result);
-    }
 });
 });

+ 142 - 599
ambari-web/app/controllers/main/admin/security/add/step3.js

@@ -17,617 +17,160 @@
  */
  */
 
 
 var App = require('app');
 var App = require('app');
-App.MainAdminSecurityAddStep3Controller = Em.Controller.extend({
+var stringUtils = require('utils/string_utils');
 
 
+App.MainAdminSecurityAddStep3Controller = Em.Controller.extend({
   name: 'mainAdminSecurityAddStep3Controller',
   name: 'mainAdminSecurityAddStep3Controller',
-  secureMapping: require('data/secure_mapping'),
-  secureProperties: require('data/secure_properties').configProperties,
-  stages: [],
-  configs: [],
-  noOfWaitingAjaxCalls: 0,
-  secureServices: [],
-  serviceConfigTags: [],
-  globalProperties: [],
-
-  isSubmitDisabled: true,
-  isBackBtnDisabled: function () {
-    return !this.get('stages').someProperty('isError', true);
-  }.property('stages.@each.isCompleted'),
-
-  isOozieSelected: function () {
-    return this.get('content.services').someProperty('serviceName', 'OOZIE');
-  }.property('content.services'),
-
-  isHiveSelected: function () {
-    return this.get('content.services').someProperty('serviceName', 'HIVE');
-  }.property('content.services'),
-
-  isNagiosSelected: function () {
-    return this.get('content.services').someProperty('serviceName', 'NAGIOS');
-  }.property('content.services'),
-
-  isZkSelected: function () {
-    return this.get('content.services').someProperty('serviceName', 'ZOOKEEPER');
-  }.property('content.services'),
-
-  isWebHcatSelected: function () {
-    var installedServices = App.Service.find().mapProperty('serviceName');
-    return installedServices.contains('WEBHCAT');
-  },
-
-  serviceUsersBinding: 'App.router.mainAdminSecurityController.serviceUsers',
-  hasHostPopup: true,
-  services: [],
-  serviceTimestamp: null,
-
-  isSecurityApplied: function () {
-    return this.get('stages').someProperty('stage', 'stage3') && this.get('stages').findProperty('stage', 'stage3').get('isSuccess');
-  }.property('stages.@each.isCompleted'),
-
-  clearStep: function () {
-    this.get('stages').clear();
-    this.set('isSubmitDisabled', true);
-    this.set('isBackBtnDisabled', true);
-    this.get('serviceConfigTags').clear();
-  },
-
-  retry: function () {
-    if (this.get('stages').someProperty('isError', true)) {
-      var failedStages = this.get('stages').filterProperty('isError', true);
-      failedStages.setEach('isError', false);
-      failedStages.setEach('isSuccess', false);
-      failedStages.setEach('isStarted', false);
-    }
-    this.moveToNextStage();
-  },
-
-  loadStep: function () {
-    this.set('secureMapping', require('data/secure_mapping').slice(0));
-    this.clearStep();
-    var stages = App.db.getSecurityDeployStages();
-    this.prepareSecureConfigs();
-    if (stages && stages.length > 0) {
-      stages.forEach(function (_stage, index) {
-        stages[index] = App.Poll.create(_stage);
-      }, this);
-      if (stages.someProperty('isError', true)) {
-        this.get('stages').pushObjects(stages);
-        return;
-      } else if (stages.filterProperty('isStarted', true).someProperty('isCompleted', false)) {
-        var runningStage = stages.filterProperty('isStarted', true).findProperty('isCompleted', false);
-        runningStage.set('isStarted', false);
-        this.get('stages').pushObjects(stages);
+  hostComponents: [],
+  doDownloadCsv: function(){
+    var blob = new Blob([stringUtils.arrayToCSV(this.get('hostComponents'))], {type: "text/csv;charset=utf-8"});
+    saveAs(blob, "host-principal-keytab-list.csv");
+  },
+  loadStep: function(){
+    var configs = this.get('content.serviceConfigProperties');
+    var hosts = App.Host.find();
+    var result = [];
+    var componentsToDisplay = ['NAMENODE', 'SECONDARY_NAMENODE', 'DATANODE', 'JOBTRACKER', 'ZOOKEEPER_SERVER', 'HIVE_SERVER', 'TASKTRACKER',
+      'OOZIE_SERVER', 'NAGIOS_SERVER', 'HBASE_MASTER', 'HBASE_REGIONSERVER'];
+    var securityUsers = [];
+    if (!securityUsers || securityUsers.length < 1) { // Page could be refreshed in middle
+      if (App.testMode) {
+        securityUsers.pushObject({id: 'puppet var', name: 'hdfs_user', value: 'hdfs'});
+        securityUsers.pushObject({id: 'puppet var', name: 'mapred_user', value: 'mapred'});
+        securityUsers.pushObject({id: 'puppet var', name: 'hbase_user', value: 'hbase'});
+        securityUsers.pushObject({id: 'puppet var', name: 'hive_user', value: 'hive'});
+        securityUsers.pushObject({id: 'puppet var', name: 'smokeuser', value: 'ambari-qa'});
+        securityUsers.pushObject({id: 'puppet var', name: 'zk_user', value: 'zookeeper'});
+        securityUsers.pushObject({id: 'puppet var', name: 'oozie_user', value: 'oozie'});
+        securityUsers.pushObject({id: 'puppet var', name: 'nagios_user', value: 'nagios'});
+        securityUsers.pushObject({id: 'puppet var', name: 'user_group', value: 'hadoop'});
       } else {
       } else {
-        this.get('stages').pushObjects(stages);
-      }
-    } else {
-      this.loadStages();
-      this.addInfoToStages();
-      var runningOperations = App.router.get('backgroundOperationsController.services').filterProperty('isRunning');
-      var stopAllOperation = runningOperations.findProperty('name', 'Stop All Services');
-      var stopStage = this.get('stages').findProperty('name', 'STOP_SERVICES');
-      if (stopStage.get('name') === 'STOP_SERVICES' && stopAllOperation) {
-        stopStage.set('requestId', stopAllOperation.get('id'));
-      }
-    }
-    this.moveToNextStage();
-  },
-
-  enableSubmit: function () {
-    var addSecurityController = App.router.get('addSecurityController');
-    if (this.get('stages').someProperty('isError', true) || this.get('stages').everyProperty('isSuccess', true)) {
-      this.set('isSubmitDisabled', false);
-      if (this.get('stages').someProperty('isError', true)) {
-        addSecurityController.setStepsEnable();
-      }
-    } else {
-      this.set('isSubmitDisabled', true);
-      addSecurityController.setLowerStepsDisable(3);
-    }
-  }.observes('stages.@each.isCompleted'),
+        App.router.get('mainAdminSecurityController').setSecurityStatus();
+        securityUsers = App.router.get('mainAdminSecurityController').get('serviceUsers');
+      }
+    }
+    var isHbaseInstalled = App.Service.find().findProperty('serviceName', 'HBASE');
+    var generalConfigs = configs.filterProperty('serviceName', 'GENERAL');
+    var realm = generalConfigs.findProperty('name', 'kerberos_domain').value;
+    var smokeUserId = securityUsers.findProperty('name', 'smokeuser').value;
+    var hdfsUserId = securityUsers.findProperty('name', 'hdfs_user').value;
+    var hbaseUserId = securityUsers.findProperty('name', 'hbase_user').value;
+    var mapredUserId = securityUsers.findProperty('name', 'mapred_user').value;
+    var hiveUserId = securityUsers.findProperty('name', 'hive_user').value;
+    var zkUserId = securityUsers.findProperty('name', 'zk_user').value;
+    var oozieUserId = securityUsers.findProperty('name', 'oozie_user').value;
+    var nagiosUserId = securityUsers.findProperty('name', 'nagios_user').value;
+    var hadoopGroupId = securityUsers.findProperty('name', 'user_group').value;
+
+    var smokeUser = smokeUserId + '@' + realm;
+    var hdfsUser = hdfsUserId + '@' + realm;
+    var hbaseUser = hbaseUserId + '@' + realm;
+    var smokeUserKeytabPath = generalConfigs.findProperty('name', 'smokeuser_keytab').value;
+    var hdfsUserKeytabPath = generalConfigs.findProperty('name', 'keytab_path').value + "/hdfs.headless.keytab";
+    var hbaseUserKeytabPath = generalConfigs.findProperty('name', 'keytab_path').value + "/hbase.headless.keytab";
+    var httpPrincipal = generalConfigs.findProperty('name', 'hadoop_http_principal_name');
+    var httpKeytabPath = generalConfigs.findProperty('name', 'hadoop_http_keytab').value;
+    var componentToOwnerMap = {
+      'NAMENODE': hdfsUserId,
+      'SECONDARY_NAMENODE': hdfsUserId,
+      'DATANODE': hdfsUserId,
+      'TASKTRACKER': mapredUserId,
+      'JOBTRACKER': mapredUserId,
+      'ZOOKEEPER_SERVER': zkUserId,
+      'HIVE_SERVER': hiveUserId,
+      'OOZIE_SERVER': oozieUserId,
+      'NAGIOS_SERVER': nagiosUserId,
+      'HBASE_MASTER': hbaseUserId,
+      'HBASE_REGIONSERVER': hbaseUserId
+    };
 
 
-  updateServices: function () {
-    this.services.clear();
-    var services = this.get("services");
-    this.get("stages").forEach(function (stage) {
-      var newService = Ember.Object.create({
-        name: stage.label,
-        hosts: []
+    var addedPrincipalsHost = {}; //Keys = host_principal, Value = 'true'
+
+    hosts.forEach(function(host){
+      result.push({
+        host: host.get('hostName'),
+        component: Em.I18n.t('admin.addSecurity.user.smokeUser'),
+        principal: smokeUser,
+        keytab: smokeUserKeytabPath,
+        owner: smokeUserId,
+        group: hadoopGroupId,
+        acl: '440'
       });
       });
-      if (stage && stage.get("polledData")) {
-        var hostNames = stage.get("polledData").mapProperty('Tasks.host_name').uniq();
-        hostNames.forEach(function (name) {
-          newService.hosts.push({
-            name: name,
-            publicName: name,
-            logTasks: stage.polledData.filterProperty("Tasks.host_name", name)
-          });
-        });
-        services.push(newService);
-      }
-    });
-    this.set('serviceTimestamp', new Date().getTime());
-  }.observes('stages.@each.polledData'),
-
-  loadStages: function () {
-    this.get('stages').pushObjects([
-      App.Poll.create({stage: 'stage2', label: Em.I18n.translations['admin.addSecurity.apply.stage2'], isPolling: true, name: 'STOP_SERVICES'}),
-      App.Poll.create({stage: 'stage3', label: Em.I18n.translations['admin.addSecurity.apply.stage3'], isPolling: false, name: 'APPLY_CONFIGURATIONS'}),
-      App.Poll.create({stage: 'stage4', label: Em.I18n.translations['admin.addSecurity.apply.stage4'], isPolling: true, name: 'START_SERVICES'})
-    ]);
-  },
-
-  startStage: function () {
-    var startedStages = this.get('stages').filterProperty('isStarted', true);
-    if (startedStages.length) {
-      var currentStage = startedStages.findProperty('isCompleted', false);
-      if (currentStage && currentStage.get('isPolling') === true) {
-        currentStage.start();
-      } else if (currentStage && currentStage.get('stage') === 'stage3') {
-        if (App.testMode) {
-          currentStage.set('isSuccess', true);
-          App.router.get('mainAdminSecurityController').setAddSecurityWizardStatus(null);
-        } else {
-          this.loadClusterConfigs()
-        }
-      }
-    }
-  }.observes('stages.@each.isStarted'),
-
-  onCompleteStage: function () {
-    var index = this.get('stages').filterProperty('isCompleted', true).length;
-    if (index > 0) {
-      var lastCompletedStageResult = this.get('stages').objectAt(index - 1).get('isSuccess');
-      if (lastCompletedStageResult) {
-        this.moveToNextStage();
-      }
-    }
-  }.observes('stages.@each.isCompleted'),
-
-  moveToNextStage: function () {
-    var leftStages = this.get('stages').filterProperty('isStarted', false);
-    var nextStage = leftStages.findProperty('isCompleted', false);
-    if (nextStage) {
-      nextStage.set('isStarted', true);
-    }
-  },
-
-  addInfoToStages: function () {
-    this.addInfoToStage2();
-    this.addInfoToStage4();
-  },
-
-  addInfoToStage1: function () {
-    var stage1 = this.get('stages').findProperty('stage', 'stage1');
-    if (App.testMode) {
-      stage1.set('isSuccess', true);
-      stage1.set('isStarted', true);
-      stage1.set('isCompleted', true);
-    }
-  },
-
-  addInfoToStage2: function () {
-    var stage2 = this.get('stages').findProperty('stage', 'stage2');
-    var url = (App.testMode) ? '/data/wizard/deploy/2_hosts/poll_1.json' : App.apiPrefix + '/clusters/' + App.router.getClusterName() + '/services';
-    var data = '{"RequestInfo": {"context" :"' + Em.I18n.t('requestInfo.stopAllServices') + '"}, "Body": {"ServiceInfo": {"state": "INSTALLED"}}}';
-    stage2.set('url', url);
-    stage2.set('data', data);
-  },
-
-  addInfoToStage4: function () {
-    var stage4 = this.get('stages').findProperty('stage', 'stage4');
-    var url = (App.testMode) ? '/data/wizard/deploy/2_hosts/poll_1.json' : App.apiPrefix + '/clusters/' + App.router.getClusterName() + '/services?params/run_smoke_test=true';
-    var data = '{"RequestInfo": {"context": "' + Em.I18n.t('requestInfo.startAllServices') + '"}, "Body": {"ServiceInfo": {"state": "STARTED"}}}';
-    stage4.set('url', url);
-    stage4.set('data', data);
-  },
-
-  loadUiSideConfigs: function () {
-    var uiConfig = [];
-    var configs = this.get('secureMapping').filterProperty('foreignKey', null);
-    configs.forEach(function (_config) {
-      var value = this.getGlobConfigValue(_config.templateName, _config.value, _config.name);
-      uiConfig.pushObject({
-        "id": "site property",
-        "name": _config.name,
-        "value": value,
-        "filename": _config.filename
+      result.push({
+        host: host.get('hostName'),
+        component: Em.I18n.t('admin.addSecurity.user.hdfsUser'),
+        principal: hdfsUser,
+        keytab: hdfsUserKeytabPath,
+        owner: hdfsUserId,
+        group: hadoopGroupId,
+        acl: '440'
       });
       });
-    }, this);
-    var dependentConfig = this.get('secureMapping').filterProperty('foreignKey');
-    dependentConfig.forEach(function (_config) {
-      if (App.Service.find().mapProperty('serviceName').contains(_config.serviceName)) {
-        this.setConfigValue(uiConfig, _config);
-        uiConfig.pushObject({
-          "id": "site property",
-          "name": _config._name || _config.name,
-          "value": _config.value,
-          "filename": _config.filename
+      if (isHbaseInstalled) {
+        result.push({
+          host: host.get('hostName'),
+          component: Em.I18n.t('admin.addSecurity.user.hbaseUser'),
+          principal: hbaseUser,
+          keytab: hbaseUserKeytabPath,
+          owner: hbaseUserId,
+          group: hadoopGroupId,
+          acl: '440'
         });
         });
       }
       }
-    }, this);
-    return uiConfig;
-  },
-
-  /**
-   * Set all site property that are derived from other puppet-variable
-   */
-
-  getGlobConfigValue: function (templateName, expression, name) {
-    var express = expression.match(/<(.*?)>/g);
-    var value = expression;
-    if (express == null) {
-      return expression;
-    }
-    express.forEach(function (_express) {
-      //console.log("The value of template is: " + _express);
-      var index = parseInt(_express.match(/\[([\d]*)(?=\])/)[1]);
-      var globValue = this.get('globalProperties').findProperty('name', templateName[index]);
-      if (globValue) {
-        console.log('The template value of templateName ' + '[' + index + ']' + ': ' + templateName[index] + ' is: ' + globValue);
-        if (value !== null) {   // if the property depends on more than one template name like <templateName[0]>/<templateName[1]> then don't proceed to the next if the prior is null or not found in the global configs
-          value = value.replace(_express, globValue.value);
-        }
-      } else {
-        /*
-         console.log("ERROR: The variable name is: " + templateName[index]);
-         console.log("ERROR: mapped config from secureMapping file has no corresponding variable in " +
-         "content.serviceConfigProperties. Two possible reasons for the error could be: 1) The service is not selected. " +
-         "and/OR 2) The service_config metadata file has no corresponding global var for the site property variable");
-         */
-        value = null;
+      if(host.get('hostComponents').someProperty('componentName', 'NAMENODE') ||
+        host.get('hostComponents').someProperty('componentName', 'SECONDARY_NAMENODE') ||
+        host.get('hostComponents').someProperty('componentName', 'WEBHCAT_SERVER') ||
+        host.get('hostComponents').someProperty('componentName', 'OOZIE_SERVER')){
+        result.push({
+          host: host.get('hostName'),
+          component: Em.I18n.t('admin.addSecurity.user.httpUser'),
+          principal: httpPrincipal.value.replace('_HOST', host.get('hostName')) + httpPrincipal.unit,
+          keytab: httpKeytabPath,
+          owner: 'root',
+          group: hadoopGroupId,
+          acl: '440'
+        });
       }
       }
-    }, this);
-    return value;
-  },
+      host.get('hostComponents').forEach(function(hostComponent){
+        if(componentsToDisplay.contains(hostComponent.get('componentName'))){
+          var serviceConfigs = configs.filterProperty('serviceName', hostComponent.get('service.serviceName'));
+          var principal, keytab;
+          serviceConfigs.forEach(function(config){
+            if (config.component && config.component === hostComponent.get('componentName')) {
+              if (config.name.endsWith('_principal_name')) {
+                principal = config.value.replace('_HOST', host.get('hostName')) + config.unit;
+              } else if (config.name.endsWith('_keytab') || config.name.endsWith('_keytab_path')) {
+                keytab = config.value;
+              }
+            } else if (config.components && config.components.contains(hostComponent.get('componentName'))) {
+              if (config.name.endsWith('_principal_name')) {
+                principal = config.value.replace('_HOST', host.get('hostName')) + config.unit;
+              } else if (config.name.endsWith('_keytab') || config.name.endsWith('_keytab_path')) {
+                keytab = config.value;
+              }
+            }
+          });
 
 
-  /**
-   * Set all site property that are derived from other site-properties
-   */
-  setConfigValue: function (uiConfig, config) {
-    if (config.value == null) {
-      return;
-    }
-    var fkValue = config.name.match(/<(foreignKey.*?)>/g);
-    if (fkValue) {
-      fkValue.forEach(function (_fkValue) {
-        var index = parseInt(_fkValue.match(/\[([\d]*)(?=\])/)[1]);
-        var globalValue;
-        if (uiConfig.someProperty('name', config.foreignKey[index])) {
-          globalValue = uiConfig.findProperty('name', config.foreignKey[index]).value;
-          config._name = config.name.replace(_fkValue, globalValue);
-        } else if (this.get('globalProperties').someProperty('name', config.foreignKey[index])) {
-          globalValue = this.get('globalProperties').findProperty('name', config.foreignKey[index]).value;
-          config._name = config.name.replace(_fkValue, globalValue);
-        }
-      }, this);
-    }
-    //For properties in the configMapping file having foreignKey and templateName properties.
 
 
-    var templateValue = config.value.match(/<(templateName.*?)>/g);
-    if (templateValue) {
-      templateValue.forEach(function (_value) {
-        var index = parseInt(_value.match(/\[([\d]*)(?=\])/)[1]);
-        var globValue = this.get('globalProperties').findProperty('name', config.templateName[index]);
-        if (globValue) {
-          config.value = config.value.replace(_value, globValue.value);
-        } else {
-          config.value = null;
+          var key = host.get('hostName') + "--" + principal;
+          if (!addedPrincipalsHost[key]) {
+            var owner = componentToOwnerMap[hostComponent.get('componentName')];
+            if(!owner){
+              owner = '';
+            }
+            result.push({
+              host: host.get('hostName'),
+              component: hostComponent.get('displayName'),
+              principal: principal,
+              keytab: keytab,
+              owner: owner,
+              group: hadoopGroupId,
+              acl: '400'
+            });
+            addedPrincipalsHost[key] = true;
+          }
         }
         }
-      }, this);
-    }
-  },
-
-  prepareSecureConfigs: function () {
-    this.loadGlobals();
-    var storedConfigs = this.get('content.serviceConfigProperties').filterProperty('id', 'site property');
-    var uiConfigs = this.loadUiSideConfigs();
-    this.set('configs', storedConfigs.concat(uiConfigs));
-  },
-
-  loadGlobals: function () {
-    var globals = this.get('content.serviceConfigProperties').filterProperty('id', 'puppet var');
-    this.set('globalProperties', globals);
-    this.loadStaticGlobal(); //Hack for properties which are declared in config_properties.js and not able to retrieve values declared in secure_properties.js
-    this.loadUsersToGlobal();
-    this.loadHostNamesToGlobal();
-    this.loadPrimaryNamesToGlobals();
-  },
-
-  loadUsersToGlobal: function () {
-    if (!this.get('serviceUsers').length) {
-      this.loadUsersFromServer();
-    }
-    App.router.get('mainAdminSecurityController.serviceUsers').forEach(function (_user) {
-      this.get('globalProperties').pushObject(_user);
-    }, this);
-  },
-
-  loadHostNamesToGlobal: function () {
-    var oozieHostComponent = App.Service.find('OOZIE').get('hostComponents').findProperty('componentName', 'OOZIE_SERVER');
-    if (this.get('isOozieSelected') && oozieHostComponent) {
-      var oozieHostName = oozieHostComponent.get('host.hostName');
-      this.get('globalProperties').pushObject({
-        id: 'puppet var',
-        name: 'oozieserver_host',
-        value: oozieHostName
       });
       });
-    }
-    var hiveHostComponent = App.Service.find('HIVE').get('hostComponents').findProperty('componentName', 'HIVE_METASTORE');
-    if (this.get('isHiveSelected') && hiveHostComponent) {
-      var hiveHostName = hiveHostComponent.get('host.hostName');
-      this.get('globalProperties').pushObject({
-        id: 'puppet var',
-        name: 'hivemetastore_host',
-        value: hiveHostName
-      });
-    }
-    var webHcatComponent = App.Service.find('WEBHCAT').get('hostComponents').findProperty('componentName', 'WEBHCAT_SERVER');
-    if (this.isWebHcatSelected() && webHcatComponent) {
-      var webHcatHostName = webHcatComponent.get('host.hostName');
-      this.get('globalProperties').pushObject({
-        id: 'puppet var',
-        name: 'webhcat_server',
-        value: webHcatHostName
-      });
-    }
-  },
-
-  loadStaticGlobal: function () {
-    var globalProperties = this.get('globalProperties');
-    this.get('globalProperties').forEach(function (_property) {
-      switch (_property.name) {
-        case 'security_enabled':
-          _property.value = 'true';
-          break;
-        case 'dfs_datanode_address':
-          _property.value = '1019';
-          break;
-        case 'dfs_datanode_http_address':
-          _property.value = '1022';
-          break;
-      }
-    }, this);
-  },
-
-  loadPrimaryNamesToGlobals: function () {
-    var principalProperties = this.getPrincipalNames();
-    principalProperties.forEach(function (_principalProperty) {
-      var name = _principalProperty.name.replace('principal', 'primary');
-      var value = _principalProperty.value.split('/')[0];
-      this.get('globalProperties').pushObject({name: name, value: value});
-    }, this);
-  },
-
-  getPrincipalNames: function () {
-    var principalNames = [];
-    var allPrincipalNames = [];
-    this.get('globalProperties').forEach(function (_globalProperty) {
-      if (/principal_name?$/.test(_globalProperty.name)) {
-        principalNames.pushObject(_globalProperty);
-      }
-    }, this);
-    this.get('secureProperties').forEach(function (_secureProperty) {
-      if (/principal_name?$/.test(_secureProperty.name)) {
-        var principalName = principalNames.findProperty('name', _secureProperty.name);
-        if (!principalName) {
-          _secureProperty.value = _secureProperty.defaultValue;
-          principalNames.pushObject(_secureProperty);
-        }
-      }
-    }, this);
-    return principalNames;
-  },
-
-  loadUsersFromServer: function () {
-    if (App.testMode) {
-      var serviceUsers = this.get('serviceUsers');
-      serviceUsers.pushObject({id: 'puppet var', name: 'hdfs_user', value: 'hdfs'});
-      serviceUsers.pushObject({id: 'puppet var', name: 'mapred_user', value: 'mapred'});
-      serviceUsers.pushObject({id: 'puppet var', name: 'hbase_user', value: 'hbase'});
-      serviceUsers.pushObject({id: 'puppet var', name: 'hive_user', value: 'hive'});
-    } else {
-      App.router.get('mainAdminSecurityController').setSecurityStatus();
-    }
-  },
-
-
-  loadClusterConfigs: function () {
-    var self = this;
-    var url = App.apiPrefix + '/clusters/' + App.router.getClusterName();
-
-    App.ajax.send({
-      name: 'admin.security.add.cluster_configs',
-      sender: this,
-      success: 'loadClusterConfigsSuccessCallback',
-      error: 'loadClusterConfigsErrorCallback'
-    });
-  },
-
-  loadClusterConfigsSuccessCallback: function (data) {
-    var self = this;
-    //prepare tags to fetch all configuration for a service
-    this.get('content.services').forEach(function (_secureService) {
-      self.setServiceTagNames(_secureService, data.Clusters.desired_configs);
     });
     });
-    this.getAllConfigurations();
-  },
-
-  loadClusterConfigsErrorCallback: function (request, ajaxOptions, error) {
-    var stage3 = this.get('stages').findProperty('stage', 'stage3');
-    if (stage3) {
-      stage3.set('isSuccess', false);
-      stage3.set('isError', true);
-    }
-    console.log("TRACE: error code status is: " + request.status);
-  },
-
-  /**
-   * set tagnames for configuration of the *-site.xml
-   */
-  setServiceTagNames: function (secureService, configs) {
-    //var serviceConfigTags = this.get('serviceConfigTags');
-    for (var index in configs) {
-      if (secureService.sites && secureService.sites.contains(index)) {
-        var serviceConfigObj = {
-          siteName: index,
-          tagName: configs[index].tag,
-          newTagName: null,
-          configs: {}
-        };
-        console.log("The value of serviceConfigTags[index]: " + configs[index]);
-        this.get('serviceConfigTags').pushObject(serviceConfigObj);
-      }
-    }
-    return serviceConfigObj;
-  },
-
-  applyConfigurationsToCluster: function () {
-    this.set('noOfWaitingAjaxCalls', this.get('serviceConfigTags').length);
-    this.get('serviceConfigTags').forEach(function (_serviceConfig) {
-      this.applyConfigurationToCluster({type: _serviceConfig.siteName, tag: _serviceConfig.newTagName, properties: _serviceConfig.configs});
-    }, this);
-  },
-
-  applyConfigurationToCluster: function (data) {
-    var clusterData = {
-      Clusters: {
-        desired_config: data
-      }
-    };
-    App.ajax.send({
-      name: 'admin.security.apply_configuration',
-      sender: this,
-      data: {
-        clusterData: clusterData
-      },
-      success: 'applyConfigurationToClusterSuccessCallback',
-      error: 'applyConfigurationToClusterErrorCallback'
-    });
-  },
-
-  applyConfigurationToClusterSuccessCallback: function (data) {
-    this.set('noOfWaitingAjaxCalls', this.get('noOfWaitingAjaxCalls') - 1);
-    if (this.get('noOfWaitingAjaxCalls') == 0) {
-      var currentStage = this.get('stages').findProperty('stage', 'stage3');
-      currentStage.set('isSuccess', true);
-      currentStage.set('isError', false);
-    }
-  },
-
-  applyConfigurationToClusterErrorCallback: function (request, ajaxOptions, error) {
-    var stage3 = this.get('stages').findProperty('stage', 'stage3');
-    if (stage3) {
-      stage3.set('isSuccess', false);
-      stage3.set('isError', true);
-    }
-  },
-
-  /**
-   * gets site config properties from server and sets it for every configuration
-   * @param serviceConfigTags
-   */
-
-  getAllConfigurations: function () {
-    var urlParams = [];
-    this.get('serviceConfigTags').forEach(function (_tag) {
-      urlParams.push('(type=' + _tag.siteName + '&tag=' + _tag.tagName + ')');
-    }, this);
-    if (urlParams.length > 0) {
-      App.ajax.send({
-        name: 'admin.security.all_configurations',
-        sender: this,
-        data: {
-          urlParams: urlParams.join('|')
-        },
-        success: 'getAllConfigurationsSuccessCallback',
-        error: 'getAllConfigurationsErrorCallback'
-      });
-    }
-  },
-
-  getAllConfigurationsSuccessCallback: function (data) {
-    console.log("TRACE: In success function for the GET getServiceConfigsFromServer call");
-    var stage3 = this.get('stages').findProperty('stage', 'stage3');
-    this.get('serviceConfigTags').forEach(function (_tag) {
-      if (!data.items.someProperty('type', _tag.siteName)) {
-        console.log("Error: Metadata for secure services (secure_configs.js) is having config tags that are not being retrieved from server");
-        if (stage3) {
-          stage3.set('isSuccess', false);
-          stage3.set('isError', true);
-        }
-      }
-      _tag.configs = data.items.findProperty('type', _tag.siteName).properties;
-    }, this);
-    this.addSecureConfigs();
-    this.applyConfigurationsToCluster();
-  },
-
-  getAllConfigurationsErrorCallback: function (request, ajaxOptions, error) {
-    var stage3 = this.get('stages').findProperty('stage', 'stage3');
-    if (stage3) {
-      stage3.set('isSuccess', false);
-      stage3.set('isError', true);
-    }
-    console.log("TRACE: In error function for the getServiceConfigsFromServer call");
-    console.log("TRACE: error code status is: " + request.status);
-  },
-
-  addSecureConfigs: function () {
-    this.get('serviceConfigTags').forEach(function (_serviceConfigTags) {
-      _serviceConfigTags.newTagName = 'version' + (new Date).getTime();
-      if (_serviceConfigTags.siteName === 'global') {
-        var realmName = this.get('globalProperties').findProperty('name', 'kerberos_domain');
-        if (this.get('isNagiosSelected')) {
-          var nagiosPrincipalName = this.get('globalProperties').findProperty('name', 'nagios_principal_name');
-          nagiosPrincipalName.value = nagiosPrincipalName.value + '@' + realmName.value;
-        }
-        if (this.get('isZkSelected')) {
-          var zkPrincipalName = this.get('globalProperties').findProperty('name', 'zookeeper_principal_name');
-          zkPrincipalName.value = zkPrincipalName.value + '@' + realmName.value;
-        }
-        this.get('globalProperties').forEach(function (_globalProperty) {
-          if (!/_hosts?$/.test(_globalProperty.name)) {
-            _serviceConfigTags.configs[_globalProperty.name] = _globalProperty.value;
-          }
-        }, this);
-      }
-      else {
-        this.get('configs').filterProperty('id', 'site property').filterProperty('filename', _serviceConfigTags.siteName + '.xml').forEach(function (_config) {
-          _serviceConfigTags.configs[_config.name] = _config.value;
-        }, this);
-      }
-    }, this);
-  },
-
-  saveStages: function () {
-    var stages = [];
-    if (this.get('stages').length === 3) {
-      this.get('stages').forEach(function (_stage) {
-        var stage = {
-          name: _stage.get('name'),
-          stage: _stage.get('stage'),
-          label: _stage.get('label'),
-          isPolling: _stage.get('isPolling'),
-          isStarted: _stage.get('isStarted'),
-          requestId: _stage.get('requestId'),
-          isSuccess: _stage.get('isSuccess'),
-          isError: _stage.get('isError'),
-          url: _stage.get('url'),
-          polledData: _stage.get('polledData'),
-          data: _stage.get('data')
-        };
-        stages.pushObject(stage);
-      }, this);
-      App.db.setSecurityDeployStages(stages);
-      if (!App.testMode) {
-        App.clusterStatus.setClusterStatus({
-          clusterName: this.get('clusterName'),
-          clusterState: 'ADD_SECURITY_STEP_3',
-          wizardControllerName: App.router.get('addSecurityController.name'),
-          localdb: App.db.data.AddSecurity
-        });
-      }
-    }
-  }.observes('stages.@each.requestId')
+    this.set('hostComponents', result);
+  }
 });
 });

+ 597 - 0
ambari-web/app/controllers/main/admin/security/add/step4.js

@@ -0,0 +1,597 @@
+/**
+ * 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.MainAdminSecurityAddStep4Controller = Em.Controller.extend({
+
+  name: 'mainAdminSecurityAddStep4Controller',
+  secureMapping: require('data/secure_mapping'),
+  secureProperties: require('data/secure_properties').configProperties,
+  stages: [],
+  configs: [],
+  noOfWaitingAjaxCalls: 0,
+  secureServices: [],
+  serviceConfigTags: [],
+  globalProperties: [],
+
+  isSubmitDisabled: true,
+  isBackBtnDisabled: true,
+
+  isOozieSelected: function () {
+    return this.get('content.services').someProperty('serviceName', 'OOZIE');
+  }.property('content.services'),
+
+  isHiveSelected: function () {
+    return this.get('content.services').someProperty('serviceName', 'HIVE');
+  }.property('content.services'),
+
+  isNagiosSelected: function () {
+    return this.get('content.services').someProperty('serviceName', 'NAGIOS');
+  }.property('content.services'),
+
+  isZkSelected: function () {
+    return this.get('content.services').someProperty('serviceName', 'ZOOKEEPER');
+  }.property('content.services'),
+
+  isWebHcatSelected: function () {
+    var installedServices = App.Service.find().mapProperty('serviceName');
+    return installedServices.contains('WEBHCAT');
+  },
+
+  serviceUsersBinding: 'App.router.mainAdminSecurityController.serviceUsers',
+  hasHostPopup: true,
+  services: [],
+  serviceTimestamp: null,
+
+  isSecurityApplied: function () {
+    return this.get('stages').someProperty('stage', 'stage3') && this.get('stages').findProperty('stage', 'stage3').get('isSuccess');
+  }.property('stages.@each.isCompleted'),
+
+  clearStep: function () {
+    this.get('stages').clear();
+    this.set('isSubmitDisabled', true);
+    this.set('isBackBtnDisabled', true);
+    this.get('serviceConfigTags').clear();
+  },
+
+  loadStep: function () {
+    this.set('secureMapping', require('data/secure_mapping').slice(0));
+    var stages = App.db.getSecurityDeployStages();
+    this.clearStep();
+    this.prepareSecureConfigs();
+    if (stages && stages.length > 0) {
+      stages.forEach(function (_stage, index) {
+        stages[index] = App.Poll.create(_stage);
+      }, this);
+      var stopServices = stages.findProperty('name', 'STOP_SERVICES');
+      var runningOperation = App.router.get('backgroundOperationsController.services').findProperty('isRunning');
+      if(stopServices.get('isStarted')){
+        if(stopServices.get('isCompleted') || !runningOperation || !(runningOperation.get('name') === 'Stop All Services')){
+          stopServices.set('requestId', undefined);
+          stopServices.set('isError', false);
+          stopServices.set('isSuccess', false);
+          stopServices.set('isStarted', false);
+        }
+      }
+      if (stages.someProperty('isError', true)) {
+        var failedStages = stages.filterProperty('isError', true);
+        failedStages.setEach('isError', false);
+        failedStages.setEach('isStarted', false);
+      } else if (stages.filterProperty('isStarted', true).someProperty('isCompleted', false)) {
+        var runningStage = stages.filterProperty('isStarted', true).findProperty('isCompleted', false);
+        runningStage.set('isStarted', false);
+      }
+      this.get('stages').pushObjects(stages);
+    } else {
+      this.loadStages();
+      this.addInfoToStages();
+      var runningOperations = App.router.get('backgroundOperationsController.services').filterProperty('isRunning');
+      var stopAllOperation = runningOperations.findProperty('name', 'Stop All Services');
+      var stopStage = this.get('stages').findProperty('name', 'STOP_SERVICES');
+      if (stopStage.get('name') === 'STOP_SERVICES' && stopAllOperation) {
+        stopStage.set('requestId', stopAllOperation.get('id'));
+      }
+    }
+    this.moveToNextStage();
+  },
+
+  enableSubmit: function () {
+    if (this.get('stages').someProperty('isError', true) || this.get('stages').everyProperty('isSuccess', true)) {
+      this.set('isSubmitDisabled', false);
+      if (this.get('stages').someProperty('isError', true)) {
+        this.set('isBackBtnDisabled', false);
+        App.router.get('addSecurityController').setStepsEnable();
+      }
+    } else {
+      this.set('isSubmitDisabled', true);
+    }
+  }.observes('stages.@each.isCompleted'),
+
+  updateServices: function () {
+    this.services.clear();
+    var services = this.get("services");
+    this.get("stages").forEach(function (stage) {
+      var newService = Ember.Object.create({
+        name: stage.label,
+        hosts: []
+      });
+      if (stage && stage.get("polledData")) {
+        var hostNames = stage.get("polledData").mapProperty('Tasks.host_name').uniq();
+        hostNames.forEach(function (name) {
+          newService.hosts.push({
+            name: name,
+            publicName: name,
+            logTasks: stage.polledData.filterProperty("Tasks.host_name", name)
+          });
+        });
+        services.push(newService);
+      }
+    });
+    this.set('serviceTimestamp', new Date().getTime());
+  }.observes('stages.@each.polledData'),
+
+  loadStages: function () {
+    this.get('stages').pushObjects([
+      App.Poll.create({stage: 'stage2', label: Em.I18n.translations['admin.addSecurity.apply.stage2'], isPolling: true, name: 'STOP_SERVICES'}),
+      App.Poll.create({stage: 'stage3', label: Em.I18n.translations['admin.addSecurity.apply.stage3'], isPolling: false, name: 'APPLY_CONFIGURATIONS'}),
+      App.Poll.create({stage: 'stage4', label: Em.I18n.translations['admin.addSecurity.apply.stage4'], isPolling: true, name: 'START_SERVICES'})
+    ]);
+  },
+
+  startStage: function () {
+    var startedStages = this.get('stages').filterProperty('isStarted', true);
+    if (startedStages.length) {
+      var currentStage = startedStages.findProperty('isCompleted', false);
+      if (currentStage && currentStage.get('isPolling') === true) {
+        currentStage.start();
+      } else if (currentStage && currentStage.get('stage') === 'stage3') {
+        if (App.testMode) {
+          currentStage.set('isSuccess', true);
+          App.router.get('mainAdminSecurityController').setAddSecurityWizardStatus(null);
+        } else {
+          this.loadClusterConfigs()
+        }
+      }
+    }
+  }.observes('stages.@each.isStarted'),
+
+  onCompleteStage: function () {
+    var index = this.get('stages').filterProperty('isCompleted', true).length;
+    if (index > 0) {
+      var lastCompletedStageResult = this.get('stages').objectAt(index - 1).get('isSuccess');
+      if (lastCompletedStageResult) {
+        this.moveToNextStage();
+      }
+    }
+  }.observes('stages.@each.isCompleted'),
+
+  moveToNextStage: function () {
+    var leftStages = this.get('stages').filterProperty('isStarted', false);
+    var nextStage = leftStages.findProperty('isCompleted', false);
+    if (nextStage) {
+      nextStage.set('isStarted', true);
+    }
+  },
+
+  addInfoToStages: function () {
+    this.addInfoToStage2();
+    this.addInfoToStage4();
+  },
+
+  addInfoToStage1: function () {
+    var stage1 = this.get('stages').findProperty('stage', 'stage1');
+    if (App.testMode) {
+      stage1.set('isSuccess', true);
+      stage1.set('isStarted', true);
+      stage1.set('isCompleted', true);
+    }
+  },
+
+  addInfoToStage2: function () {
+    var stage2 = this.get('stages').findProperty('stage', 'stage2');
+    var url = (App.testMode) ? '/data/wizard/deploy/2_hosts/poll_1.json' : App.apiPrefix + '/clusters/' + App.router.getClusterName() + '/services';
+    var data = '{"RequestInfo": {"context" :"' + Em.I18n.t('requestInfo.stopAllServices') + '"}, "Body": {"ServiceInfo": {"state": "INSTALLED"}}}';
+    stage2.set('url', url);
+    stage2.set('data', data);
+  },
+
+  addInfoToStage4: function () {
+    var stage4 = this.get('stages').findProperty('stage', 'stage4');
+    var url = (App.testMode) ? '/data/wizard/deploy/2_hosts/poll_1.json' : App.apiPrefix + '/clusters/' + App.router.getClusterName() + '/services?params/run_smoke_test=true';
+    var data = '{"RequestInfo": {"context": "' + Em.I18n.t('requestInfo.startAllServices') + '"}, "Body": {"ServiceInfo": {"state": "STARTED"}}}';
+    stage4.set('url', url);
+    stage4.set('data', data);
+  },
+
+  loadUiSideConfigs: function () {
+    var uiConfig = [];
+    var configs = this.get('secureMapping').filterProperty('foreignKey', null);
+    configs.forEach(function (_config) {
+      var value = this.getGlobConfigValue(_config.templateName, _config.value, _config.name);
+      uiConfig.pushObject({
+        "id": "site property",
+        "name": _config.name,
+        "value": value,
+        "filename": _config.filename
+      });
+    }, this);
+    var dependentConfig = this.get('secureMapping').filterProperty('foreignKey');
+    dependentConfig.forEach(function (_config) {
+      if (App.Service.find().mapProperty('serviceName').contains( _config.serviceName)) {
+        this.setConfigValue(uiConfig, _config);
+        uiConfig.pushObject({
+          "id": "site property",
+          "name": _config._name || _config.name,
+          "value": _config.value,
+          "filename": _config.filename
+        });
+      }
+    }, this);
+    return uiConfig;
+  },
+
+  /**
+   * Set all site property that are derived from other puppet-variable
+   */
+
+  getGlobConfigValue: function (templateName, expression, name) {
+    var express = expression.match(/<(.*?)>/g);
+    var value = expression;
+    if (express == null) {
+      return expression;
+    }
+    express.forEach(function (_express) {
+      //console.log("The value of template is: " + _express);
+      var index = parseInt(_express.match(/\[([\d]*)(?=\])/)[1]);
+      var globValue = this.get('globalProperties').findProperty('name', templateName[index]);
+      if (globValue) {
+        console.log('The template value of templateName ' + '[' + index + ']' + ': ' + templateName[index] + ' is: ' + globValue);
+        if (value !== null) {   // if the property depends on more than one template name like <templateName[0]>/<templateName[1]> then don't proceed to the next if the prior is null or not found in the global configs
+          value = value.replace(_express, globValue.value);
+        }
+      } else {
+        /*
+         console.log("ERROR: The variable name is: " + templateName[index]);
+         console.log("ERROR: mapped config from secureMapping file has no corresponding variable in " +
+         "content.serviceConfigProperties. Two possible reasons for the error could be: 1) The service is not selected. " +
+         "and/OR 2) The service_config metadata file has no corresponding global var for the site property variable");
+         */
+        value = null;
+      }
+    }, this);
+    return value;
+  },
+
+  /**
+   * Set all site property that are derived from other site-properties
+   */
+  setConfigValue: function (uiConfig, config) {
+    if (config.value == null) {
+      return;
+    }
+    var fkValue = config.name.match(/<(foreignKey.*?)>/g);
+    if (fkValue) {
+      fkValue.forEach(function (_fkValue) {
+        var index = parseInt(_fkValue.match(/\[([\d]*)(?=\])/)[1]);
+        var globalValue;
+        if (uiConfig.someProperty('name', config.foreignKey[index])) {
+          globalValue = uiConfig.findProperty('name', config.foreignKey[index]).value;
+          config._name = config.name.replace(_fkValue, globalValue);
+        } else if (this.get('globalProperties').someProperty('name', config.foreignKey[index])) {
+          globalValue = this.get('globalProperties').findProperty('name', config.foreignKey[index]).value;
+          config._name = config.name.replace(_fkValue, globalValue);
+        }
+      }, this);
+    }
+    //For properties in the configMapping file having foreignKey and templateName properties.
+
+    var templateValue = config.value.match(/<(templateName.*?)>/g);
+    if (templateValue) {
+      templateValue.forEach(function (_value) {
+        var index = parseInt(_value.match(/\[([\d]*)(?=\])/)[1]);
+        var globValue = this.get('globalProperties').findProperty('name', config.templateName[index]);
+        if (globValue) {
+          config.value = config.value.replace(_value, globValue.value);
+        } else {
+          config.value = null;
+        }
+      }, this);
+    }
+  },
+
+  prepareSecureConfigs: function () {
+    this.loadGlobals();
+    var storedConfigs = this.get('content.serviceConfigProperties').filterProperty('id', 'site property');
+    var uiConfigs = this.loadUiSideConfigs();
+    this.set('configs', storedConfigs.concat(uiConfigs));
+  },
+
+  loadGlobals: function () {
+    var globals = this.get('content.serviceConfigProperties').filterProperty('id', 'puppet var');
+    this.set('globalProperties', globals);
+    this.loadStaticGlobal(); //Hack for properties which are declared in config_properties.js and not able to retrieve values declared in secure_properties.js
+    this.loadUsersToGlobal();
+    this.loadHostNamesToGlobal();
+    this.loadPrimaryNamesToGlobals();
+  },
+
+  loadUsersToGlobal: function () {
+    if (!this.get('serviceUsers').length) {
+      this.loadUsersFromServer();
+    }
+    App.router.get('mainAdminSecurityController.serviceUsers').forEach(function (_user) {
+      this.get('globalProperties').pushObject(_user);
+    }, this);
+  },
+
+  loadHostNamesToGlobal: function () {
+    var oozieHostComponent = App.Service.find('OOZIE').get('hostComponents').findProperty('componentName', 'OOZIE_SERVER');
+    if (this.get('isOozieSelected') && oozieHostComponent) {
+      var oozieHostName = oozieHostComponent.get('host.hostName');
+      this.get('globalProperties').pushObject({
+        id: 'puppet var',
+        name: 'oozieserver_host',
+        value: oozieHostName
+      });
+    }
+    var hiveHostComponent = App.Service.find('HIVE').get('hostComponents').findProperty('componentName', 'HIVE_METASTORE');
+    if (this.get('isHiveSelected') && hiveHostComponent) {
+      var hiveHostName = hiveHostComponent.get('host.hostName');
+      this.get('globalProperties').pushObject({
+        id: 'puppet var',
+        name: 'hivemetastore_host',
+        value: hiveHostName
+      });
+    }
+  },
+
+  loadStaticGlobal: function () {
+    var globalProperties = this.get('globalProperties');
+    this.get('globalProperties').forEach(function (_property) {
+      switch (_property.name) {
+        case 'security_enabled':
+          _property.value = 'true';
+          break;
+        case 'dfs_datanode_address':
+          _property.value = '1019';
+          break;
+        case 'dfs_datanode_http_address':
+          _property.value = '1022';
+          break;
+      }
+    }, this);
+  },
+
+  loadPrimaryNamesToGlobals: function () {
+    var principalProperties = this.getPrincipalNames();
+    principalProperties.forEach(function (_principalProperty) {
+      var name = _principalProperty.name.replace('principal', 'primary');
+      var value = _principalProperty.value.split('/')[0];
+      this.get('globalProperties').pushObject({name: name, value: value});
+    }, this);
+  },
+
+  getPrincipalNames: function () {
+    var principalNames = [];
+    var allPrincipalNames = [];
+    this.get('globalProperties').forEach(function (_globalProperty) {
+      if (/principal_name?$/.test(_globalProperty.name)) {
+        principalNames.pushObject(_globalProperty);
+      }
+    }, this);
+    this.get('secureProperties').forEach(function (_secureProperty) {
+      if (/principal_name?$/.test(_secureProperty.name)) {
+        var principalName = principalNames.findProperty('name', _secureProperty.name);
+        if (!principalName) {
+          _secureProperty.value = _secureProperty.defaultValue;
+          principalNames.pushObject(_secureProperty);
+        }
+      }
+    }, this);
+    return principalNames;
+  },
+
+  loadUsersFromServer: function () {
+    if (App.testMode) {
+      var serviceUsers = this.get('serviceUsers');
+      serviceUsers.pushObject({id: 'puppet var', name: 'hdfs_user', value: 'hdfs'});
+      serviceUsers.pushObject({id: 'puppet var', name: 'mapred_user', value: 'mapred'});
+      serviceUsers.pushObject({id: 'puppet var', name: 'hbase_user', value: 'hbase'});
+      serviceUsers.pushObject({id: 'puppet var', name: 'hive_user', value: 'hive'});
+    } else {
+      App.router.get('mainAdminSecurityController').setSecurityStatus();
+    }
+  },
+
+
+  loadClusterConfigs: function () {
+    var self = this;
+    var url = App.apiPrefix + '/clusters/' + App.router.getClusterName();
+
+    App.ajax.send({
+      name: 'admin.security.add.cluster_configs',
+      sender: this,
+      success: 'loadClusterConfigsSuccessCallback',
+      error: 'loadClusterConfigsErrorCallback'
+    });
+  },
+
+  loadClusterConfigsSuccessCallback: function (data) {
+    var self = this;
+    //prepare tags to fetch all configuration for a service
+    this.get('content.services').forEach(function (_secureService) {
+      self.setServiceTagNames(_secureService, data.Clusters.desired_configs);
+    });
+    this.getAllConfigurations();
+  },
+
+  loadClusterConfigsErrorCallback: function (request, ajaxOptions, error) {
+    this.get('stages').findProperty('stage', 'stage3').set('isError', true);
+    console.log("TRACE: error code status is: " + request.status);
+  },
+
+  /**
+   * set tagnames for configuration of the *-site.xml
+   */
+  setServiceTagNames: function (secureService, configs) {
+    //var serviceConfigTags = this.get('serviceConfigTags');
+    for (var index in configs) {
+      if (secureService.sites && secureService.sites.contains(index)) {
+        var serviceConfigObj = {
+          siteName: index,
+          tagName: configs[index].tag,
+          newTagName: null,
+          configs: {}
+        };
+        console.log("The value of serviceConfigTags[index]: " + configs[index]);
+        this.get('serviceConfigTags').pushObject(serviceConfigObj);
+      }
+    }
+    return serviceConfigObj;
+  },
+
+  applyConfigurationsToCluster: function () {
+    this.set('noOfWaitingAjaxCalls', this.get('serviceConfigTags').length);
+    this.get('serviceConfigTags').forEach(function (_serviceConfig) {
+      this.applyConfigurationToCluster({type: _serviceConfig.siteName, tag: _serviceConfig.newTagName, properties: _serviceConfig.configs});
+    }, this);
+  },
+
+  applyConfigurationToCluster: function (data) {
+    var clusterData = {
+      Clusters: {
+        desired_config: data
+      }
+    };
+    App.ajax.send({
+      name: 'admin.security.apply_configuration',
+      sender: this,
+      data: {
+        clusterData: clusterData
+      },
+      success: 'applyConfigurationToClusterSuccessCallback',
+      error: 'applyConfigurationToClusterErrorCallback'
+    });
+  },
+
+  applyConfigurationToClusterSuccessCallback: function (data) {
+    this.set('noOfWaitingAjaxCalls', this.get('noOfWaitingAjaxCalls') - 1);
+    if (this.get('noOfWaitingAjaxCalls') == 0) {
+      var currentStage = this.get('stages').findProperty('stage', 'stage3');
+      currentStage.set('isSuccess', true);
+    }
+  },
+
+  applyConfigurationToClusterErrorCallback: function (request, ajaxOptions, error) {
+    this.get('stages').findProperty('stage', 'stage3').set('isError', true);
+  },
+
+  /**
+   * gets site config properties from server and sets it for every configuration
+   * @param serviceConfigTags
+   */
+
+  getAllConfigurations: function () {
+    var urlParams = [];
+    this.get('serviceConfigTags').forEach(function (_tag) {
+      urlParams.push('(type=' + _tag.siteName + '&tag=' + _tag.tagName + ')');
+    }, this);
+    if (urlParams.length > 0) {
+      App.ajax.send({
+        name: 'admin.security.all_configurations',
+        sender: this,
+        data: {
+          urlParams: urlParams.join('|')
+        },
+        success: 'getAllConfigurationsSuccessCallback',
+        error: 'getAllConfigurationsErrorCallback'
+      });
+    }
+  },
+
+  getAllConfigurationsSuccessCallback: function (data) {
+    console.log("TRACE: In success function for the GET getServiceConfigsFromServer call");
+    this.get('serviceConfigTags').forEach(function (_tag) {
+      if (!data.items.someProperty('type', _tag.siteName)) {
+        console.log("Error: Metadata for secure services (secure_configs.js) is having config tags that are not being retrieved from server");
+        this.get('stages').findProperty('stage', 'stage3').set('isError', true);
+      }
+      _tag.configs = data.items.findProperty('type', _tag.siteName).properties;
+    }, this);
+    this.addSecureConfigs();
+    this.applyConfigurationsToCluster();
+  },
+
+  getAllConfigurationsErrorCallback: function (request, ajaxOptions, error) {
+    this.get('stages').findProperty('stage', 'stage3').set('isError', true);
+    console.log("TRACE: In error function for the getServiceConfigsFromServer call");
+    console.log("TRACE: error code status is: " + request.status);
+  },
+
+  addSecureConfigs: function () {
+    this.get('serviceConfigTags').forEach(function (_serviceConfigTags) {
+      _serviceConfigTags.newTagName = 'version' + (new Date).getTime();
+      if (_serviceConfigTags.siteName === 'global') {
+        var realmName = this.get('globalProperties').findProperty('name', 'kerberos_domain');
+        if (this.get('isNagiosSelected')) {
+          var nagiosPrincipalName = this.get('globalProperties').findProperty('name', 'nagios_principal_name');
+          nagiosPrincipalName.value = nagiosPrincipalName.value + '@' + realmName.value;
+        }
+        if (this.get('isZkSelected')) {
+          var zkPrincipalName = this.get('globalProperties').findProperty('name', 'zookeeper_principal_name');
+          zkPrincipalName.value = zkPrincipalName.value + '@' + realmName.value;
+        }
+        this.get('globalProperties').forEach(function (_globalProperty) {
+          _serviceConfigTags.configs[_globalProperty.name] = _globalProperty.value;
+        }, this);
+      }
+      else {
+        this.get('configs').filterProperty('id', 'site property').filterProperty('filename', _serviceConfigTags.siteName + '.xml').forEach(function (_config) {
+          _serviceConfigTags.configs[_config.name] = _config.value;
+        }, this);
+      }
+    }, this);
+  },
+
+  saveStages: function () {
+    var stages = [];
+    this.get('stages').forEach(function (_stage) {
+      var stage = {
+        name: _stage.get('name'),
+        stage: _stage.get('stage'),
+        label: _stage.get('label'),
+        isPolling: _stage.get('isPolling'),
+        isStarted: _stage.get('isStarted'),
+        requestId: _stage.get('requestId'),
+        isSuccess: _stage.get('isSuccess'),
+        isError: _stage.get('isError'),
+        url: _stage.get('url'),
+        polledData: _stage.get('polledData'),
+        data: _stage.get('data')
+      };
+      stages.pushObject(stage);
+    }, this);
+    App.db.setSecurityDeployStages(stages);
+    App.clusterStatus.setClusterStatus({
+      clusterName: this.get('clusterName'),
+      clusterState: 'ADD_SECURITY_STEP_4',
+      wizardControllerName: App.router.get('addSecurityController.name'),
+      localdb: App.db.data
+    });
+  }.observes('stages.@each.requestId', 'stages.@each.isStarted', 'stages.@each.isCompleted')
+});

+ 11 - 11
ambari-web/app/messages.js

@@ -616,7 +616,8 @@ Em.I18n.translations = {
   'admin.addSecurity.header': 'Add security wizard',
   'admin.addSecurity.header': 'Add security wizard',
   'admin.security.step1.header': 'Get Started',
   'admin.security.step1.header': 'Get Started',
   'admin.security.step2.header': 'Configure Services',
   'admin.security.step2.header': 'Configure Services',
-  'admin.security.step3.header': 'Save and Apply Configuration',
+  'admin.security.step3.header': 'Create Principals and Keytabs',
+  'admin.security.step4.header': 'Save and Apply Configuration',
   'admin.security.step1.body.header': 'Important: Before configuring Ambari to manage your Kerberos-enabled cluster, ' +
   'admin.security.step1.body.header': 'Important: Before configuring Ambari to manage your Kerberos-enabled cluster, ' +
     'you must perform the following manual steps on your cluster. Be sure to record the location of the keytab files ' +
     'you must perform the following manual steps on your cluster. Be sure to record the location of the keytab files ' +
     'for each host and the principals for each Hadoop service. This information is required in order to use the wizard.',
     'for each host and the principals for each Hadoop service. This information is required in order to use the wizard.',
@@ -625,16 +626,15 @@ Em.I18n.translations = {
   'admin.security.step1.body.instruction3': 'Create Kerberos principals for Hadoop services and hosts',
   'admin.security.step1.body.instruction3': 'Create Kerberos principals for Hadoop services and hosts',
   'admin.security.step1.body.instruction4': 'Generate keytabs for each principal and place on the appropriate hosts',
   'admin.security.step1.body.instruction4': 'Generate keytabs for each principal and place on the appropriate hosts',
   'admin.security.step2.body.header': 'Configure Kerberos security properties',
   'admin.security.step2.body.header': 'Configure Kerberos security properties',
-  'admin.security.step2.popup.header': 'Manual Steps Required Before Proceeding',
-  'admin.security.step2.popup.notice': 'You need to create the following principals and keytabs on the hosts shown.<br />'+
-  'You can download the list as a CSV file and use it to create a script to generate the principals and keytabs.' +
-  'Once the principals and keytabs have been created, click on <i>Proceed</i> to continue. If you need to make configuration changes, click <i>Cancel</i>.',
-  'admin.security.step2.popup.table.principal': 'Principal',
-  'admin.security.step2.popup.table.keytab': 'Keytab',
-  'admin.security.step2.popup.downloadCSV': 'Download CSV',
-  'admin.security.step3.body.header': 'Applying kerberos security to the cluster',
-  'admin.security.step3.body.success.header' : 'Kerberos-based security has been enabled on your cluster. Please wait while services are started in secure mode.',
-  'admin.security.step3.body.failure.header' : 'Failed to enable Kerberos-based security on your cluster. Your cluster will keep running in non-secure mode.',
+  'admin.security.step3.notice': 'You need to create the following principals and keytabs on the hosts shown.<br />'+
+  'You can download the list as a CSV file and use it to create a script to generate the principals and keytabs. ' +
+  'Once the principals and keytabs have been created, click on <i>Proceed</i> to continue. If you need to make configuration changes, click <i>Back</i>.',
+  'admin.security.step3.table.principal': 'Principal',
+  'admin.security.step3.table.keytab': 'Keytab',
+  'admin.security.step3.downloadCSV': 'Download CSV',
+  'admin.security.step4.body.header': 'Applying kerberos security to the cluster',
+  'admin.security.step4.body.success.header' : 'Kerberos-based security has been enabled on your cluster. Please wait while services are started in secure mode.',
+  'admin.security.step4.body.failure.header' : 'Failed to enable Kerberos-based security on your cluster. Your cluster will keep running in non-secure mode.',
   'admin.security.disable.body.header' : 'Disabling kerberos security on the cluster',
   'admin.security.disable.body.header' : 'Disabling kerberos security on the cluster',
   'admin.security.disable.body.success.header': 'Kerberos-based security has been disabled on your cluster. Please wait while services are started in non-secure mode.',
   'admin.security.disable.body.success.header': 'Kerberos-based security has been disabled on your cluster. Please wait while services are started in non-secure mode.',
   'admin.security.disable.body.failure.header': 'Failed to disable Kerberos-based security on your cluster. Your cluster will keep running in secure mode.',
   'admin.security.disable.body.failure.header': 'Failed to disable Kerberos-based security on your cluster. Your cluster will keep running in secure mode.',

+ 3 - 3
ambari-web/app/models/cluster_states.js

@@ -22,8 +22,8 @@ App.clusterStatus = Ember.Object.create({
   validStates: ['CLUSTER_NOT_CREATED_1', 'CLUSTER_DEPLOY_PREP_2', 'CLUSTER_INSTALLING_3', 'SERVICE_STARTING_3', 'CLUSTER_INSTALLED_4',  'CLUSTER_STARTED_5',
   validStates: ['CLUSTER_NOT_CREATED_1', 'CLUSTER_DEPLOY_PREP_2', 'CLUSTER_INSTALLING_3', 'SERVICE_STARTING_3', 'CLUSTER_INSTALLED_4',  'CLUSTER_STARTED_5',
     'ADD_HOSTS_DEPLOY_PREP_2', 'ADD_HOSTS_INSTALLING_3', 'ADD_HOSTS_INSTALLED_4', 'ADD_HOSTS_COMPLETED_5',
     'ADD_HOSTS_DEPLOY_PREP_2', 'ADD_HOSTS_INSTALLING_3', 'ADD_HOSTS_INSTALLED_4', 'ADD_HOSTS_COMPLETED_5',
     'ADD_SERVICES_DEPLOY_PREP_2', 'ADD_SERVICES_INSTALLING_3', 'ADD_SERVICES_INSTALLED_4', 'ADD_SERVICES_COMPLETED_5',
     'ADD_SERVICES_DEPLOY_PREP_2', 'ADD_SERVICES_INSTALLING_3', 'ADD_SERVICES_INSTALLED_4', 'ADD_SERVICES_COMPLETED_5',
-    'STOPPING_SERVICES', 'STACK_UPGRADING', 'STACK_UPGRADE_FAILED', 'STACK_UPGRADED', 'STACK_UPGRADE_COMPLETED','ADD_SECURITY_STEP_1',
-    'ADD_SECURITY_STEP_2','ADD_SECURITY_STEP_3','DISABLE_SECURITY','SECURITY_COMPLETED'],
+    'STOPPING_SERVICES', 'STACK_UPGRADING', 'STACK_UPGRADE_FAILED', 'STACK_UPGRADED', 'STACK_UPGRADE_COMPLETED', 'ADD_SECURITY_STEP_1',
+    'ADD_SECURITY_STEP_2', 'ADD_SECURITY_STEP_3', 'ADD_SECURITY_STEP_4', 'DISABLE_SECURITY', 'SECURITY_COMPLETED'],
   clusterState: 'CLUSTER_NOT_CREATED_1',
   clusterState: 'CLUSTER_NOT_CREATED_1',
   wizardControllerName: null,
   wizardControllerName: null,
   localdb: null,
   localdb: null,
@@ -129,4 +129,4 @@ App.clusterStatus = Ember.Object.create({
       };
       };
   }.property('clusterName', 'clusterState', 'localdb', 'wizardControllerName')
   }.property('clusterName', 'clusterState', 'localdb', 'wizardControllerName')
 
 
-});
+});

+ 55 - 15
ambari-web/app/routes/add_security.js

@@ -41,13 +41,14 @@ module.exports = Em.Route.extend({
 
 
             onClose: function () {
             onClose: function () {
               var self = this;
               var self = this;
-              if (router.get('addSecurityController.currentStep') == 3) {
-                var controller = router.get('mainAdminSecurityAddStep3Controller');
+              if (router.get('addSecurityController.currentStep') == 4) {
+                var controller = router.get('mainAdminSecurityAddStep4Controller');
                 if (!controller.get('isSubmitDisabled')) {
                 if (!controller.get('isSubmitDisabled')) {
+                  router.get('mainAdminSecurityAddStep4Controller').clearStep();
                   self.proceedOnClose();
                   self.proceedOnClose();
                   return;
                   return;
                 }
                 }
-                var applyingConfigStage = router.get('mainAdminSecurityAddStep3Controller.stages').findProperty('stage', 'stage3');
+                var applyingConfigStage = router.get('mainAdminSecurityAddStep4Controller.stages').findProperty('stage', 'stage3');
                 if (applyingConfigStage) {
                 if (applyingConfigStage) {
                   if (!applyingConfigStage.get('isCompleted')) {
                   if (!applyingConfigStage.get('isCompleted')) {
                     if (applyingConfigStage.get('isStarted')) {
                     if (applyingConfigStage.get('isStarted')) {
@@ -67,13 +68,13 @@ module.exports = Em.Route.extend({
                   return;
                   return;
                 }
                 }
               }
               }
-              router.get('mainAdminSecurityAddStep3Controller').clearStep();
+              router.get('mainAdminSecurityAddStep4Controller').clearStep();
               App.db.setSecurityDeployStages(undefined);
               App.db.setSecurityDeployStages(undefined);
               self.proceedOnClose();
               self.proceedOnClose();
             },
             },
             proceedOnClose: function () {
             proceedOnClose: function () {
               this.hide();
               this.hide();
-              router.get('mainAdminSecurityAddStep3Controller').clearStep();
+              router.get('mainAdminSecurityAddStep4Controller').clearStep();
               router.get('addSecurityController.content.services').clear();
               router.get('addSecurityController.content.services').clear();
               router.set('addSecurityController.content.serviceConfigProperties', null);
               router.set('addSecurityController.content.serviceConfigProperties', null);
               App.router.get('updateController').set('isWorking', true);
               App.router.get('updateController').set('isWorking', true);
@@ -84,7 +85,7 @@ module.exports = Em.Route.extend({
                 clusterName: router.get('content.cluster.name'),
                 clusterName: router.get('content.cluster.name'),
                 clusterState: 'SECURITY_COMPLETED',
                 clusterState: 'SECURITY_COMPLETED',
                 wizardControllerName: router.get('addSecurityController.name'),
                 wizardControllerName: router.get('addSecurityController.name'),
-                localdb: App.db.data.AddSecurity
+                localdb: App.db.data
               });
               });
               router.transitionTo('adminSecurity.index');
               router.transitionTo('adminSecurity.index');
             },
             },
@@ -110,7 +111,7 @@ module.exports = Em.Route.extend({
           clusterName: this.get('clusterName'),
           clusterName: this.get('clusterName'),
           clusterState: 'ADD_SECURITY_STEP_1',
           clusterState: 'ADD_SECURITY_STEP_1',
           wizardControllerName: router.get('addSecurityController.name'),
           wizardControllerName: router.get('addSecurityController.name'),
-          localdb:  App.db.data.AddSecurity
+          localdb: App.db.data
         });
         });
       }
       }
     },
     },
@@ -141,7 +142,7 @@ module.exports = Em.Route.extend({
           clusterName: this.get('clusterName'),
           clusterName: this.get('clusterName'),
           clusterState: 'ADD_SECURITY_STEP_2',
           clusterState: 'ADD_SECURITY_STEP_2',
           wizardControllerName: router.get('addSecurityController.name'),
           wizardControllerName: router.get('addSecurityController.name'),
-          localdb:  App.db.data.AddSecurity
+          localdb: App.db.data
         });
         });
       }
       }
     },
     },
@@ -164,29 +165,66 @@ module.exports = Em.Route.extend({
   }),
   }),
 
 
   step3: Em.Route.extend({
   step3: Em.Route.extend({
-    route: '/apply',
+    route: '/principal_keytab',
 
 
+    enter: function (router) {
+      router.get('addSecurityController').setCurrentStep('3');
+      if(!App.testMode){
+        App.clusterStatus.setClusterStatus({
+          clusterName: this.get('clusterName'),
+          clusterState: 'ADD_SECURITY_STEP_3',
+          wizardControllerName: router.get('addSecurityController.name'),
+          localdb: App.db.data
+        });
+      }
+    },
     connectOutlets: function (router) {
     connectOutlets: function (router) {
       console.log('in addSecurity.step3:connectOutlets');
       console.log('in addSecurity.step3:connectOutlets');
       var controller = router.get('addSecurityController');
       var controller = router.get('addSecurityController');
       controller.dataLoading().done(function () {
       controller.dataLoading().done(function () {
-        controller.setCurrentStep('3');
         controller.loadAllPriorSteps();
         controller.loadAllPriorSteps();
-        controller.setLowerStepsDisable(3);
         controller.connectOutlet('mainAdminSecurityAddStep3', controller.get('content'));
         controller.connectOutlet('mainAdminSecurityAddStep3', controller.get('content'));
       })
       })
     },
     },
+    back: Em.Router.transitionTo('step2'),
+    next: Em.Router.transitionTo('step4')
+  }),
+
+  step4: Em.Route.extend({
+    route: '/apply',
+
+    enter: function (router) {
+      router.get('addSecurityController').setCurrentStep('4');
+      if(!App.testMode){
+        App.clusterStatus.setClusterStatus({
+          clusterName: this.get('clusterName'),
+          clusterState: 'ADD_SECURITY_STEP_4',
+          wizardControllerName: router.get('addSecurityController.name'),
+          localdb: App.db.data
+        });
+      }
+    },
+
+    connectOutlets: function (router) {
+      console.log('in addSecurity.step4:connectOutlets');
+      var controller = router.get('addSecurityController');
+      controller.dataLoading().done(function () {
+        controller.loadAllPriorSteps();
+        controller.setLowerStepsDisable(4);
+        controller.connectOutlet('mainAdminSecurityAddStep4', controller.get('content'));
+      })
+    },
     unroutePath: function () {
     unroutePath: function () {
       return false;
       return false;
     },
     },
     back: function (router, context) {
     back: function (router, context) {
-      var controller = router.get('mainAdminSecurityAddStep3Controller');
+      var controller = router.get('mainAdminSecurityAddStep4Controller');
       if (!controller.get('isBackBtnDisabled')) {
       if (!controller.get('isBackBtnDisabled')) {
-        router.transitionTo('step2');
+        router.transitionTo('step3');
       }
       }
     },
     },
     done: function (router, context) {
     done: function (router, context) {
-      var controller = router.get('mainAdminSecurityAddStep3Controller');
+      var controller = router.get('mainAdminSecurityAddStep4Controller');
       if (!controller.get('isSubmitDisabled')) {
       if (!controller.get('isSubmitDisabled')) {
         $(context.currentTarget).parents("#modal").find(".close").trigger('click');
         $(context.currentTarget).parents("#modal").find(".close").trigger('click');
       }
       }
@@ -197,7 +235,9 @@ module.exports = Em.Route.extend({
 
 
   gotoStep2: Em.Router.transitionTo('step2'),
   gotoStep2: Em.Router.transitionTo('step2'),
 
 
-  gotoStep3: Em.Router.transitionTo('step3')
+  gotoStep3: Em.Router.transitionTo('step3'),
+
+  gotoStep4: Em.Router.transitionTo('step4')
 
 
 });
 });
 
 

+ 15 - 9
ambari-web/app/styles/application.less

@@ -1572,7 +1572,22 @@ width:100%;
   .progress-percentage {
   .progress-percentage {
     margin-left: 10px;
     margin-left: 10px;
   }
   }
+  a.remove-link {
+    text-decoration:none;
+    pointer-events: none;
+    color:black;
+    cursor: default;
+  }
+}
 
 
+#enable_security {
+  .step3 {
+    overflow: auto;
+    max-height: 500px;
+    table td {
+      word-break: break-all;
+    }
+  }
 }
 }
 
 
 .faintText {
 .faintText {
@@ -4382,15 +4397,6 @@ i.icon-asterisks {
   }
   }
 }
 }
 
 
-#security-stages {
-  a.remove-link {
-    text-decoration:none;
-    pointer-events: none;
-    color:black;
-    cursor: default;
-  }
-}
-
 #advancedRepoAccordion{
 #advancedRepoAccordion{
   #collapseOne{
   #collapseOne{
     .pull-right{
     .pull-right{

+ 2 - 1
ambari-web/app/templates/main/admin/security/add/menu.hbs

@@ -17,7 +17,7 @@
 }}
 }}
 
 
 
 
-<div class="wizard">
+<div class="wizard" id="enable_security">
     <div class="container">
     <div class="container">
         <div class="container-fluid">
         <div class="container-fluid">
             <div class="row-fluid">
             <div class="row-fluid">
@@ -29,6 +29,7 @@
                             <li {{bindAttr class="isStep1:active view.isStep1Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep1 target="controller"}}>{{t admin.security.step1.header}}</a></li>
                             <li {{bindAttr class="isStep1:active view.isStep1Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep1 target="controller"}}>{{t admin.security.step1.header}}</a></li>
                             <li {{bindAttr class="isStep2:active view.isStep2Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep2 target="controller"}}>{{t admin.security.step2.header}}</a></li>
                             <li {{bindAttr class="isStep2:active view.isStep2Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep2 target="controller"}}>{{t admin.security.step2.header}}</a></li>
                             <li {{bindAttr class="isStep3:active view.isStep3Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep3 target="controller"}}>{{t admin.security.step3.header}}</a></li>
                             <li {{bindAttr class="isStep3:active view.isStep3Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep3 target="controller"}}>{{t admin.security.step3.header}}</a></li>
+                            <li {{bindAttr class="isStep4:active view.isStep4Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep4 target="controller"}}>{{t admin.security.step4.header}}</a></li>
                         </ul>
                         </ul>
                     </div>
                     </div>
                 </div>
                 </div>

+ 2 - 3
ambari-web/app/templates/main/admin/security/add/step2.hbs

@@ -16,9 +16,9 @@
 * limitations under the License.
 * limitations under the License.
 }}
 }}
 
 
-<div id="serviceConfig">
-  <h2>{{t admin.security.step2.header}}</h2>
+<h2>{{t admin.security.step2.header}}</h2>
 
 
+<div id="serviceConfig">
   <p class="alert alert-info">
   <p class="alert alert-info">
     {{t admin.security.step2.body.header}}
     {{t admin.security.step2.body.header}}
   </p>
   </p>
@@ -29,6 +29,5 @@
 
 
     <a class="btn btn-success pull-right" {{bindAttr disabled="isSubmitDisabled"}}
     <a class="btn btn-success pull-right" {{bindAttr disabled="isSubmitDisabled"}}
       {{action submit target="controller"}}>{{t common.apply}} &rarr;</a>
       {{action submit target="controller"}}>{{t common.apply}} &rarr;</a>
-    <a style="margin-right:5px;" class="btn btn-info pull-right" {{action doDownloadCsv target="controller"}}>{{t admin.security.step2.popup.downloadCSV}}</a>
   </div>
   </div>
 </div>
 </div>

+ 28 - 11
ambari-web/app/templates/main/admin/security/add/step3.hbs

@@ -17,16 +17,33 @@
 }}
 }}
 
 
 <h2>{{t admin.security.step3.header}}</h2>
 <h2>{{t admin.security.step3.header}}</h2>
-
-{{#if view.message}}
-  <p {{bindAttr class="view.msgColor :alert"}}>{{view.message}}</p>
-{{/if}}
-
-{{view App.MainServiceReconfigureView}}
-
+<div class="alert alert-info">{{t admin.security.step3.notice}}</div>
+<div class="step3">
+    <table class="table table-bordered table-striped">
+        <thead>
+        <tr>
+            <th>{{t common.host}}</th>
+            <th>{{t common.component}}</th>
+            <th>{{t admin.security.step3.table.principal}}</th>
+            <th>{{t admin.security.step3.table.keytab}}</th>
+            </tr>
+        </thead>
+        <tbody>
+        {{#each hostComponent in hostComponents}}
+            <tr>
+                <td>{{hostComponent.host}}</td>
+                <td>{{hostComponent.component}}</td>
+                <td>{{hostComponent.principal}}</td>
+                <td>{{hostComponent.keytab}}</td>
+            </tr>
+        {{/each}}
+    </tbody>
+    </table>
+</div>
 <div class="btn-area">
 <div class="btn-area">
-  <a class="btn" {{bindAttr disabled="isBackBtnDisabled"}}
-    {{action back}}>&larr; {{t common.back}}</a>
-  <a class="btn btn-success pull-right" {{bindAttr disabled="isSubmitDisabled"}}
-    {{action done}}>{{t common.done}} </a>
+    <a class="btn" {{action back}}>&larr; {{t common.back}}</a>
+    <div class="pull-right">
+        <a class="btn btn-info" {{action doDownloadCsv target="controller"}}>{{t admin.security.step3.downloadCSV}}</a>
+        <a class="btn btn-success" {{bindAttr disabled="isSubmitDisabled"}} {{action next}}>{{t common.proceed}} &rarr;</a>
+    </div>
 </div>
 </div>

+ 32 - 0
ambari-web/app/templates/main/admin/security/add/step4.hbs

@@ -0,0 +1,32 @@
+{{!
+* 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.
+}}
+
+<h2>{{t admin.security.step4.header}}</h2>
+
+{{#if view.message}}
+  <p {{bindAttr class="view.msgColor :alert"}}>{{view.message}}</p>
+{{/if}}
+
+{{view App.MainServiceReconfigureView}}
+
+<div class="btn-area">
+  <a class="btn" {{bindAttr disabled="isBackBtnDisabled"}}
+    {{action back}}>&larr; {{t common.back}}</a>
+  <a class="btn btn-success pull-right" {{bindAttr disabled="isSubmitDisabled"}}
+    {{action done}}>{{t common.done}} </a>
+</div>

+ 1 - 0
ambari-web/app/views.js

@@ -71,6 +71,7 @@ require('views/main/admin/security/add/menu');
 require('views/main/admin/security/add/step1');
 require('views/main/admin/security/add/step1');
 require('views/main/admin/security/add/step2');
 require('views/main/admin/security/add/step2');
 require('views/main/admin/security/add/step3');
 require('views/main/admin/security/add/step3');
+require('views/main/admin/security/add/step4');
 require('views/main/dashboard');
 require('views/main/dashboard');
 require('views/main/dashboard/service');
 require('views/main/dashboard/service');
 require('views/main/dashboard/service/hdfs');
 require('views/main/dashboard/service/hdfs');

+ 4 - 0
ambari-web/app/views/main/admin/security/add/menu.js

@@ -32,6 +32,10 @@ App.MainAdminSecurityAddMenuView = Em.View.extend({
 
 
   isStep3Disabled: function () {
   isStep3Disabled: function () {
     return this.get('controller.isStepDisabled').findProperty('step',3).get('value');
     return this.get('controller.isStepDisabled').findProperty('step',3).get('value');
+  }.property('controller.isStepDisabled.@each.value').cacheable(),
+
+  isStep4Disabled: function () {
+    return this.get('controller.isStepDisabled').findProperty('step',4).get('value');
   }.property('controller.isStepDisabled.@each.value').cacheable()
   }.property('controller.isStepDisabled.@each.value').cacheable()
 
 
 });
 });

+ 2 - 49
ambari-web/app/views/main/admin/security/add/step3.js

@@ -19,56 +19,9 @@
 var App = require('app');
 var App = require('app');
 
 
 App.MainAdminSecurityAddStep3View = Em.View.extend({
 App.MainAdminSecurityAddStep3View = Em.View.extend({
-
   templateName: require('templates/main/admin/security/add/step3'),
   templateName: require('templates/main/admin/security/add/step3'),
-  didInsertElement: function () {
+  didInsertElement: function(){
     this.get('controller').loadStep();
     this.get('controller').loadStep();
-  },
-  msgColor: 'alert-info',
-  message: Em.I18n.t('admin.security.step3.body.header'),
-  onResult: function () {
-    var stage1 = this.get('controller.stages').findProperty('stage', 'stage2');
-    var stage2 = this.get('controller.stages').findProperty('stage', 'stage3');
-    var stage3 = this.get('controller.stages').findProperty('stage', 'stage4');
-      if (stage2 && stage2.get('isSuccess') === true ) {
-        this.set('message', Em.I18n.t('admin.security.step3.body.success.header'));
-        this.set('msgColor','alert-success');
-      } else if ((stage1 && stage1.get('isError') === true) || (stage2 && stage2.get('isError') === true)) {
-        this.set('message', Em.I18n.t('admin.security.step3.body.failure.header'));
-        this.set('msgColor','alert-error');
-      } else {
-        this.set('message', Em.I18n.t('admin.security.step3.body.header'));
-        this.set('msgColor','alert-info');
-      }
-  }.observes('controller.stages.@each.isCompleted')
-
-});
-
-App.StageStatusView = Em.View.extend({
-  tagName: 'tr',
-  hasStarted: null,
-  classNameBindings: ['faintText']
-});
-
-App.StageSuccessView = Em.View.extend({
-  template: Ember.Handlebars.compile('<i class="icon-ok icon-large"></i> Done')
-});
-
-App.StageFailureView = Em.View.extend({
-  template: Ember.Handlebars.compile('<i class="icon-remove icon-large"></i> Failed')
-});
-
-App.StageInProgressView = Em.View.extend({
-  stage: null,
-  classNames: ['progress-striped', 'active', 'progress'],
-  template: Ember.Handlebars.compile([
-    '<div class="bar" {{bindAttr style="stage.barWidth"}}>',
-    '</div>'
-  ].join('\n')),
-
-  isStageCompleted: function () {
-    return this.get('obj.progress') == 100 || this.get('controller.isStepCompleted');
-  }.property('controller.isStepCompleted', 'obj.progress')
-
+  }
 });
 });
 
 

+ 74 - 0
ambari-web/app/views/main/admin/security/add/step4.js

@@ -0,0 +1,74 @@
+/**
+ * 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.MainAdminSecurityAddStep4View = Em.View.extend({
+
+  templateName: require('templates/main/admin/security/add/step4'),
+  didInsertElement: function () {
+    this.get('controller').loadStep();
+  },
+  msgColor: 'alert-info',
+  message: Em.I18n.t('admin.security.step4.body.header'),
+  onResult: function () {
+    var stage1 = this.get('controller.stages').findProperty('stage', 'stage2');
+    var stage2 = this.get('controller.stages').findProperty('stage', 'stage3');
+    var stage3 = this.get('controller.stages').findProperty('stage', 'stage4');
+      if (stage2 && stage2.get('isSuccess') === true ) {
+        this.set('message', Em.I18n.t('admin.security.step4.body.success.header'));
+        this.set('msgColor','alert-success');
+      } else if ((stage1 && stage1.get('isError') === true) || (stage2 && stage2.get('isError') === true)) {
+        this.set('message', Em.I18n.t('admin.security.step4.body.failure.header'));
+        this.set('msgColor','alert-error');
+      } else {
+        this.set('message', Em.I18n.t('admin.security.step4.body.header'));
+        this.set('msgColor','alert-info');
+      }
+  }.observes('controller.stages.@each.isCompleted')
+
+});
+
+App.StageStatusView = Em.View.extend({
+  tagName: 'tr',
+  hasStarted: null,
+  classNameBindings: ['faintText']
+});
+
+App.StageSuccessView = Em.View.extend({
+  template: Ember.Handlebars.compile('<i class="icon-ok icon-large"></i> Done')
+});
+
+App.StageFailureView = Em.View.extend({
+  template: Ember.Handlebars.compile('<i class="icon-remove icon-large"></i> Failed')
+});
+
+App.StageInProgressView = Em.View.extend({
+  stage: null,
+  classNames: ['progress-striped', 'active', 'progress'],
+  template: Ember.Handlebars.compile([
+    '<div class="bar" {{bindAttr style="stage.barWidth"}}>',
+    '</div>'
+  ].join('\n')),
+
+  isStageCompleted: function () {
+    return this.get('obj.progress') == 100 || this.get('controller.isStepCompleted');
+  }.property('controller.isStepCompleted', 'obj.progress')
+
+});
+