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