Blob Blame History Raw
From ef01aa872871b8e1ea79058cbe3301ce878dde9a Mon Sep 17 00:00:00 2001
From: Ondrej Mular <omular@redhat.com>
Date: Tue, 25 Aug 2015 11:44:00 +0200
Subject: [PATCH] fix dashboard in web UI

---
 pcsd/cluster_entity.rb           | 53 +++++++++++++++++++++++++++++-----------
 pcsd/pcs.rb                      | 14 ++++++++---
 pcsd/public/js/nodes-ember.js    | 17 ++++++++++---
 pcsd/public/js/pcsd.js           | 38 ++++++++++++++--------------
 pcsd/remote.rb                   | 22 +++++++++++++++--
 pcsd/test/test_cluster_entity.rb |  4 +--
 pcsd/views/_resource.erb         | 20 +++++++--------
 pcsd/views/main.erb              |  4 +++
 8 files changed, 117 insertions(+), 55 deletions(-)

diff --git a/pcsd/cluster_entity.rb b/pcsd/cluster_entity.rb
index b291937..78bc5ab 100644
--- a/pcsd/cluster_entity.rb
+++ b/pcsd/cluster_entity.rb
@@ -112,6 +112,9 @@ module ClusterEntity
       status.node = node
       primitive.crm_status << status
     }
+    primitives.each {|_, resource|
+      resource[0].update_status
+    }
     return primitives
   end
 
@@ -178,6 +181,9 @@ module ClusterEntity
         end
       end
     }
+    tree.each {|resource|
+      resource.update_status
+    }
     return tree
   end
 
@@ -491,23 +497,27 @@ module ClusterEntity
       end
     end
 
+    def update_status
+      @status = get_status
+    end
+
     def get_status
-      count = @crm_status.length
       running = 0
+      failed = 0
       @crm_status.each do |s|
-        if ['Started', 'Master', 'Slave'].include?(s.role)
+        if s.active
           running += 1
+        elsif s.failed
+          failed += 1
         end
       end
 
       if disabled?
         status = ClusterEntity::ResourceStatus.new(:disabled)
-      elsif running != 0
-        if running == count
-          status = ClusterEntity::ResourceStatus.new(:running)
-        else
-          status = ClusterEntity::ResourceStatus.new(:partially_running)
-        end
+      elsif running > 0
+        status = ClusterEntity::ResourceStatus.new(:running)
+      elsif failed > 0
+        status = ClusterEntity::ResourceStatus.new(:failed)
       else
         status = ClusterEntity::ResourceStatus.new(:blocked)
       end
@@ -655,6 +665,14 @@ module ClusterEntity
       end
     end
 
+    def update_status
+      @status = ClusterEntity::ResourceStatus.new(:running)
+      @members.each { |p|
+        p.update_status
+        @status = p.status if @status < p.status
+      }
+    end
+
     def to_status(version='1')
       if version == '2'
         hash = super(version)
@@ -730,6 +748,13 @@ module ClusterEntity
       end
     end
 
+    def update_status
+      if @member
+        @member.update_status
+        @status = @member.status
+      end
+    end
+
     def to_status(version='1')
       if version == '2'
         hash = super(version)
@@ -794,13 +819,13 @@ module ClusterEntity
           primitive_list = @member.members
         end
         @masters, @slaves = get_masters_slaves(primitive_list)
-      end
-      if @masters.empty?
-        @error_list << {
-          :message => 'Resource is master/slave but has not been promoted '\
+        if @masters.empty?
+          @error_list << {
+            :message => 'Resource is master/slave but has not been promoted '\
               + 'to master on any node.',
-          :type => 'no_master'
-        }
+            :type => 'no_master'
+          }
+        end
       end
     end
 
diff --git a/pcsd/pcs.rb b/pcsd/pcs.rb
index 1fe9b99..cc5b038 100644
--- a/pcsd/pcs.rb
+++ b/pcsd/pcs.rb
@@ -1506,10 +1506,18 @@ def cluster_status_from_nodes(session, cluster_nodes, cluster_name)
     status = overview.update(cluster_nodes_map[quorate_nodes[0]])
     status[:quorate] = true
     status[:node_list] = node_status_list
-  # if we don't have quorum, use data from any node
-  # no node has quorum, so no node has any info about the cluster
+  # if we don't have quorum, use data from any online node,
+  # otherwise use data from any node no node has quorum, so no node has any
+  # info about the cluster
   elsif not old_status
-    status = overview.update(cluster_nodes_map.values[0])
+    node_to_use = cluster_nodes_map.values[0]
+    cluster_nodes_map.each { |_, node_data|
+      if node_data[:node] and node_data[:node][:status] == 'online'
+        node_to_use = node_data
+        break
+      end
+    }
+    status = overview.update(node_to_use)
     status[:quorate] = false
     status[:node_list] = node_status_list
   # old pcsd doesn't provide info about quorum, use data from any node
diff --git a/pcsd/public/js/nodes-ember.js b/pcsd/public/js/nodes-ember.js
index 1f60adc..172c00a 100644
--- a/pcsd/public/js/nodes-ember.js
+++ b/pcsd/public/js/nodes-ember.js
@@ -54,7 +54,8 @@ Pcs = Ember.Application.createWithMixins({
     if (window.location.pathname.lastIndexOf('/manage', 0) !== 0) {
       return;
     }
-    clearTimeout(Pcs.update_timeout);
+    clearTimeout(Pcs.get('update_timeout'));
+    Pcs.set('update_timeout', null);
     var self = Pcs;
     var cluster_name = self.cluster_name;
     if (cluster_name == null) {
@@ -77,7 +78,7 @@ Pcs = Ember.Application.createWithMixins({
           if (data["not_current_data"]) {
             self.update();
           } else {
-            Pcs.update_timeout = window.setTimeout(self.update, 20000);
+            Pcs.set('update_timeout', window.setTimeout(self.update,20000));
           }
           hide_loading_screen();
         },
@@ -92,7 +93,7 @@ Pcs = Ember.Application.createWithMixins({
               console.log("Error: Unable to parse json for clusters_overview");
             }
           }
-          Pcs.update_timeout = window.setTimeout(self.update,20000);
+          Pcs.set('update_timeout', window.setTimeout(self.update,20000));
           hide_loading_screen();
         }
       });
@@ -126,6 +127,7 @@ Pcs = Ember.Application.createWithMixins({
           var cur_resource = self.get('cur_resource');
           var resource_map = self.get('resource_map');
           if (first_run) {
+            setup_node_links();
             Pcs.nodesController.load_node($('#node_list_row').find('.node_selected').first(),true);
             Pcs.aclsController.load_role($('#acls_list_row').find('.node_selected').first(), true);
             if (self.get("fence_id_to_load")) {
@@ -173,7 +175,6 @@ Pcs = Ember.Application.createWithMixins({
             if (!resource_change && self.get('cur_resource'))
               tree_view_select(self.get('cur_resource').get('id'));
             Pcs.selectedNodeController.reset();
-            setup_node_links();
             disable_checkbox_clicks();
           });
         });
@@ -207,6 +208,7 @@ Pcs.resourcesContainer = Ember.Object.create({
   cur_fence: null,
   constraints: {},
   group_list: [],
+  data_version: null,
 
   get_resource_by_id: function(resource_id) {
     var resource_map = this.get('resource_map');
@@ -434,6 +436,7 @@ Pcs.resourcesContainer = Ember.Object.create({
   update: function(data) {
     var self = this;
     self.set('group_list', data['groups']);
+    self.set("data_version", data['status_version']);
     var resources = data["resource_list"];
     var resource_obj = null;
     var resource_id;
@@ -495,6 +498,12 @@ Pcs.resourcesContainer = Ember.Object.create({
   }
 });
 
+Pcs.resourcesContainer.reopen({
+  is_version_1: function() {
+    return (this.get("data_version") == '1');
+  }.property('data_version')
+});
+
 Pcs.ResourceObj = Ember.Object.extend({
   id: null,
   _id: Ember.computed.alias('id'),
diff --git a/pcsd/public/js/pcsd.js b/pcsd/public/js/pcsd.js
index 9891aa8..2c71e6b 100644
--- a/pcsd/public/js/pcsd.js
+++ b/pcsd/public/js/pcsd.js
@@ -1242,26 +1242,24 @@ function destroy_tooltips() {
 }
 
 function remove_cluster(ids) {
-  for (var i=0; i<ids.length; i++) {
-    var cluster = ids[i];
-    var clusterid_name = "clusterid-"+ids[i];
-    var data = {}
-    data[clusterid_name] = true;
-    $.ajax({
-      type: 'POST',
-      url: '/manage/removecluster',
-      data: data,
-      timeout: pcs_timeout,
-      success: function () {
-        $("#dialog_verify_remove_clusters.ui-dialog-content").each(function(key, item) {$(item).dialog("destroy")});
-        location.reload();
-      },
-      error: function (xhr, status, error) {
-        alert("Unable to remove cluster: " + res + " ("+error+")");
-        $("#dialog_verify_remove_clusters.ui-dialog-content").each(function(key, item) {$(item).dialog("destroy")});
-      }
-    });
-  }
+  var data = {};
+  $.each(ids, function(_, cluster) {
+    data[ "clusterid-" + cluster] = true;
+  });
+  $.ajax({
+    type: 'POST',
+    url: '/manage/removecluster',
+    data: data,
+    timeout: pcs_timeout,
+    success: function () {
+      $("#dialog_verify_remove_clusters.ui-dialog-content").each(function(key, item) {$(item).dialog("destroy")});
+      location.reload();
+    },
+    error: function (xhr, status, error) {
+      alert("Unable to remove cluster: " + res + " ("+error+")");
+      $("#dialog_verify_remove_clusters.ui-dialog-content").each(function(key, item) {$(item).dialog("destroy")});
+    }
+  });
 }
 
 function remove_nodes(ids, force) {
diff --git a/pcsd/remote.rb b/pcsd/remote.rb
index a40c1c7..06947ec 100644
--- a/pcsd/remote.rb
+++ b/pcsd/remote.rb
@@ -2,6 +2,7 @@ require 'json'
 require 'uri'
 require 'open4'
 require 'set'
+require 'timeout'
 
 require 'pcs.rb'
 require 'resource.rb'
@@ -1120,6 +1121,16 @@ def clusters_overview(params, request, session)
   config = PCSConfig.new(Cfgsync::PcsdSettings.from_file('{}').text())
   config.clusters.each { |cluster|
     threads << Thread.new {
+      cluster_map[cluster.name] = {
+        'cluster_name' => cluster.name,
+        'error_list' => [
+          {'message' => 'Unable to connect to the cluster. Request timeout.'}
+        ],
+        'warning_list' => [],
+        'status' => 'unknown',
+        'node_list' => get_default_overview_node_list(cluster.name),
+        'resource_list' => []
+      }
       overview_cluster = nil
       online, offline, not_authorized_nodes = check_gui_status_of_nodes(
         session,
@@ -1134,7 +1145,7 @@ def clusters_overview(params, request, session)
       nodes_not_in_cluster = []
       for node in cluster_nodes_auth
         code, response = send_request_with_token(
-          session, node, 'cluster_status', true, {}, true, nil, 15
+          session, node, 'cluster_status', true, {}, true, nil, 8
         )
         if code == 404
           not_supported = true
@@ -1228,7 +1239,14 @@ def clusters_overview(params, request, session)
       cluster_map[cluster.name] = overview_cluster
     }
   }
-  threads.each { |t| t.join }
+
+  begin
+    Timeout::timeout(18) {
+      threads.each { |t| t.join }
+    }
+  rescue Timeout::Error
+    threads.each { |t| t.exit }
+  end
 
   # update clusters in PCSConfig
   not_current_data = false
diff --git a/pcsd/views/_resource.erb b/pcsd/views/_resource.erb
index 862b648..cc4c06e 100644
--- a/pcsd/views/_resource.erb
+++ b/pcsd/views/_resource.erb
@@ -32,16 +32,16 @@
     <td id="<%=@myView%>_list" class="node_list">
       <%= erb :_resource_list %>
     </td>
-	<td id="node_info" colspan=2>
-	  <div id="<%=@myView%>_info_div">
-		<% if @myView == "resource" %>
-			{{resource-edit resource=Pcs.resourcesContainer.cur_resource page_name="Resource"}}
-		<% else %>
-			{{resource-edit resource=Pcs.resourcesContainer.cur_fence page_name="Fence device" stonith=1}}
-		<% end %>
-	  </div>
-	  </td>
-	</tr>
+  <td id="node_info" colspan=2>
+    <div id="<%=@myView%>_info_div">
+    <% if @myView == "resource" %>
+      {{resource-edit resource=Pcs.resourcesContainer.cur_resource page_name="Resource" old_pcsd=Pcs.resourcesContainer.is_version_1}}
+    <% else %>
+      {{resource-edit resource=Pcs.resourcesContainer.cur_fence page_name="Fence device" stonith=1 old_pcsd=Pcs.resourcesContainer.is_version_1}}
+    <% end %>
+    </div>
+    </td>
+  </tr>
     <% if @myView == "resource" %>
       </div>
     </table>
diff --git a/pcsd/views/main.erb b/pcsd/views/main.erb
index 3c1e0cd..bb4e989 100644
--- a/pcsd/views/main.erb
+++ b/pcsd/views/main.erb
@@ -197,6 +197,7 @@
             <td class="bold" nowrap>Current Location:</td>
             <td id="cur_res_loc" class="reg">{{resource.nodes_running_on_string}}</td>
           </tr>
+          {{#unless old_pcsd}}
           {{#unless resource.parent}}
             <tr>
               <td class="bold" nowrap>Clone:</td>
@@ -226,8 +227,10 @@
             </tr>
             {{/if}}
           {{/unless}}
+          {{/unless}}
         {{/if}}
         {{/unless}}
+        {{#unless old_pcsd}}
         {{#if resource.is_group}}
         {{#unless resource.parent}}
           <tr>
@@ -258,6 +261,7 @@
             </td>
           </tr>
         {{/if}}
+        {{/unless}}
       </table>
       {{#unless resource.stonith}}
         {{location_constraints-table constraints=resource.location_constraints}}
-- 
1.9.1