瀏覽代碼

AMBARI-1059. Refactor cluster management. (yusaku)

git-svn-id: https://svn.apache.org/repos/asf/incubator/ambari/branches/AMBARI-666@1418944 13f79535-47bb-0310-9956-ffa450edef68
Yusaku Sako 12 年之前
父節點
當前提交
6e0b836d9e

+ 5 - 0
ambari-web/app/assets/data/wizard/bootstrap/bootstrap.json

@@ -0,0 +1,5 @@
+{
+  "status": "OK",
+  "log": "Running Bootstrap now",
+  "requestId": "1"
+}

+ 16 - 0
ambari-web/app/assets/data/wizard/bootstrap/poll_1.json

@@ -0,0 +1,16 @@
+{
+  "status": "RUNNING",
+  "hostsStatus": [
+    {
+      "status": "RUNNING",
+      "hostName": "dev001",
+      "log": "STDOUT\n\nSTDERR\nWarning: Permanently added 'dev001,10.0.2.15' (RSA) to the list of known hosts.\n"
+    },
+    {
+      "status": "RUNNING",
+      "hostName": "dev002",
+      "log": "STDOUT\n\nSTDERR\nWarning: Permanently added 'dev002,10.0.2.16' (RSA) to the list of known hosts.\n"
+    }
+  ],
+  "log": ""
+}

+ 16 - 0
ambari-web/app/assets/data/wizard/bootstrap/poll_2.json

@@ -0,0 +1,16 @@
+{
+  "status": "SUCCESS",
+  "hostsStatus": [
+    {
+      "status": "FAILED",
+      "hostName": "dev001",
+      "log": "STDOUT\n\nSTDERR\nWarning: Permanently added 'dev001,10.0.2.15' (RSA) to the list of known hosts.\r\n/etc/yum.repos.d/ambari.repo: No such file or directory\nSTDOUT\n\nSTDERR\nPermission denied, please try again.\r\nConnection closed by UNKNOWN\r\nlost connection\nSTDOUT\n\nSTDERR\npython: can't open file '/tmp/setupAgent.py': [Errno 2] No such file or directory\n"
+    },
+    {
+      "status": "DONE",
+      "hostName": "dev002",
+      "log": "STDOUT\n\nSTDERR\nWarning: Permanently added 'dev002,10.0.2.16' (RSA) to the list of known hosts.\r\n/etc/yum.repos.d/ambari.repo: No such file or directory\nSTDOUT\n\nSTDERR\nPermission denied, please try again.\r\nConnection closed by UNKNOWN\r\nlost connection\nSTDOUT\n\nSTDERR\npython: can't open file '/tmp/setupAgent.py': [Errno 2] No such file or directory\n"
+    }
+  ],
+  "log": "\n\nINFO:root:BootStrapping hosts ['dev001','dev002'] using /root/dev/ambari/ambari-server/src/main/python with sshKey File /tmp/bootstrap/1/sshKey using tmp dir /tmp/bootstrap/1 ambari: localhost\nINFO:root:Running scp command scp -o ConnectTimeout=3 -o StrictHostKeyChecking=no -i /tmp/bootstrap/1/sshKey /etc/yum.repos.d/ambari.repo root@dev001:/etc/yum.repos.d\nINFO:root:scp /etc/yum.repos.d/ambari.repo done for host dev001, exitcode=1\nINFO:root:Parallel scp returns for repo file\nINFO:root:Running scp command scp -o ConnectTimeout=3 -o StrictHostKeyChecking=no -i /tmp/bootstrap/1/sshKey /root/dev/ambari/ambari-server/src/main/python/setupAgent.py root@dev001:/tmp\nINFO:root:scp /root/dev/ambari/ambari-server/src/main/python/setupAgent.py done for host dev001, exitcode=1\nINFO:root:Parallel scp returns for agent script\nINFO:root:Running setup agent...\nINFO:root:Running ssh command ssh -o ConnectTimeOut=3 -o StrictHostKeyChecking=no -i /tmp/bootstrap/1/sshKey root@dev001 python /tmp/setupAgent.py tmp localhost\nINFO:root:Setup agent done for host dev001, exitcode=2\nINFO:root:Parallel ssh returns for setup agent\n"
+}

+ 6 - 4
ambari-web/app/controllers/wizard/step2_controller.js

@@ -140,15 +140,17 @@ App.WizardStep2Controller = Em.Controller.extend({
 
 
     var bootStrapData = JSON.stringify({'verbose': true, 'sshKey': this.get('sshKey'), hosts: this.get('hostNameArr')});
     var bootStrapData = JSON.stringify({'verbose': true, 'sshKey': this.get('sshKey'), hosts: this.get('hostNameArr')});
 
 
-    // TODO: skipping bootstrap for now
-    if (true) {
+    if (App.skipBootstrap) {
       App.router.send('next');
       App.router.send('next');
       return true;
       return true;
     }
     }
 
 
+    var method = App.testMode ? 'GET' : 'POST';
+    var url = App.testMode ? '/data/wizard/bootstrap/bootstrap.json' : '/api/bootstrap';
+
     $.ajax({
     $.ajax({
-      type: 'POST',
-      url: '/api/bootstrap',
+      type: method,
+      url: url,
       data: bootStrapData,
       data: bootStrapData,
       timeout: 10000,
       timeout: 10000,
       contentType: 'application/json',
       contentType: 'application/json',

+ 54 - 26
ambari-web/app/controllers/wizard/step3_controller.js

@@ -42,8 +42,16 @@ App.WizardStep3Controller = Em.Controller.extend({
 
 
   navigateStep: function () {
   navigateStep: function () {
     this.loadStep();
     this.loadStep();
-    if (App.db.getBootStatus() === false) {
-      this.startBootstrap();
+    if (App.db.getInstallType().installType !== 'manual') {
+      if (App.db.getBootStatus() === false) {
+        this.startBootstrap();
+      }
+    } else {
+      // TODO: assume manually bootstrapped hosts are all successful for now
+      this.get('hosts').forEach(function (_host) {
+        _host.set('bootStatus', 'DONE');
+        _host.set('bootLog', 'Success');
+      });
     }
     }
   },
   },
 
 
@@ -55,7 +63,7 @@ App.WizardStep3Controller = Em.Controller.extend({
     console.log("TRACE: Loading step3: Confirm Hosts");
     console.log("TRACE: Loading step3: Confirm Hosts");
     this.clearStep();
     this.clearStep();
     var hosts = this.loadHosts();
     var hosts = this.loadHosts();
-    // hosts.setEach('bootStatus', 'pending');
+    // hosts.setEach('bootStatus', 'RUNNING');
     this.renderHosts(hosts);
     this.renderHosts(hosts);
   },
   },
 
 
@@ -88,30 +96,27 @@ App.WizardStep3Controller = Em.Controller.extend({
   },
   },
 
 
   /**
   /**
-   * Parses and updates the content, and governs the possibility
-   * of the next doBootstrap (polling) call.
-   * Returns true if polling should stop (no hosts are in "pending" state); false otherwise
+   * Parses and updates the content based on bootstrap API response.
+   * Returns true if polling should continue (some hosts are in "RUNNING" state); false otherwise
    */
    */
-  parseHostInfo: function (hostsFromServer, hostsFromContent) {
-    var result = true;  // default value as true implies
-    hostsFromServer.forEach(function (_hostFromServer) {
-      var host = hostsFromContent.findProperty('name', _hostFromServer.name);
+  parseHostInfo: function (hostsStatusFromServer) {
+    hostsStatusFromServer.forEach(function (_hostStatus) {
+      var host = this.get('bootHosts').findProperty('name', _hostStatus.hostName);
       if (host !== null && host !== undefined) { // check if hostname extracted from REST API data matches any hostname in content
       if (host !== null && host !== undefined) { // check if hostname extracted from REST API data matches any hostname in content
-        host.set('bootStatus', _hostFromServer.status);
-        host.set('cpu', _hostFromServer.cpu);
-        host.set('memory', _hostFromServer.memory);
+        host.set('bootStatus', _hostStatus.status);
+        host.set('bootLog', _hostStatus.log);
       }
       }
-    });
-    // if the data rendered by REST API has no hosts or no hosts are in "pending" state, polling will stop
-    return this.hosts.length == 0 || !this.hosts.someProperty('bootStatus', 'pending');
+    }, this);
+    // if the data rendered by REST API has hosts in "RUNNING" state, polling will continue
+    return this.get('bootHosts').length != 0 && this.get('bootHosts').someProperty('bootStatus', 'RUNNING');
   },
   },
 
 
   /* Returns the current set of visible hosts on view (All, Succeeded, Failed) */
   /* Returns the current set of visible hosts on view (All, Succeeded, Failed) */
   visibleHosts: function () {
   visibleHosts: function () {
     if (this.get('category') === 'Success') {
     if (this.get('category') === 'Success') {
-      return (this.hosts.filterProperty('bootStatus', 'success'));
+      return (this.hosts.filterProperty('bootStatus', 'DONE'));
     } else if (this.get('category') === 'Error') {
     } else if (this.get('category') === 'Error') {
-      return (this.hosts.filterProperty('bootStatus', 'error'));
+      return (this.hosts.filterProperty('bootStatus', 'FAILED'));
     } else { // if (this.get('category') === 'All Hosts')
     } else { // if (this.get('category') === 'All Hosts')
       return this.hosts;
       return this.hosts;
     }
     }
@@ -179,27 +184,42 @@ App.WizardStep3Controller = Em.Controller.extend({
     }
     }
   },
   },
 
 
+  numPolls: 0,
+
   startBootstrap: function () {
   startBootstrap: function () {
     //this.set('isSubmitDisabled', true);    //TODO: uncomment after actual hookup
     //this.set('isSubmitDisabled', true);    //TODO: uncomment after actual hookup
+    this.numPolls = 0;
     this.set('bootHosts', this.get('hosts'));
     this.set('bootHosts', this.get('hosts'));
     this.doBootstrap();
     this.doBootstrap();
   },
   },
 
 
   doBootstrap: function () {
   doBootstrap: function () {
+    this.numPolls++;
     var self = this;
     var self = this;
-    var url = '/api/bootstrap';
+    var url = App.testMode ? '/data/wizard/bootstrap/poll_' + this.numPolls + '.json' : '/api/bootstrap/1';
     $.ajax({
     $.ajax({
       type: 'GET',
       type: 'GET',
       url: url,
       url: url,
       timeout: 5000,
       timeout: 5000,
       success: function (data) {
       success: function (data) {
-        console.log("TRACE: In success function for the GET bootstrap call");
-        var result = self.parseHostInfo(data, this.get('bootHosts'));
-        window.setTimeout(self.doBootstrap, 3000);
+        if (data.hostsStatus !== null) {
+          // in case of bootstrapping just one server, the server returns an object rather than an array...
+          if (!(data.hostsStatus instanceof Array)) {
+            data.hostsStatus = [ data.hostsStatus ];
+          }
+          console.log("TRACE: In success function for the GET bootstrap call");
+          var result = self.parseHostInfo(data.hostsStatus);
+          if (result) {
+            window.setTimeout(function () { self.doBootstrap() }, 3000);
+            return;
+          }
+        }
+        console.log('Bootstrap failed');
+        self.stopBootstrap();
       },
       },
 
 
       error: function () {
       error: function () {
-        console.log("ERROR");
+        console.log('Bootstrap failed');
         self.stopBootstrap();
         self.stopBootstrap();
       },
       },
 
 
@@ -210,6 +230,7 @@ App.WizardStep3Controller = Em.Controller.extend({
 
 
   stopBootstrap: function () {
   stopBootstrap: function () {
     //TODO: uncomment following line after the hook up with the API call
     //TODO: uncomment following line after the hook up with the API call
+    console.log('stopBootstrap() called');
     // this.set('isSubmitDisabled',false);
     // this.set('isSubmitDisabled',false);
   },
   },
 
 
@@ -220,14 +241,21 @@ App.WizardStep3Controller = Em.Controller.extend({
     }
     }
   },
   },
 
 
-  hostLogPopup: function (event) {
+  hostLogPopup: function (event, context) {
+    var host = event.context;
+
     App.ModalPopup.show({
     App.ModalPopup.show({
-      header: Em.I18n.t('installer.step3.hostLog.popup.header'),
+
+      header: Em.I18n.t('installer.step3.hostLog.popup.header').format(host.get('name')),
+      secondary: null,
+
       onPrimary: function () {
       onPrimary: function () {
         this.hide();
         this.hide();
       },
       },
+
       bodyClass: Ember.View.extend({
       bodyClass: Ember.View.extend({
-        templateName: require('templates/wizard/step3HostLogPopup')
+        templateName: require('templates/wizard/step3_host_log_popup'),
+        host: host
       })
       })
     });
     });
   },
   },

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

@@ -20,6 +20,7 @@
 window.App = require('app');
 window.App = require('app');
 
 
 App.testMode = false;
 App.testMode = false;
+App.skipBootstrap = false;
 
 
 require('messages');
 require('messages');
 require('utils/data_table');
 require('utils/data_table');

+ 1 - 2
ambari-web/app/messages.js

@@ -88,8 +88,7 @@ Em.I18n.translations = {
   'installer.step3.header':'Confirm Hosts',
   'installer.step3.header':'Confirm Hosts',
   'installer.step3.body':'Here are the results of the host discovery process.<br>' +
   'installer.step3.body':'Here are the results of the host discovery process.<br>' +
     'Please verify and remove the ones that you do not want to be part of the cluster.',
     'Please verify and remove the ones that you do not want to be part of the cluster.',
-  'installer.step3.hostLog.popup.header':'Log file for the host',
-  'installer.step3.hostLog.popup.body':'Placeholder for the log file',
+  'installer.step3.hostLog.popup.header':'Bootstrap log for {0}',
   'installer.step3.hosts.remove.popup.header':'Remove Hosts',
   'installer.step3.hosts.remove.popup.header':'Remove Hosts',
   'installer.step3.hosts.remove.popup.body':'Are you sure you want to remove the selected host(s)?',
   'installer.step3.hosts.remove.popup.body':'Are you sure you want to remove the selected host(s)?',
   'installer.step3.hosts.retry.popup.header':'Retry Host Discovery',
   'installer.step3.hosts.retry.popup.header':'Retry Host Discovery',

文件差異過大導致無法顯示
+ 0 - 2
ambari-web/app/models/hosts.js


+ 3 - 0
ambari-web/app/styles/application.less

@@ -260,6 +260,9 @@ h1 {
         margin-bottom: 0;
         margin-bottom: 0;
       }
       }
     }
     }
+    .progress {
+      margin-bottom: 0;
+    }
   }
   }
   #step4, #step6 {
   #step4, #step6 {
     a.selected {
     a.selected {

+ 9 - 7
ambari-web/app/templates/wizard/step3.hbs

@@ -61,11 +61,10 @@
         <thead>
         <thead>
         <tr>
         <tr>
           <th class="span1">{{view Ember.Checkbox checkedBinding="allChecked"}}</th>
           <th class="span1">{{view Ember.Checkbox checkedBinding="allChecked"}}</th>
-          <th class="span2">Status</th>
-          <!--  given by the parsing function that parses data from bootstrap call -->
-          <th class="span4">Host</th>
+          <th class="span3">Host</th>
           <!-- retrieved from local storage initially -->
           <!-- retrieved from local storage initially -->
-          <th class="span2">Message</th>
+          <th class="span3">Progress</th>
+          <th class="span2">Status</th>
           <!-- given by the parsing function that parses data from bootstrap call, dynamically assign the color -->
           <!-- given by the parsing function that parses data from bootstrap call, dynamically assign the color -->
           <th class="span3">Action</th>
           <th class="span3">Action</th>
           <!-- trash icon -->
           <!-- trash icon -->
@@ -81,14 +80,17 @@
           {{view Ember.Checkbox checkedBinding="host.isChecked"}}
           {{view Ember.Checkbox checkedBinding="host.isChecked"}}
         </td>
         </td>
         <td>
         <td>
-          {{host.bootStatus}}
+          {{host.name}}
         </td>
         </td>
         <td>
         <td>
-          {{host.name}}
+          <div {{bindAttr class="host.bootBarColor host.isBootDone::progress-striped host.isBootDone::active :progress"}}>
+            <div class="bar" style="width:100%">
+            </div>
+          </div>
         </td>
         </td>
         <td>
         <td>
           <a href="javascript:void(null)"
           <a href="javascript:void(null)"
-             data-toggle="modal" {{action hostLogPopup target="controller"}}>{{host.message}}</a>
+             data-toggle="modal" {{action hostLogPopup host target="controller"}}>{{host.bootStatusForDisplay}}</a>
         </td>
         </td>
         <td>
         <td>
           {{#if view.isRemovable}}<a class="btn btn-mini" {{action remove target="view"}}><i class="icon-trash"></i>
           {{#if view.isRemovable}}<a class="btn btn-mini" {{action remove target="view"}}><i class="icon-trash"></i>

+ 6 - 1
ambari-web/app/templates/wizard/step3HostLogPopup.hbs → ambari-web/app/templates/wizard/step3_host_log_popup.hbs

@@ -16,4 +16,9 @@
 * limitations under the License.
 * limitations under the License.
 }}
 }}
 
 
-<p>{{t installer.step3.hostLog.popup.body}}</p>
+
+<div id="host-log">
+  <div>
+    <pre class="bootLog">{{view.host.bootLog}}</pre>
+  </div>
+</div>

+ 2 - 0
ambari-web/app/views/wizard/step3_view.js

@@ -52,3 +52,5 @@ App.WizardHostView = Em.View.extend({
   }.property('hostInfo.bootStatus')
   }.property('hostInfo.bootStatus')
 
 
 });
 });
+
+

部分文件因文件數量過多而無法顯示