You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by yu...@apache.org on 2013/03/14 01:27:04 UTC

svn commit: r1456292 - in /incubator/ambari/trunk: ./ ambari-web/app/ ambari-web/app/controllers/main/service/ ambari-web/app/controllers/wizard/ ambari-web/app/routes/ ambari-web/app/styles/ ambari-web/app/templates/main/service/ ambari-web/app/templa...

Author: yusaku
Date: Thu Mar 14 00:27:03 2013
New Revision: 1456292

URL: http://svn.apache.org/r1456292
Log:
AMBARI-1633. Reassign Master Wizard - Step 5. (yusaku)

Added:
    incubator/ambari/trunk/ambari-web/app/controllers/wizard/step14_controller.js
    incubator/ambari/trunk/ambari-web/app/templates/wizard/step14.hbs
    incubator/ambari/trunk/ambari-web/app/views/wizard/step14_view.js
Modified:
    incubator/ambari/trunk/CHANGES.txt
    incubator/ambari/trunk/ambari-web/app/controllers.js
    incubator/ambari/trunk/ambari-web/app/controllers/main/service/reassign_controller.js
    incubator/ambari/trunk/ambari-web/app/messages.js
    incubator/ambari/trunk/ambari-web/app/routes/reassign_master_routes.js
    incubator/ambari/trunk/ambari-web/app/styles/application.less
    incubator/ambari/trunk/ambari-web/app/templates/main/service/reassign.hbs
    incubator/ambari/trunk/ambari-web/app/views.js

Modified: incubator/ambari/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/CHANGES.txt?rev=1456292&r1=1456291&r2=1456292&view=diff
==============================================================================
--- incubator/ambari/trunk/CHANGES.txt (original)
+++ incubator/ambari/trunk/CHANGES.txt Thu Mar 14 00:27:03 2013
@@ -12,6 +12,8 @@ Trunk (unreleased changes):
 
  NEW FEATURES
 
+ AMBARI-1633. Reassign Master Wizard - Step 5. (yusaku)
+
  AMBARI-1585. Creating the agent scripts for Hue server installation and 
  configuration on the Hue host. (swagle)
 

Modified: incubator/ambari/trunk/ambari-web/app/controllers.js
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-web/app/controllers.js?rev=1456292&r1=1456291&r2=1456292&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-web/app/controllers.js (original)
+++ incubator/ambari/trunk/ambari-web/app/controllers.js Thu Mar 14 00:27:03 2013
@@ -82,6 +82,7 @@ require('controllers/wizard/step10_contr
 require('controllers/wizard/step11_controller');
 require('controllers/wizard/step12_controller');
 require('controllers/wizard/step13_controller');
+require('controllers/wizard/step14_controller');
 require('controllers/wizard/stack_upgrade/step1_controller');
 require('controllers/wizard/stack_upgrade/step2_controller');
 require('controllers/wizard/stack_upgrade/step3_controller');

Modified: incubator/ambari/trunk/ambari-web/app/controllers/main/service/reassign_controller.js
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-web/app/controllers/main/service/reassign_controller.js?rev=1456292&r1=1456291&r2=1456292&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-web/app/controllers/main/service/reassign_controller.js (original)
+++ incubator/ambari/trunk/ambari-web/app/controllers/main/service/reassign_controller.js Thu Mar 14 00:27:03 2013
@@ -210,6 +210,7 @@ App.ReassignMasterController = App.Wizar
         this.loadConfirmedHosts();
       case '1':
         this.loadComponentToReassign();
+        this.load('cluster');
     }
   },
 

Added: incubator/ambari/trunk/ambari-web/app/controllers/wizard/step14_controller.js
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-web/app/controllers/wizard/step14_controller.js?rev=1456292&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-web/app/controllers/wizard/step14_controller.js (added)
+++ incubator/ambari/trunk/ambari-web/app/controllers/wizard/step14_controller.js Thu Mar 14 00:27:03 2013
@@ -0,0 +1,793 @@
+/**
+ * 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.WizardStep14Controller = Em.Controller.extend({
+
+  status: function () {
+    if (this.get('tasks').someProperty('status', 'FAILED')) {
+      return 'FAILED';
+    }
+    if (this.get('tasks').everyProperty('status', 'COMPLETED')) {
+      return 'COMPLETED';
+    }
+    return 'IN_PROGRESS';
+  }.property('tasks.@each.status'),
+
+  tasks: [],
+
+  /**
+   * Set messages for tasks depending on their status
+   */
+  setTasksMessages: function () {
+    var service = this.get('service.displayName');
+    var master = this.get('masterComponent.display_name');
+    for (i = 0; i < this.get('tasks').length; i++) {
+      var status = this.get('tasks')[i].status.toLowerCase().replace('initialize', 'pending').replace('_', ' ');
+      if (i == 0 || i == 6) {
+        this.get('tasks')[i].set('message', Em.I18n.t('installer.step14.task' + i).format(service) + ' ' + status);
+      } else {
+        this.get('tasks')[i].set('message', Em.I18n.t('installer.step14.task' + i).format(master) + ' ' + status);
+      }
+    }
+  }.observes('tasks.@each.status'),
+
+  configs: [],
+  globals: [],
+  configMapping: require('data/config_mapping'),
+  newConfigsTag: null,
+  createdConfigs: [],
+
+  currentRequestId: null,
+
+  isSubmitDisabled: true,
+
+  service: function () {
+    return App.Service.find().findProperty('serviceName', this.get('masterComponent.service_id'));
+  }.property('masterComponent'),
+
+  masterComponent: function () {
+    return this.get('content.reassign');
+  }.property('content.reassign'),
+
+  loadStep: function () {
+    this.clearStep();
+    this.loadTasks();
+    this.navigateStep();
+  },
+
+  clearStep: function () {
+    var tasks = [];
+    for (var i = 0; i < 8; i++) {
+      tasks.pushObject(Ember.Object.create({
+        status: 'INITIALIZE',
+        logs: '',
+        message: '',
+        progress: 0
+      }));
+    }
+    this.set('tasks', tasks);
+    this.set('isSubmitDisabled', true);
+    this.get('configs').clear();
+    this.get('globals').clear();
+    this.get('createdConfigs').clear();
+  },
+
+  loadTasks: function () {
+
+  },
+
+  /**
+   * Run tasks in proper way
+   */
+  navigateStep: function () {
+    if (this.get('tasks')[0].status == 'INITIALIZE') {
+      this.stopService();
+    }
+    else if (this.get('tasks')[1].status == 'INITIALIZE') {
+      this.createMasterComponent();
+    }
+    else if (this.taskIsReady(2)) {
+      this.createConfigs();
+    }
+    else if (this.taskIsReady(3)) {
+      this.applyConfigs();
+    }
+    else if (this.taskIsReady(4)) {
+      this.putInMaintenanceMode();
+    }
+    else if (this.taskIsReady(5)) {
+      this.installComponent();
+    }
+    else if (this.taskIsReady(6)) {
+      this.startComponents();
+    }
+    else if (this.taskIsReady(7)) {
+      this.removeComponent();
+    }
+  }.observes('tasks.@each.status'),
+
+  /**
+   * Determine preparedness to run task
+   * @param task
+   * @return {Boolean}
+   */
+  taskIsReady: function (task) {
+    var startIndex = (task == 5) ? 0 : 1;
+    var tempArr = this.get('tasks').mapProperty('status').slice(startIndex, task).uniq();
+    return this.get('tasks')[task].status == 'INITIALIZE' && tempArr.length == 1 && tempArr[0] == 'COMPLETED';
+  },
+
+  /**
+   * Change status of the task
+   * @param task
+   * @param status
+   */
+  setTasksStatus: function (task, status) {
+    this.get('tasks')[task].set('status', status);
+  },
+
+  stopService: function () {
+    var self = this;
+    var clusterName = this.get('content.cluster.name');
+    var serviceName = this.get('masterComponent.service_id');
+    var url = App.apiPrefix + '/clusters/' + clusterName + '/services/' + serviceName;
+    var data = '{"ServiceInfo": {"state": "INSTALLED"}}';
+    var method = 'PUT';
+    $.ajax({
+      type: method,
+      url: url,
+      data: data,
+      dataType: 'text',
+      timeout: App.timeout,
+
+      beforeSend: function () {
+        self.setTasksStatus(0, 'PENDING');
+      },
+
+      success: function (data) {
+        if (jQuery.parseJSON(data)) {
+          self.set('currentRequestId', jQuery.parseJSON(data).Requests.id);
+          self.getLogsByRequest();
+        } else {
+          self.setTasksStatus(0, 'FAILED');
+        }
+      },
+
+      error: function () {
+        self.setTasksStatus(0, 'FAILED');
+      },
+
+      statusCode: require('data/statusCodes')
+    });
+  },
+
+  createMasterComponent: function () {
+    var self = this;
+    var clusterName = this.get('content.cluster.name');
+    var hostName = this.get('content.masterComponentHosts').findProperty('component', this.get('content.reassign.component_name')).hostName;
+    var componentName = this.get('masterComponent.component_name');
+    var url = App.apiPrefix + '/clusters/' + clusterName + '/hosts?Hosts/host_name=' + hostName;
+    var data = {
+      "host_components": [
+        {
+          "HostRoles": {
+            "component_name": componentName
+          }
+        }
+      ]
+    };
+    var method = 'POST';
+    $.ajax({
+      type: method,
+      url: url,
+      data: JSON.stringify(data),
+      dataType: 'text',
+      timeout: App.timeout,
+
+      beforeSend: function () {
+        self.setTasksStatus(1, 'PENDING');
+      },
+
+      success: function () {
+        self.setTasksStatus(1, 'COMPLETED');
+      },
+
+      error: function () {
+        self.setTasksStatus(1, 'FAILED');
+      },
+
+      statusCode: require('data/statusCodes')
+    });
+
+  },
+
+  createConfigs: function () {
+    this.loadGlobals();
+    this.loadConfigs();
+    this.set('newConfigsTag', 'version' + (new Date).getTime());
+    var serviceName = this.get('service.serviceName');
+    this.createConfigSite(this.createGlobalSiteObj());
+    this.createConfigSite(this.createCoreSiteObj());
+    if (serviceName == 'HDFS') {
+      this.createConfigSite(this.createHdfsSiteObj());
+    }
+    if (serviceName == 'MAPREDUCE') {
+      this.createConfigSite(this.createMrSiteObj());
+    }
+    if (serviceName == 'HBASE') {
+      this.createConfigSite(this.createHbaseSiteObj());
+    }
+    if (serviceName == 'OOZIE') {
+      this.createConfigSite(this.createOozieSiteObj());
+    }
+    if (serviceName == 'HIVE') {
+      this.createConfigSite(this.createHiveSiteObj());
+    }
+    if (serviceName == 'WEBHCAT') {
+      this.createConfigSite(this.createWebHCatSiteObj());
+    }
+    if (this.get('tasks')[2].status !== 'FAILED') {
+      this.setTasksStatus(2, 'COMPLETED');
+    }
+  },
+
+  createConfigSite: function (data) {
+    var self = this;
+    data.tag = this.get('newConfigsTag');
+    var clusterName = this.get('content.cluster.name');
+    var url = App.apiPrefix + '/clusters/' + clusterName + '/configurations';
+    $.ajax({
+      type: 'POST',
+      url: url,
+      data: JSON.stringify(data),
+      dataType: 'text',
+      timeout: 5000,
+
+      beforeSend: function () {
+        self.setTasksStatus(2, 'PENDING');
+      },
+
+      success: function () {
+        self.get('createdConfigs').push(data.type);
+      },
+
+      error: function () {
+        self.setTasksStatus(2, 'FAILED');
+      },
+
+      statusCode: require('data/statusCodes')
+    });
+  },
+
+  loadGlobals: function () {
+    var globals = this.get('content.serviceConfigProperties').filterProperty('id', 'puppet var');
+    if (globals.someProperty('name', 'hive_database')) {
+      //TODO: Hive host depends on the type of db selected. Change puppet variable name if postgres is not the default db
+      var hiveDb = globals.findProperty('name', 'hive_database');
+      if (hiveDb.value === 'New MySQL Database') {
+        if (globals.someProperty('name', 'hive_ambari_host')) {
+          globals.findProperty('name', 'hive_ambari_host').name = 'hive_mysql_hostname';
+        }
+        globals = globals.without(globals.findProperty('name', 'hive_existing_host'));
+        globals = globals.without(globals.findProperty('name', 'hive_existing_database'));
+      } else {
+        globals.findProperty('name', 'hive_existing_host').name = 'hive_mysql_hostname';
+        globals = globals.without(globals.findProperty('name', 'hive_ambari_host'));
+        globals = globals.without(globals.findProperty('name', 'hive_ambari_database'));
+      }
+    }
+    this.set('globals', globals);
+  },
+
+  loadConfigs: function () {
+    var storedConfigs = this.get('content.serviceConfigProperties').filterProperty('id', 'site property').filterProperty('value');
+    var uiConfigs = this.loadUiSideConfigs();
+    this.set('configs', storedConfigs.concat(uiConfigs));
+  },
+
+  loadUiSideConfigs: function () {
+    var uiConfig = [];
+    var configs = this.get('configMapping').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('configMapping').filterProperty('foreignKey');
+    dependentConfig.forEach(function (_config) {
+      this.setConfigValue(uiConfig, _config);
+      uiConfig.pushObject({
+        "id": "site property",
+        "name": _config.name,
+        "value": _config.value,
+        "filename": _config.filename
+      });
+    }, this);
+    return uiConfig;
+  },
+
+  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]);
+      if (this.get('globals').someProperty('name', templateName[index])) {
+        //console.log("The name of the variable is: " + this.get('content.serviceConfigProperties').findProperty('name', templateName[index]).name);
+        var globValue = this.get('globals').findProperty('name', templateName[index]).value;
+        // Hack for templeton.zookeeper.hosts
+        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
+          if (name === "templeton.zookeeper.hosts" || name === 'hbase.zookeeper.quorum') {
+            // globValue is an array of ZooKeeper Server hosts
+            var zooKeeperPort = '2181';
+            if (name === "templeton.zookeeper.hosts") {
+              var zooKeeperServers = globValue.map(function (item) {
+                return item + ':' + zooKeeperPort;
+              }).join(',');
+              value = value.replace(_express, zooKeeperServers);
+            } else {
+              value = value.replace(_express, globValue.join(','));
+            }
+          } else {
+            value = value.replace(_express, globValue);
+          }
+        }
+      } else {
+        /*
+         console.log("ERROR: The variable name is: " + templateName[index]);
+         console.log("ERROR: mapped config from configMapping 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.value.match(/<(foreignKey.*?)>/g);
+    if (fkValue) {
+      fkValue.forEach(function (_fkValue) {
+        var index = parseInt(_fkValue.match(/\[([\d]*)(?=\])/)[1]);
+        if (uiConfig.someProperty('name', config.foreignKey[index])) {
+          var globalValue = uiConfig.findProperty('name', config.foreignKey[index]).value;
+          config.value = config.value.replace(_fkValue, globalValue);
+        } else if (this.get('content.serviceConfigProperties').someProperty('name', config.foreignKey[index])) {
+          var globalValue;
+          if (this.get('content.serviceConfigProperties').findProperty('name', config.foreignKey[index]).value === '') {
+            globalValue = this.get('content.serviceConfigProperties').findProperty('name', config.foreignKey[index]).defaultValue;
+          } else {
+            globalValue = this.get('content.serviceConfigProperties').findProperty('name', config.foreignKey[index]).value;
+          }
+          config.value = config.value.replace(_fkValue, globalValue);
+        }
+      }, this);
+    }
+    if (fkValue = config.name.match(/<(foreignKey.*?)>/g)) {
+      fkValue.forEach(function (_fkValue) {
+        var index = parseInt(_fkValue.match(/\[([\d]*)(?=\])/)[1]);
+        if (uiConfig.someProperty('name', config.foreignKey[index])) {
+          var globalValue = uiConfig.findProperty('name', config.foreignKey[index]).value;
+          config.name = config.name.replace(_fkValue, globalValue);
+        } else if (this.get('content.serviceConfigProperties').someProperty('name', config.foreignKey[index])) {
+          var globalValue;
+          if (this.get('content.serviceConfigProperties').findProperty('name', config.foreignKey[index]).value === '') {
+            globalValue = this.get('content.serviceConfigProperties').findProperty('name', config.foreignKey[index]).defaultValue;
+          } else {
+            globalValue = this.get('content.serviceConfigProperties').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]);
+        if (this.get('globals').someProperty('name', config.templateName[index])) {
+          var globalValue = this.get('globals').findProperty('name', config.templateName[index]).value;
+          config.value = config.value.replace(_value, globalValue);
+        } else {
+          config.value = null;
+        }
+      }, this);
+    }
+  },
+
+
+  /**
+   * override site properties with the entered key-value pair in *-site.xml
+   */
+  setCustomConfigs: function () {
+    var site = this.get('content.serviceConfigProperties').filterProperty('id', 'conf-site');
+    site.forEach(function (_site) {
+      var keyValue = _site.value.split(/\n+/);
+      if (keyValue) {
+        keyValue.forEach(function (_keyValue) {
+          _keyValue = _keyValue.trim();
+          console.log("The value of the keyValue is: " + _keyValue);
+          // split on the first = encountered (the value may contain ='s)
+          var matches = _keyValue.match(/^([^=]+)=(.*)$/);
+          if (matches) {
+            var key = matches[1];
+            var value = matches[2];
+            if (key) {
+              this.setSiteProperty(key, value, _site.name + '.xml');
+            }
+          }
+        }, this);
+      }
+    }, this);
+  },
+
+  /**
+   * Set property of the site variable
+   */
+  setSiteProperty: function (key, value, filename) {
+    this.get('configs').pushObject({
+      "id": "site property",
+      "name": key,
+      "value": value,
+      "filename": filename
+    });
+  },
+
+  createGlobalSiteObj: function () {
+    var globalSiteProperties = {};
+    //this.get('globals').filterProperty('domain', 'global').forEach(function (_globalSiteObj) {
+    this.get('globals').forEach(function (_globalSiteObj) {
+      // do not pass any globals whose name ends with _host or _hosts
+      if (!/_hosts?$/.test(_globalSiteObj.name)) {
+        // append "m" to JVM memory options except for hadoop_heapsize
+        if (/_heapsize|_newsize|_maxnewsize$/.test(_globalSiteObj.name) && _globalSiteObj.name !== 'hadoop_heapsize') {
+          globalSiteProperties[_globalSiteObj.name] = _globalSiteObj.value + "m";
+        } else {
+          globalSiteProperties[_globalSiteObj.name] = _globalSiteObj.value;
+        }
+        console.log("STEP8: name of the global property is: " + _globalSiteObj.name);
+        console.log("STEP8: value of the global property is: " + _globalSiteObj.value);
+      }
+    }, this);
+    return {"type": "global", "properties": globalSiteProperties};
+  },
+
+  createCoreSiteObj: function () {
+    var serviceName = this.get('service.serviceName');
+    var coreSiteObj = this.get('configs').filterProperty('filename', 'core-site.xml');
+    var coreSiteProperties = {};
+    // hadoop.proxyuser.oozie.hosts needs to be skipped if oozie is not selected
+    var isOozieSelected = serviceName == 'OOZIE';
+    var oozieUser = this.get('globals').someProperty('name', 'oozie_user') ? this.get('globals').findProperty('name', 'oozie_user').value : null;
+    var isHiveSelected = serviceName == 'HIVE';
+    var hiveUser = this.get('globals').someProperty('name', 'hive_user') ? this.get('globals').findProperty('name', 'hive_user').value : null;
+    var isHcatSelected = serviceName == 'WEBHCAT';
+    var hcatUser = this.get('globals').someProperty('name', 'hcat_user') ? this.get('globals').findProperty('name', 'hcat_user').value : null;
+    coreSiteObj.forEach(function (_coreSiteObj) {
+      if ((isOozieSelected || (_coreSiteObj.name != 'hadoop.proxyuser.' + oozieUser + '.hosts' && _coreSiteObj.name != 'hadoop.proxyuser.' + oozieUser + '.groups')) && (isHiveSelected || (_coreSiteObj.name != 'hadoop.proxyuser.' + hiveUser + '.hosts' && _coreSiteObj.name != 'hadoop.proxyuser.' + hiveUser + '.groups')) && (isHcatSelected || (_coreSiteObj.name != 'hadoop.proxyuser.' + hcatUser + '.hosts' && _coreSiteObj.name != 'hadoop.proxyuser.' + hcatUser + '.groups'))) {
+        coreSiteProperties[_coreSiteObj.name] = _coreSiteObj.value;
+      }
+      console.log("STEP*: name of the property is: " + _coreSiteObj.name);
+      console.log("STEP8: value of the property is: " + _coreSiteObj.value);
+    }, this);
+    return {"type": "core-site", "properties": coreSiteProperties};
+  },
+
+  createHdfsSiteObj: function () {
+    var hdfsSiteObj = this.get('configs').filterProperty('filename', 'hdfs-site.xml');
+    var hdfsProperties = {};
+    hdfsSiteObj.forEach(function (_configProperty) {
+      hdfsProperties[_configProperty.name] = _configProperty.value;
+      console.log("STEP*: name of the property is: " + _configProperty.name);
+      console.log("STEP8: value of the property is: " + _configProperty.value);
+    }, this);
+    return {"type": "hdfs-site", "properties": hdfsProperties };
+  },
+
+  createMrSiteObj: function () {
+    var configs = this.get('configs').filterProperty('filename', 'mapred-site.xml');
+    var mrProperties = {};
+    configs.forEach(function (_configProperty) {
+      mrProperties[_configProperty.name] = _configProperty.value;
+      console.log("STEP*: name of the property is: " + _configProperty.name);
+      console.log("STEP8: value of the property is: " + _configProperty.value);
+    }, this);
+    return {type: 'mapred-site', properties: mrProperties};
+  },
+
+  createHbaseSiteObj: function () {
+    var configs = this.get('configs').filterProperty('filename', 'hbase-site.xml');
+    var hbaseProperties = {};
+    configs.forEach(function (_configProperty) {
+      hbaseProperties[_configProperty.name] = _configProperty.value;
+    }, this);
+    return {type: 'hbase-site', properties: hbaseProperties};
+  },
+
+  createOozieSiteObj: function () {
+    var configs = this.get('configs').filterProperty('filename', 'oozie-site.xml');
+    var oozieProperties = {};
+    configs.forEach(function (_configProperty) {
+      oozieProperties[_configProperty.name] = _configProperty.value;
+    }, this);
+    return {type: 'oozie-site', properties: oozieProperties};
+  },
+
+  createHiveSiteObj: function () {
+    var configs = this.get('configs').filterProperty('filename', 'hive-site.xml');
+    var hiveProperties = {};
+    configs.forEach(function (_configProperty) {
+      hiveProperties[_configProperty.name] = _configProperty.value;
+    }, this);
+    return {type: 'hive-site', properties: hiveProperties};
+  },
+
+  createWebHCatSiteObj: function () {
+    var configs = this.get('configs').filterProperty('filename', 'webhcat-site.xml');
+    var webHCatProperties = {};
+    configs.forEach(function (_configProperty) {
+      webHCatProperties[_configProperty.name] = _configProperty.value;
+    }, this);
+    return {type: 'webhcat-site', properties: webHCatProperties};
+  },
+
+  applyConfigs: function () {
+    var self = this;
+    var configTags;
+    var clusterName = this.get('content.cluster.name');
+    var url = App.apiPrefix + '/clusters/' + clusterName + '/services/' + this.get('service.serviceName');
+    $.ajax({
+      type: 'GET',
+      url: url,
+      async: false,
+      timeout: 10000,
+      dataType: 'text',
+      success: function (data) {
+        var jsonData = jQuery.parseJSON(data);
+        configTags = jsonData.ServiceInfo.desired_configs;
+      },
+
+      error: function () {
+        self.setTasksStatus(3, 'FAILED');
+      },
+
+      statusCode: require('data/statusCodes')
+    });
+
+    if (!configTags) {
+      this.setTasksStatus(0, 'FAILED');
+      return;
+    }
+
+    for (var tag in configTags) {
+      if (this.get('createdConfigs').contains(tag)) {
+        configTags[tag] = this.get('newConfigsTag');
+      }
+    }
+    var data = {config: configTags};
+
+    $.ajax({
+      type: 'PUT',
+      url: url,
+      dataType: 'text',
+      data: JSON.stringify(data),
+      timeout: 5000,
+
+      beforeSend: function () {
+        self.setTasksStatus(3, 'PENDING');
+      },
+
+      success: function () {
+        self.setTasksStatus(3, 'COMPLETED');
+      },
+
+      error: function () {
+        self.setTasksStatus(3, 'FAILED');
+      },
+
+      statusCode: require('data/statusCodes')
+    });
+  },
+
+  putInMaintenanceMode: function () {
+    //todo after API providing
+    this.setTasksStatus(4, 'COMPLETED');
+  },
+
+  installComponent: function () {
+    var self = this;
+    var clusterName = this.get('content.cluster.name');
+    var url = App.apiPrefix + '/clusters/' + clusterName + '/host_components?HostRoles/state=INIT';
+    var data = '{"HostRoles": {"state": "INSTALLED"}}';
+    var method = 'PUT';
+    $.ajax({
+      type: method,
+      url: url,
+      data: data,
+      dataType: 'text',
+      timeout: App.timeout,
+
+      beforeSend: function () {
+        self.setTasksStatus(5, 'PENDING');
+      },
+
+      success: function (data) {
+        if (jQuery.parseJSON(data)) {
+          self.set('currentRequestId', jQuery.parseJSON(data).Requests.id);
+          self.getLogsByRequest();
+        } else {
+          self.setTasksStatus(5, 'FAILED');
+        }
+      },
+
+      error: function () {
+        self.setTasksStatus(5, 'FAILED');
+      },
+
+      statusCode: require('data/statusCodes')
+    });
+  },
+
+  startComponents: function () {
+    var self = this;
+    var clusterName = this.get('content.cluster.name');
+    var serviceName = this.get('masterComponent.service_id');
+    var url = App.apiPrefix + '/clusters/' + clusterName + '/services/' + serviceName;
+    var data = '{"ServiceInfo": {"state": "STARTED"}}';
+    var method = 'PUT';
+    $.ajax({
+      type: method,
+      url: url,
+      data: data,
+      dataType: 'text',
+      timeout: App.timeout,
+
+      beforeSend: function () {
+        self.setTasksStatus(6, 'PENDING');
+      },
+
+      success: function (data) {
+        if (jQuery.parseJSON(data)) {
+          self.set('currentRequestId', jQuery.parseJSON(data).Requests.id);
+          self.getLogsByRequest();
+        }
+      },
+
+      error: function () {
+        self.setTasksStatus(6, 'FAILED');
+      },
+
+      statusCode: require('data/statusCodes')
+    });
+  },
+
+  /**
+   * Parse logs to define status of Start, Stop ot Install task
+   * @param logs
+   */
+  parseLogs: function (logs) {
+    var self = this;
+    var task;
+    var stopPolling = false;
+    var starting = false;
+    var polledData = logs.tasks;
+    var status;
+    if ((this.get('tasks')[5].status != 'COMPLETED' && this.get('tasks')[6].status != 'COMPLETED' && this.get('tasks')[0].status != 'COMPLETED') ||
+        ((this.get('tasks')[5].status == 'COMPLETED') && this.get('tasks')[0].status == 'COMPLETED' && this.get('tasks')[6].status != 'COMPLETED')) {
+      //stopping or starting components
+      if (this.get('tasks')[0].status == 'COMPLETED') {
+        task = 6;
+        starting = true;
+      } else {
+        task = 0;
+      }
+      if (!polledData.someProperty('Tasks.status', 'PENDING') && !polledData.someProperty('Tasks.status', 'QUEUED') && !polledData.someProperty('Tasks.status', 'IN_PROGRESS')) {
+        if (polledData.someProperty('Tasks.status', 'FAILED')) {
+          this.setTasksStatus(task, 'FAILED');
+          status = 'FAILED'
+        } else {
+          this.setTasksStatus(task, 'COMPLETED');
+          status = 'COMPLETED';
+        }
+        stopPolling = true;
+      } else if (polledData.someProperty('Tasks.status', 'IN_PROGRESS')) {
+        var progress = polledData.filterProperty('Tasks.status', 'COMPLETED').length / polledData.length * 100;
+        this.setTasksStatus(task, 'IN_PROGRESS');
+        this.get('tasks')[task].set('progress', Math.round(progress));
+      }
+    } else {
+      //installing component
+      status = polledData[0].Tasks.status;
+      this.setTasksStatus(5, status);
+      if (status == 'IN_PROGRESS') {
+        this.get('tasks')[5].set('progress', '50');
+      }
+      if (status == 'COMPLETED' || status == 'FAILED') {
+        stopPolling = true;
+      }
+    }
+    if (!stopPolling) {
+      window.setTimeout(function () {
+        self.getLogsByRequest()
+      }, self.POLL_INTERVAL);
+    } else {
+      if (status == 'FAILED') {
+        //todo show retry
+      }
+      if (starting && status == 'COMPLETED') {
+        this.set('isSubmitDisabled', false);
+      }
+    }
+  },
+
+  POLL_INTERVAL: 4000,
+
+  getLogsByRequest: function () {
+    var self = this;
+    var clusterName = this.get('content.cluster.name');
+    var requestId = this.get('currentRequestId');
+    var url = App.apiPrefix + '/clusters/' + clusterName + '/requests/' + requestId + '?fields=tasks/*';
+    $.ajax({
+      type: 'GET',
+      url: url,
+      timeout: App.timeout,
+      dataType: 'text',
+      success: function (data) {
+        self.parseLogs(jQuery.parseJSON(data));
+      },
+
+      error: function () {
+        this.set('status', 'FAILED');
+      },
+
+      statusCode: require('data/statusCodes')
+    }).retry({times: App.maxRetries, timeout: App.timeout}).then(null,
+        function () {
+          App.showReloadPopup();
+          console.log('Install services all retries FAILED');
+        }
+    );
+  },
+
+  removeComponent: function () {
+    //todo after API providing
+    this.setTasksStatus(7, 'COMPLETED');
+  },
+
+  submit: function () {
+    if (!this.get('isSubmitDisabled')) {
+      App.router.send('next');
+    }
+  }
+})

Modified: incubator/ambari/trunk/ambari-web/app/messages.js
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-web/app/messages.js?rev=1456292&r1=1456291&r2=1456292&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-web/app/messages.js (original)
+++ incubator/ambari/trunk/ambari-web/app/messages.js Thu Mar 14 00:27:03 2013
@@ -413,6 +413,17 @@ Em.I18n.translations = {
   'installer.step13.sourceHost':'Source Host:',
   'installer.step13.changes':'Configs to change:',
   'installer.step13.component':'Component name:',
+  'installer.step14.task0':'{0} stop',
+  'installer.step14.task1':'{0} create',
+  'installer.step14.task2':'{0} configs create',
+  'installer.step14.task3':'{0} configs apply',
+  'installer.step14.task4':'{0} put in maintenance mode',
+  'installer.step14.task5':'{0} install',
+  'installer.step14.task6':'{0} start',
+  'installer.step14.task7':'{0} remove',
+  'installer.step14.status.success': 'Successfully reassigned {0}',
+  'installer.step14.status.failed': 'Failed to reassign {0}',
+  'installer.step14.status.info': 'Reassigning {0}. \nPlease wait while all tasks will be completed.',
 
   'installer.stackUpgrade.header':'Stack Upgrade Wizard',
   'installer.stackUpgrade.step1.newVersion':'New Version',

Modified: incubator/ambari/trunk/ambari-web/app/routes/reassign_master_routes.js
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-web/app/routes/reassign_master_routes.js?rev=1456292&r1=1456291&r2=1456292&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-web/app/routes/reassign_master_routes.js (original)
+++ incubator/ambari/trunk/ambari-web/app/routes/reassign_master_routes.js Thu Mar 14 00:27:03 2013
@@ -113,7 +113,7 @@ module.exports = Em.Route.extend({
   }),
 
   step4: Em.Route.extend({
-    route: '/step3',
+    route: '/step4',
     connectOutlets: function (router) {
       console.log('in reassignMaster.step4:connectOutlets');
       var controller = router.get('reassignMasterController');
@@ -125,6 +125,24 @@ module.exports = Em.Route.extend({
     },
     back: Em.Router.transitionTo('step3'),
     next: function (router) {
+      router.transitionTo('step5');
+    }
+  }),
+
+  step5: Em.Route.extend({
+    route: '/step5',
+    connectOutlets: function (router) {
+      console.log('in reassignMaster.step5:connectOutlets');
+      var controller = router.get('reassignMasterController');
+      controller.setCurrentStep('5');
+      controller.dataLoading().done(function () {
+        controller.loadAllPriorSteps();
+        controller.connectOutlet('wizardStep14', controller.get('content'));
+      })
+    },
+    back: Em.Router.transitionTo('step3'),
+    next: function (router) {
+      //router.transitionTo('step6');
     }
   }),
 

Modified: incubator/ambari/trunk/ambari-web/app/styles/application.less
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-web/app/styles/application.less?rev=1456292&r1=1456291&r2=1456292&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-web/app/styles/application.less (original)
+++ incubator/ambari/trunk/ambari-web/app/styles/application.less Thu Mar 14 00:27:03 2013
@@ -399,6 +399,17 @@ h1 {
       }
     }
   }
+  #step14 {
+    .item {
+      line-height: 30px;
+      i {
+        font-size: 20px;
+      }
+    }
+    .row {
+      margin-left: 0;
+    }
+  }
 }
 
 #stack-upgrade {

Modified: incubator/ambari/trunk/ambari-web/app/templates/main/service/reassign.hbs
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-web/app/templates/main/service/reassign.hbs?rev=1456292&r1=1456291&r2=1456292&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-web/app/templates/main/service/reassign.hbs (original)
+++ incubator/ambari/trunk/ambari-web/app/templates/main/service/reassign.hbs Thu Mar 14 00:27:03 2013
@@ -29,6 +29,7 @@
               <li {{bindAttr class="isStep2:active view.isStep2Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep2 target="controller"}}>{{t installer.step5.reassign.header}}</a></li>
               <li {{bindAttr class="isStep3:active view.isStep3Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep3 target="controller"}}>{{t installer.step12.header}}</a></li>
               <li {{bindAttr class="isStep4:active view.isStep4Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep4 target="controller"}}>{{t installer.step8.header}}</a></li>
+              <li {{bindAttr class="isStep5:active view.isStep5Disabled:disabled"}}><a href="javascript:void(null);"  {{action gotoStep5 target="controller"}}>{{t installer.step9.header}}</a></li>
             </ul>
           </div>
         </div>

Added: incubator/ambari/trunk/ambari-web/app/templates/wizard/step14.hbs
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-web/app/templates/wizard/step14.hbs?rev=1456292&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-web/app/templates/wizard/step14.hbs (added)
+++ incubator/ambari/trunk/ambari-web/app/templates/wizard/step14.hbs Thu Mar 14 00:27:03 2013
@@ -0,0 +1,39 @@
+{{!
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+}}
+<div id="step14">
+  <div {{bindAttr class="view.statusClass :alert"}}>{{view.statusMessage}}</div>
+    {{#each task in tasks}}
+      {{#view view.taskView contentBinding="task"}}
+        <div class="item">
+          <i {{bindAttr class="view.icon view.iconColor"}}></i>
+          <a href="javascript:void(0)">{{task.message}}</a>
+        </div>
+        <div {{bindAttr class="view.inProgress::hide :row :span12" }}>
+          <div class="progress-bar span4">
+            <div class="progress-striped active progress-info progress">
+              <div class="bar" {{bindAttr style="view.barWidth"}}></div>
+            </div>
+          </div>
+          <div class="span1">{{task.progress}}&#37;</div>
+        </div>
+      {{/view}}
+    {{/each}}
+  </div>
+  <div class="btn-area">
+    <a class="btn btn-success pull-right" {{bindAttr disabled="controller.isSubmitDisabled"}} {{action submit target="controller"}}>{{t common.next}} &rarr;</a>
+</div>

Modified: incubator/ambari/trunk/ambari-web/app/views.js
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-web/app/views.js?rev=1456292&r1=1456291&r2=1456292&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-web/app/views.js (original)
+++ incubator/ambari/trunk/ambari-web/app/views.js Thu Mar 14 00:27:03 2013
@@ -134,6 +134,7 @@ require('views/wizard/step10_view');
 require('views/wizard/step11_view');
 require('views/wizard/step12_view');
 require('views/wizard/step13_view');
+require('views/wizard/step14_view');
 require('views/wizard/stack_upgrade/step1_view');
 require('views/wizard/stack_upgrade/step2_view');
 require('views/wizard/stack_upgrade/step3_view');

Added: incubator/ambari/trunk/ambari-web/app/views/wizard/step14_view.js
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-web/app/views/wizard/step14_view.js?rev=1456292&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-web/app/views/wizard/step14_view.js (added)
+++ incubator/ambari/trunk/ambari-web/app/views/wizard/step14_view.js Thu Mar 14 00:27:03 2013
@@ -0,0 +1,91 @@
+/**
+ * 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.WizardStep14View = Em.View.extend({
+
+  templateName: require('templates/wizard/step14'),
+
+  statusMessage: null,
+  statusClass: 'alert-info',
+
+  didInsertElement: function () {
+    this.get('controller').loadStep();
+  },
+
+  tasks: function () {
+    return this.get('controller.tasks');
+  }.property('controller.tasks'),
+
+  onStatus: function () {
+    var master = this.get('controller.content.reassign.display_name');
+    switch (this.get('controller.status')) {
+      case 'COMPLETED':
+        this.set('statusMessage', Em.I18n.t('installer.step14.status.success').format(master));
+        this.set('statusClass', 'alert-success');
+        break;
+      case 'FAILED':
+        this.set('statusMessage', Em.I18n.t('installer.step14.status.failed').format(master));
+        this.set('statusClass', 'alert-error');
+        break;
+      case 'IN_PROGRESS':
+      default:
+        this.set('statusMessage', Em.I18n.t('installer.step14.status.info').format(master));
+        this.set('statusClass', 'alert-info');
+    }
+  }.observes('controller.status'),
+
+  taskView: Em.View.extend({
+    icon: '',
+    iconColor: '',
+
+    didInsertElement: function () {
+      this.onStatus();
+    },
+
+    barWidth: function () {
+      return 'width: ' + this.get('content.progress') + '%;';
+    }.property('content.progress'),
+
+    onStatus: function () {
+      if (this.get('content.status') === 'IN_PROGRESS') {
+        this.set('icon', 'icon-cog');
+        this.set('iconColor', 'text-info');
+      } else if (this.get('content.status') === 'WARNING') {
+        this.set('icon', 'icon-warning-sign');
+        this.set('iconColor', 'text-warning');
+      } else if (this.get('content.status') === 'FAILED') {
+        this.set('icon', 'icon-exclamation-sign');
+        this.set('iconColor', 'text-error');
+      } else if (this.get('content.status') === 'COMPLETED') {
+        this.set('icon', 'icon-ok');
+        this.set('iconColor', 'text-success');
+      } else {
+        this.set('icon', 'icon-cog');
+        this.set('iconColor', '');
+      }
+    }.observes('content.status'),
+
+    inProgress: function () {
+      return this.get('content.status') === "IN_PROGRESS";
+    }.property('content.status')
+
+  })
+});