375 lines
14 KiB
Diff
375 lines
14 KiB
Diff
|
commit 9584fca04fc5b7a72dba09cc44fcfbe917325737
|
||
|
Author: Gao,Yan <ygao@suse.com>
|
||
|
Date: Fri Jan 24 16:11:36 2014 +0800
|
||
|
|
||
|
Feature: crm_mon: Display brief output if "-b/--brief" is supplied or 'b' is toggled
|
||
|
|
||
|
It's very helpful if there are many same types of resources.
|
||
|
|
||
|
If -b/--brief is supplied, the output is like:
|
||
|
|
||
|
6 (ocf::pacemaker:Dummy): Active node1
|
||
|
|
||
|
If -r/--inactive is also supplied:
|
||
|
|
||
|
6/10 (ocf::pacemaker:Dummy): Active node1
|
||
|
0/5 (ocf::heartbeat:Dummy): Active
|
||
|
|
||
|
Output for a group is like:
|
||
|
Resource Group: group1
|
||
|
18/20 (ocf::pacemaker:Dummy): Active node1
|
||
|
12/15 (ocf::heartbeat:Dummy): Active node1
|
||
|
|
||
|
If -n/--group-by-node is also supplied, the output of the node is like:
|
||
|
|
||
|
Node node1: online
|
||
|
24 (ocf::pacemaker:Dummy): Active
|
||
|
12 (ocf::heartbeat:Dummy): Active
|
||
|
|
||
|
diff --git a/include/crm/pengine/common.h b/include/crm/pengine/common.h
|
||
|
index c1901ef..ddca95d 100644
|
||
|
--- a/include/crm/pengine/common.h
|
||
|
+++ b/include/crm/pengine/common.h
|
||
|
@@ -98,6 +98,7 @@ enum pe_print_options {
|
||
|
pe_print_suppres_nl = 0x0200,
|
||
|
pe_print_xml = 0x0400,
|
||
|
pe_print_pending = 0x0800,
|
||
|
+ pe_print_brief = 0x1000,
|
||
|
};
|
||
|
/* *INDENT-ON* */
|
||
|
|
||
|
diff --git a/include/crm/pengine/internal.h b/include/crm/pengine/internal.h
|
||
|
index 46e63c4..072c0a9 100644
|
||
|
--- a/include/crm/pengine/internal.h
|
||
|
+++ b/include/crm/pengine/internal.h
|
||
|
@@ -265,4 +265,7 @@ gboolean is_baremetal_remote_node(node_t *node);
|
||
|
gboolean is_container_remote_node(node_t *node);
|
||
|
gboolean is_remote_node(node_t *node);
|
||
|
resource_t * rsc_contains_remote_node(pe_working_set_t * data_set, resource_t *rsc);
|
||
|
+
|
||
|
+void print_rscs_brief(GListPtr rsc_list, const char * pre_text, long options,
|
||
|
+ void * print_data, gboolean print_all);
|
||
|
#endif
|
||
|
diff --git a/lib/pengine/group.c b/lib/pengine/group.c
|
||
|
index 885486e..831376c 100644
|
||
|
--- a/lib/pengine/group.c
|
||
|
+++ b/lib/pengine/group.c
|
||
|
@@ -168,15 +168,20 @@ group_print(resource_t * rsc, const char *pre_text, long options, void *print_da
|
||
|
status_print("\n");
|
||
|
}
|
||
|
|
||
|
- for (; gIter != NULL; gIter = gIter->next) {
|
||
|
- resource_t *child_rsc = (resource_t *) gIter->data;
|
||
|
+ if (options & pe_print_brief) {
|
||
|
+ print_rscs_brief(rsc->children, child_text, options, print_data, TRUE);
|
||
|
|
||
|
- if (options & pe_print_html) {
|
||
|
- status_print("<li>\n");
|
||
|
- }
|
||
|
- child_rsc->fns->print(child_rsc, child_text, options, print_data);
|
||
|
- if (options & pe_print_html) {
|
||
|
- status_print("</li>\n");
|
||
|
+ } else {
|
||
|
+ for (; gIter != NULL; gIter = gIter->next) {
|
||
|
+ resource_t *child_rsc = (resource_t *) gIter->data;
|
||
|
+
|
||
|
+ if (options & pe_print_html) {
|
||
|
+ status_print("<li>\n");
|
||
|
+ }
|
||
|
+ child_rsc->fns->print(child_rsc, child_text, options, print_data);
|
||
|
+ if (options & pe_print_html) {
|
||
|
+ status_print("</li>\n");
|
||
|
+ }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
diff --git a/lib/pengine/native.c b/lib/pengine/native.c
|
||
|
index be95ba1..b223ab3 100644
|
||
|
--- a/lib/pengine/native.c
|
||
|
+++ b/lib/pengine/native.c
|
||
|
@@ -687,3 +687,160 @@ native_location(resource_t * rsc, GListPtr * list, gboolean current)
|
||
|
g_list_free(result);
|
||
|
return one;
|
||
|
}
|
||
|
+
|
||
|
+static void
|
||
|
+get_rscs_brief(GListPtr rsc_list, GHashTable * rsc_table, GHashTable * active_table)
|
||
|
+{
|
||
|
+ GListPtr gIter = rsc_list;
|
||
|
+
|
||
|
+ for (; gIter != NULL; gIter = gIter->next) {
|
||
|
+ resource_t *rsc = (resource_t *) gIter->data;
|
||
|
+
|
||
|
+ const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
|
||
|
+ const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
|
||
|
+
|
||
|
+ int offset = 0;
|
||
|
+ char buffer[LINE_MAX];
|
||
|
+
|
||
|
+ int *rsc_counter = NULL;
|
||
|
+ int *active_counter = NULL;
|
||
|
+
|
||
|
+ if (rsc->variant != pe_native) {
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", class);
|
||
|
+ if (safe_str_eq(class, "ocf")) {
|
||
|
+ const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
|
||
|
+ offset += snprintf(buffer + offset, LINE_MAX - offset, "::%s", prov);
|
||
|
+ }
|
||
|
+ offset += snprintf(buffer + offset, LINE_MAX - offset, ":%s", kind);
|
||
|
+
|
||
|
+ if (rsc_table) {
|
||
|
+ rsc_counter = g_hash_table_lookup(rsc_table, buffer);
|
||
|
+ if (rsc_counter == NULL) {
|
||
|
+ rsc_counter = calloc(1, sizeof(int));
|
||
|
+ *rsc_counter = 0;
|
||
|
+ g_hash_table_insert(rsc_table, strdup(buffer), rsc_counter);
|
||
|
+ }
|
||
|
+ (*rsc_counter)++;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (active_table) {
|
||
|
+ GListPtr gIter2 = rsc->running_on;
|
||
|
+
|
||
|
+ for (; gIter2 != NULL; gIter2 = gIter2->next) {
|
||
|
+ node_t *node = (node_t *) gIter2->data;
|
||
|
+ GHashTable *node_table = NULL;
|
||
|
+
|
||
|
+ if (node->details->unclean == FALSE && node->details->online == FALSE) {
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ node_table = g_hash_table_lookup(active_table, node->details->uname);
|
||
|
+ if (node_table == NULL) {
|
||
|
+ node_table = g_hash_table_new_full(crm_str_hash, g_str_equal, free, free);
|
||
|
+ g_hash_table_insert(active_table, strdup(node->details->uname), node_table);
|
||
|
+ }
|
||
|
+
|
||
|
+ active_counter = g_hash_table_lookup(node_table, buffer);
|
||
|
+ if (active_counter == NULL) {
|
||
|
+ active_counter = calloc(1, sizeof(int));
|
||
|
+ *active_counter = 0;
|
||
|
+ g_hash_table_insert(node_table, strdup(buffer), active_counter);
|
||
|
+ }
|
||
|
+ (*active_counter)++;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+destroy_node_table(gpointer data)
|
||
|
+{
|
||
|
+ GHashTable *node_table = data;
|
||
|
+
|
||
|
+ if (node_table) {
|
||
|
+ g_hash_table_destroy(node_table);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+print_rscs_brief(GListPtr rsc_list, const char *pre_text, long options,
|
||
|
+ void *print_data, gboolean print_all)
|
||
|
+{
|
||
|
+ GHashTable *rsc_table = g_hash_table_new_full(crm_str_hash, g_str_equal, free, free);
|
||
|
+ GHashTable *active_table = g_hash_table_new_full(crm_str_hash, g_str_equal,
|
||
|
+ free, destroy_node_table);
|
||
|
+ GHashTableIter hash_iter;
|
||
|
+ char *type = NULL;
|
||
|
+ int *rsc_counter = NULL;
|
||
|
+
|
||
|
+ get_rscs_brief(rsc_list, rsc_table, active_table);
|
||
|
+
|
||
|
+ g_hash_table_iter_init(&hash_iter, rsc_table);
|
||
|
+ while (g_hash_table_iter_next(&hash_iter, (gpointer *)&type, (gpointer *)&rsc_counter)) {
|
||
|
+ GHashTableIter hash_iter2;
|
||
|
+ char *node_name = NULL;
|
||
|
+ GHashTable *node_table = NULL;
|
||
|
+ int active_counter_all = 0;
|
||
|
+
|
||
|
+ g_hash_table_iter_init(&hash_iter2, active_table);
|
||
|
+ while (g_hash_table_iter_next(&hash_iter2, (gpointer *)&node_name, (gpointer *)&node_table)) {
|
||
|
+ int *active_counter = g_hash_table_lookup(node_table, type);
|
||
|
+
|
||
|
+ if (active_counter == NULL || *active_counter == 0) {
|
||
|
+ continue;
|
||
|
+
|
||
|
+ } else {
|
||
|
+ active_counter_all += *active_counter;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (options & pe_print_rsconly) {
|
||
|
+ node_name = NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (options & pe_print_html) {
|
||
|
+ status_print("<li>\n");
|
||
|
+ }
|
||
|
+
|
||
|
+ if (print_all) {
|
||
|
+ status_print("%s%d/%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
|
||
|
+ active_counter ? *active_counter : 0,
|
||
|
+ rsc_counter ? *rsc_counter : 0, type,
|
||
|
+ active_counter && (*active_counter > 0) && node_name ? node_name : "");
|
||
|
+ } else {
|
||
|
+ status_print("%s%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
|
||
|
+ active_counter ? *active_counter : 0, type,
|
||
|
+ active_counter && (*active_counter > 0) && node_name ? node_name : "");
|
||
|
+ }
|
||
|
+
|
||
|
+ if (options & pe_print_html) {
|
||
|
+ status_print("</li>\n");
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (print_all && active_counter_all == 0) {
|
||
|
+ if (options & pe_print_html) {
|
||
|
+ status_print("<li>\n");
|
||
|
+ }
|
||
|
+
|
||
|
+ status_print("%s%d/%d\t(%s):\tActive\n", pre_text ? pre_text : "",
|
||
|
+ active_counter_all,
|
||
|
+ rsc_counter ? *rsc_counter : 0, type);
|
||
|
+
|
||
|
+ if (options & pe_print_html) {
|
||
|
+ status_print("</li>\n");
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (rsc_table) {
|
||
|
+ g_hash_table_destroy(rsc_table);
|
||
|
+ rsc_table = NULL;
|
||
|
+ }
|
||
|
+ if (active_table) {
|
||
|
+ g_hash_table_destroy(active_table);
|
||
|
+ active_table = NULL;
|
||
|
+ }
|
||
|
+}
|
||
|
diff --git a/tools/crm_mon.c b/tools/crm_mon.c
|
||
|
index 746094f..a69a4fe 100644
|
||
|
--- a/tools/crm_mon.c
|
||
|
+++ b/tools/crm_mon.c
|
||
|
@@ -97,6 +97,7 @@ gboolean print_tickets = FALSE;
|
||
|
gboolean watch_fencing = FALSE;
|
||
|
gboolean hide_headers = FALSE;
|
||
|
gboolean print_pending = FALSE;
|
||
|
+gboolean print_brief = FALSE;
|
||
|
|
||
|
/* FIXME allow, detect, and correctly interpret glob pattern or regex? */
|
||
|
const char *print_neg_location_prefix;
|
||
|
@@ -342,6 +343,7 @@ static struct crm_option long_options[] = {
|
||
|
{"show-node-attributes", 0, 0, 'A', "Display node attributes" },
|
||
|
{"hide-headers", 0, 0, 'D', "\tHide all headers" },
|
||
|
{"pending", 0, 0, 'j', "\t\tDisplay pending state if 'record-pending' is enabled" },
|
||
|
+ {"brief", 0, 0, 'b', "\t\tBrief output" },
|
||
|
|
||
|
{"-spacer-", 1, 0, '-', "\nAdditional Options:"},
|
||
|
{"interval", 1, 0, 'i', "\tUpdate frequency in seconds" },
|
||
|
@@ -454,6 +456,9 @@ detect_user_input(GIOChannel *channel, GIOCondition condition, gpointer unused)
|
||
|
case 'j':
|
||
|
print_pending = ! print_pending;
|
||
|
break;
|
||
|
+ case 'b':
|
||
|
+ print_brief = ! print_brief;
|
||
|
+ break;
|
||
|
case '?':
|
||
|
config_mode = TRUE;
|
||
|
break;
|
||
|
@@ -478,6 +483,7 @@ detect_user_input(GIOChannel *channel, GIOCondition condition, gpointer unused)
|
||
|
print_as("%c L: \t%s\n", print_neg_location_prefix ? '*': ' ', get_option_desc('L'));
|
||
|
print_as("%c D: \t%s\n", hide_headers ? '*': ' ', get_option_desc('D'));
|
||
|
print_as("%c j: \t%s\n", print_pending ? '*': ' ', get_option_desc('j'));
|
||
|
+ print_as("%c b: \t%s\n", print_brief ? '*': ' ', get_option_desc('b'));
|
||
|
print_as("\n");
|
||
|
print_as("Toggle fields via field letter, type any other key to return");
|
||
|
}
|
||
|
@@ -562,6 +568,9 @@ main(int argc, char **argv)
|
||
|
case 'D':
|
||
|
hide_headers = TRUE;
|
||
|
break;
|
||
|
+ case 'b':
|
||
|
+ print_brief = TRUE;
|
||
|
+ break;
|
||
|
case 'c':
|
||
|
print_tickets = TRUE;
|
||
|
break;
|
||
|
@@ -1326,7 +1335,11 @@ print_status(pe_working_set_t * data_set)
|
||
|
print_as("Node %s (%s): %s\n", node_name, node->details->id, node_mode);
|
||
|
}
|
||
|
|
||
|
- if (group_by_node) {
|
||
|
+ if (print_brief && group_by_node) {
|
||
|
+ print_rscs_brief(node->details->running_rsc, "\t", print_opts | pe_print_rsconly,
|
||
|
+ stdout, FALSE);
|
||
|
+
|
||
|
+ } else if (group_by_node) {
|
||
|
GListPtr gIter2 = NULL;
|
||
|
|
||
|
for (gIter2 = node->details->running_rsc; gIter2 != NULL; gIter2 = gIter2->next) {
|
||
|
@@ -1368,12 +1381,24 @@ print_status(pe_working_set_t * data_set)
|
||
|
|
||
|
if (group_by_node == FALSE || inactive_resources) {
|
||
|
print_as("\n");
|
||
|
+
|
||
|
+ if (print_brief && group_by_node == FALSE) {
|
||
|
+ print_opts |= pe_print_brief;
|
||
|
+ print_rscs_brief(data_set->resources, NULL, print_opts, stdout,
|
||
|
+ inactive_resources);
|
||
|
+ }
|
||
|
+
|
||
|
for (gIter = data_set->resources; gIter != NULL; gIter = gIter->next) {
|
||
|
resource_t *rsc = (resource_t *) gIter->data;
|
||
|
|
||
|
gboolean is_active = rsc->fns->active(rsc, TRUE);
|
||
|
gboolean partially_active = rsc->fns->active(rsc, FALSE);
|
||
|
|
||
|
+ if (print_brief && group_by_node == FALSE
|
||
|
+ && rsc->variant == pe_native) {
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
if (is_set(rsc->flags, pe_rsc_orphan) && is_active == FALSE) {
|
||
|
continue;
|
||
|
|
||
|
@@ -1740,7 +1765,13 @@ print_html_status(pe_working_set_t * data_set, const char *filename, gboolean we
|
||
|
fprintf(stream, "Node: %s (%s): %s", node->details->uname, node->details->id,
|
||
|
"<font color=\"red\">OFFLINE</font>\n");
|
||
|
}
|
||
|
- if (group_by_node) {
|
||
|
+ if (print_brief && group_by_node) {
|
||
|
+ fprintf(stream, "<ul>\n");
|
||
|
+ print_rscs_brief(node->details->running_rsc, NULL, print_opts | pe_print_rsconly,
|
||
|
+ stream, FALSE);
|
||
|
+ fprintf(stream, "</ul>\n");
|
||
|
+
|
||
|
+ } else if (group_by_node) {
|
||
|
GListPtr lpc2 = NULL;
|
||
|
|
||
|
fprintf(stream, "<ul>\n");
|
||
|
@@ -1765,11 +1796,22 @@ print_html_status(pe_working_set_t * data_set, const char *filename, gboolean we
|
||
|
}
|
||
|
|
||
|
if (group_by_node == FALSE || inactive_resources) {
|
||
|
+ if (print_brief && group_by_node == FALSE) {
|
||
|
+ print_opts |= pe_print_brief;
|
||
|
+ print_rscs_brief(data_set->resources, NULL, print_opts, stream,
|
||
|
+ inactive_resources);
|
||
|
+ }
|
||
|
+
|
||
|
for (gIter = data_set->resources; gIter != NULL; gIter = gIter->next) {
|
||
|
resource_t *rsc = (resource_t *) gIter->data;
|
||
|
gboolean is_active = rsc->fns->active(rsc, TRUE);
|
||
|
gboolean partially_active = rsc->fns->active(rsc, FALSE);
|
||
|
|
||
|
+ if (print_brief && group_by_node == FALSE
|
||
|
+ && rsc->variant == pe_native) {
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
if (is_set(rsc->flags, pe_rsc_orphan) && is_active == FALSE) {
|
||
|
continue;
|
||
|
|