commit 9584fca04fc5b7a72dba09cc44fcfbe917325737 Author: Gao,Yan 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("
  • \n"); - } - child_rsc->fns->print(child_rsc, child_text, options, print_data); - if (options & pe_print_html) { - status_print("
  • \n"); + } else { + for (; gIter != NULL; gIter = gIter->next) { + resource_t *child_rsc = (resource_t *) gIter->data; + + if (options & pe_print_html) { + status_print("
  • \n"); + } + child_rsc->fns->print(child_rsc, child_text, options, print_data); + if (options & pe_print_html) { + status_print("
  • \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("
  • \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("
  • \n"); + } + } + + if (print_all && active_counter_all == 0) { + if (options & pe_print_html) { + status_print("
  • \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("
  • \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, "OFFLINE\n"); } - if (group_by_node) { + if (print_brief && group_by_node) { + fprintf(stream, "\n"); + + } else if (group_by_node) { GListPtr lpc2 = NULL; fprintf(stream, "