diff --git a/cts/cli/regression.tools.exp b/cts/cli/regression.tools.exp index 7166714..221730d 100644 --- a/cts/cli/regression.tools.exp +++ b/cts/cli/regression.tools.exp @@ -2001,12 +2001,13 @@ WARNING: Creating rsc_location constraint 'cli-ban-dummy-on-node1' with a score =#=#=#= End test: Ban dummy from node1 - OK (0) =#=#=#= * Passed: crm_resource - Ban dummy from node1 =#=#=#= Begin test: Show where a resource is running =#=#=#= -resource dummy is running on: node1 +resource dummy is running on: node1 =#=#=#= End test: Show where a resource is running - OK (0) =#=#=#= * Passed: crm_resource - Show where a resource is running =#=#=#= Begin test: Show constraints on a resource =#=#=#= -* dummy - : Node node1 (score=-INFINITY, id=cli-ban-dummy-on-node1) +dummy: + * Locations: + * Node node1 (score=-INFINITY, id=cli-ban-dummy-on-node1) =#=#=#= End test: Show constraints on a resource - OK (0) =#=#=#= * Passed: crm_resource - Show constraints on a resource =#=#=#= Begin test: Ban dummy from node2 =#=#=#= diff --git a/include/pcmki/pcmki_output.h b/include/pcmki/pcmki_output.h index 2b750fb..0faef35 100644 --- a/include/pcmki/pcmki_output.h +++ b/include/pcmki/pcmki_output.h @@ -21,6 +21,13 @@ extern pcmk__supported_format_t pcmk__out_formats[]; int pcmk__out_prologue(pcmk__output_t **out, xmlNodePtr *xml); void pcmk__out_epilogue(pcmk__output_t *out, xmlNodePtr *xml, int retval); +/* This function registers only the formatted output messages that are a part + * of libpacemaker. It is not to be confused with pcmk__register_messages, + * which is a part of formatted output support and registers a whole table of + * messages at a time. + */ +void pcmk__register_lib_messages(pcmk__output_t *out); + #ifdef __cplusplus } #endif diff --git a/lib/pacemaker/pcmk_output.c b/lib/pacemaker/pcmk_output.c index adf4c34..306e561 100644 --- a/lib/pacemaker/pcmk_output.c +++ b/lib/pacemaker/pcmk_output.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include pcmk__supported_format_t pcmk__out_formats[] = { PCMK__SUPPORTED_FORMAT_XML, @@ -46,3 +46,329 @@ pcmk__out_epilogue(pcmk__output_t *out, xmlNodePtr *xml, int retval) { pcmk__output_free(out); } + +PCMK__OUTPUT_ARGS("colocations-list", "pe_resource_t *", "gboolean", "gboolean") +static int colocations_list(pcmk__output_t *out, va_list args) { + pe_resource_t *rsc = va_arg(args, pe_resource_t *); + gboolean dependents = va_arg(args, gboolean); + gboolean recursive = va_arg(args, gboolean); + + GListPtr lpc = NULL; + GListPtr list = rsc->rsc_cons; + bool printed_header = false; + + if (dependents) { + list = rsc->rsc_cons_lhs; + } + + if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) { + return pcmk_rc_no_output; + } + + pe__set_resource_flags(rsc, pe_rsc_allocating); + for (lpc = list; lpc != NULL; lpc = lpc->next) { + rsc_colocation_t *cons = (rsc_colocation_t *) lpc->data; + + char *score = NULL; + pe_resource_t *peer = cons->rsc_rh; + + if (dependents) { + peer = cons->rsc_lh; + } + + if (pcmk_is_set(peer->flags, pe_rsc_allocating)) { + if (dependents == FALSE) { + if (!printed_header) { + out->begin_list(out, NULL, NULL, "Colocations"); + printed_header = true; + } + + out->list_item(out, NULL, "%s (id=%s - loop)", peer->id, cons->id); + } + continue; + } + + if (dependents && recursive) { + if (!printed_header) { + out->begin_list(out, NULL, NULL, "Colocations"); + printed_header = true; + } + + out->message(out, "colocations-list", rsc, dependents, recursive); + } + + if (!printed_header) { + out->begin_list(out, NULL, NULL, "Colocations"); + printed_header = true; + } + + score = score2char(cons->score); + if (cons->role_rh > RSC_ROLE_STARTED) { + out->list_item(out, NULL, "%s (score=%s, %s role=%s, id=%s", + peer->id, score, dependents ? "needs" : "with", + role2text(cons->role_rh), cons->id); + } else { + out->list_item(out, NULL, "%s (score=%s, id=%s", + peer->id, score, cons->id); + } + + free(score); + out->message(out, "locations-list", peer); + + if (!dependents && recursive) { + out->message(out, "colocations-list", rsc, dependents, recursive); + } + } + + if (printed_header) { + out->end_list(out); + } + + return pcmk_rc_no_output; +} + +PCMK__OUTPUT_ARGS("colocations-list", "pe_resource_t *", "gboolean", "gboolean") +static int colocations_list_xml(pcmk__output_t *out, va_list args) { + pe_resource_t *rsc = va_arg(args, pe_resource_t *); + gboolean dependents = va_arg(args, gboolean); + gboolean recursive = va_arg(args, gboolean); + + GListPtr lpc = NULL; + GListPtr list = rsc->rsc_cons; + bool printed_header = false; + + if (dependents) { + list = rsc->rsc_cons_lhs; + } + + if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) { + return pcmk_rc_ok; + } + + pe__set_resource_flags(rsc, pe_rsc_allocating); + for (lpc = list; lpc != NULL; lpc = lpc->next) { + rsc_colocation_t *cons = (rsc_colocation_t *) lpc->data; + pe_resource_t *peer = cons->rsc_rh; + char *score = NULL; + + if (dependents) { + peer = cons->rsc_lh; + } + + if (pcmk_is_set(peer->flags, pe_rsc_allocating)) { + if (dependents == FALSE) { + xmlNodePtr node; + + if (!printed_header) { + pcmk__output_xml_create_parent(out, "colocations"); + printed_header = true; + } + + node = pcmk__output_create_xml_node(out, "colocation"); + xmlSetProp(node, (pcmkXmlStr) "peer", (pcmkXmlStr) peer->id); + xmlSetProp(node, (pcmkXmlStr) "id", (pcmkXmlStr) cons->id); + } + continue; + } + + if (dependents && recursive) { + if (!printed_header) { + pcmk__output_xml_create_parent(out, "colocations"); + printed_header = true; + } + + out->message(out, "colocations-list", rsc, dependents, recursive); + } + + if (!printed_header) { + pcmk__output_xml_create_parent(out, "colocations"); + printed_header = true; + } + + score = score2char(cons->score); + if (cons->role_rh > RSC_ROLE_STARTED) { + xmlNodePtr node = pcmk__output_create_xml_node(out, "colocation"); + xmlSetProp(node, (pcmkXmlStr) "peer", (pcmkXmlStr) peer->id); + xmlSetProp(node, (pcmkXmlStr) "id", (pcmkXmlStr) cons->id); + xmlSetProp(node, (pcmkXmlStr) "score", (pcmkXmlStr) score); + xmlSetProp(node, (pcmkXmlStr) "dependents", + (pcmkXmlStr) (dependents ? "needs" : "with")); + xmlSetProp(node, (pcmkXmlStr) "role", (pcmkXmlStr) role2text(cons->role_rh)); + } else { + xmlNodePtr node = pcmk__output_create_xml_node(out, "colocation"); + xmlSetProp(node, (pcmkXmlStr) "peer", (pcmkXmlStr) peer->id); + xmlSetProp(node, (pcmkXmlStr) "id", (pcmkXmlStr) cons->id); + xmlSetProp(node, (pcmkXmlStr) "score", (pcmkXmlStr) score); + } + + free(score); + out->message(out, "locations-list", peer); + + if (!dependents && recursive) { + out->message(out, "colocations-list", rsc, dependents, recursive); + } + } + + if (printed_header) { + pcmk__output_xml_pop_parent(out); + } + + return pcmk_rc_ok; +} + +PCMK__OUTPUT_ARGS("locations-list", "pe_resource_t *") +static int locations_list(pcmk__output_t *out, va_list args) { + pe_resource_t *rsc G_GNUC_UNUSED = va_arg(args, pe_resource_t *); + + GListPtr lpc = NULL; + GListPtr list = rsc->rsc_location; + + out->begin_list(out, NULL, NULL, "Locations"); + + for (lpc = list; lpc != NULL; lpc = lpc->next) { + pe__location_t *cons = lpc->data; + + GListPtr lpc2 = NULL; + + for (lpc2 = cons->node_list_rh; lpc2 != NULL; lpc2 = lpc2->next) { + pe_node_t *node = (pe_node_t *) lpc2->data; + char *score = score2char(node->weight); + + out->list_item(out, NULL, "Node %s (score=%s, id=%s)", + node->details->uname, score, cons->id); + free(score); + } + } + + out->end_list(out); + + return pcmk_rc_ok; +} + +PCMK__OUTPUT_ARGS("locations-list", "pe_resource_t *") +static int locations_list_xml(pcmk__output_t *out, va_list args) { + pe_resource_t *rsc = va_arg(args, pe_resource_t *); + + GListPtr lpc = NULL; + GListPtr list = rsc->rsc_location; + + pcmk__output_xml_create_parent(out, "locations"); + + for (lpc = list; lpc != NULL; lpc = lpc->next) { + pe__location_t *cons = lpc->data; + + GListPtr lpc2 = NULL; + + for (lpc2 = cons->node_list_rh; lpc2 != NULL; lpc2 = lpc2->next) { + pe_node_t *node = (pe_node_t *) lpc2->data; + char *score = score2char(node->weight); + + xmlNodePtr xml_node = pcmk__output_create_xml_node(out, "location"); + xmlSetProp(xml_node, (pcmkXmlStr) "host", (pcmkXmlStr) node->details->uname); + xmlSetProp(xml_node, (pcmkXmlStr) "id", (pcmkXmlStr) cons->id); + xmlSetProp(xml_node, (pcmkXmlStr) "score", (pcmkXmlStr) score); + + free(score); + } + } + + pcmk__output_xml_pop_parent(out); + + return pcmk_rc_ok; +} + +PCMK__OUTPUT_ARGS("stacks-constraints", "pe_resource_t *", "pe_working_set_t *", "gboolean") +static int +stacks_and_constraints(pcmk__output_t *out, va_list args) { + pe_resource_t *rsc G_GNUC_UNUSED = va_arg(args, pe_resource_t *); + pe_working_set_t *data_set G_GNUC_UNUSED = va_arg(args, pe_working_set_t *); + gboolean recursive G_GNUC_UNUSED = va_arg(args, gboolean); + + GListPtr lpc = NULL; + xmlNode *cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, + data_set->input); + + unpack_constraints(cib_constraints, data_set); + + // Constraints apply to group/clone, not member/instance + rsc = uber_parent(rsc); + + for (lpc = data_set->resources; lpc != NULL; lpc = lpc->next) { + pe_resource_t *r = (pe_resource_t *) lpc->data; + + pe__clear_resource_flags(r, pe_rsc_allocating); + } + + out->message(out, "colocations-list", rsc, TRUE, recursive); + + out->begin_list(out, NULL, NULL, "%s", rsc->id); + out->message(out, "locations-list", rsc); + out->end_list(out); + + for (lpc = data_set->resources; lpc != NULL; lpc = lpc->next) { + pe_resource_t *r = (pe_resource_t *) lpc->data; + + pe__clear_resource_flags(r, pe_rsc_allocating); + } + + out->message(out, "colocations-list", rsc, FALSE, recursive); + return pcmk_rc_ok; +} + +PCMK__OUTPUT_ARGS("stacks-constraints", "pe_resource_t *", "pe_working_set_t *", "gboolean") +static int +stacks_and_constraints_xml(pcmk__output_t *out, va_list args) { + pe_resource_t *rsc = va_arg(args, pe_resource_t *); + pe_working_set_t *data_set = va_arg(args, pe_working_set_t *); + gboolean recursive = va_arg(args, gboolean); + + GListPtr lpc = NULL; + xmlNodePtr node = NULL; + xmlNode *cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, + data_set->input); + + unpack_constraints(cib_constraints, data_set); + + // Constraints apply to group/clone, not member/instance + rsc = uber_parent(rsc); + + for (lpc = data_set->resources; lpc != NULL; lpc = lpc->next) { + pe_resource_t *r = (pe_resource_t *) lpc->data; + + pe__clear_resource_flags(r, pe_rsc_allocating); + } + + pcmk__output_xml_create_parent(out, "constraints"); + + out->message(out, "colocations-list", rsc, TRUE, recursive); + + node = pcmk__output_xml_create_parent(out, "resource"); + xmlSetProp(node, (pcmkXmlStr) "id", (pcmkXmlStr) rsc->id); + out->message(out, "locations-list", rsc); + pcmk__output_xml_pop_parent(out); + + for (lpc = data_set->resources; lpc != NULL; lpc = lpc->next) { + pe_resource_t *r = (pe_resource_t *) lpc->data; + + pe__clear_resource_flags(r, pe_rsc_allocating); + } + + out->message(out, "colocations-list", rsc, FALSE, recursive); + return pcmk_rc_ok; +} + +static pcmk__message_entry_t fmt_functions[] = { + { "colocations-list", "default", colocations_list }, + { "colocations-list", "xml", colocations_list_xml }, + { "locations-list", "default", locations_list }, + { "locations-list", "xml", locations_list_xml }, + { "stacks-constraints", "default", stacks_and_constraints }, + { "stacks-constraints", "xml", stacks_and_constraints_xml }, + + { NULL, NULL, NULL } +}; + +void +pcmk__register_lib_messages(pcmk__output_t *out) { + pcmk__register_messages(out, fmt_functions); +} diff --git a/tools/crm_resource.c b/tools/crm_resource.c index 9acb955..bfa74eb 100644 --- a/tools/crm_resource.c +++ b/tools/crm_resource.c @@ -1194,38 +1194,6 @@ list_providers(pcmk__output_t *out, const char *agent_spec, crm_exit_t *exit_cod return rc; } -static void -list_stacks_and_constraints(pcmk__output_t *out, pe_resource_t *rsc, bool recursive) -{ - GListPtr lpc = NULL; - xmlNode *cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, - data_set->input); - - unpack_constraints(cib_constraints, data_set); - - // Constraints apply to group/clone, not member/instance - rsc = uber_parent(rsc); - - for (lpc = data_set->resources; lpc != NULL; lpc = lpc->next) { - pe_resource_t *r = (pe_resource_t *) lpc->data; - - pe__clear_resource_flags(r, pe_rsc_allocating); - } - - cli_resource_print_colocation(out, rsc, TRUE, recursive, 1); - - fprintf(stdout, "* %s\n", rsc->id); - cli_resource_print_location(out, rsc, NULL); - - for (lpc = data_set->resources; lpc != NULL; lpc = lpc->next) { - pe_resource_t *r = (pe_resource_t *) lpc->data; - - pe__clear_resource_flags(r, pe_rsc_allocating); - } - - cli_resource_print_colocation(out, rsc, FALSE, recursive, 1); -} - static int populate_working_set(xmlNodePtr *cib_xml_copy) { @@ -1629,7 +1597,8 @@ main(int argc, char **argv) pcmk__force_args(context, &error, "%s --xml-substitute", g_get_prgname()); } } else if (pcmk__str_eq(args->output_ty, "text", pcmk__str_null_matches)) { - if (options.rsc_cmd == cmd_list_resources) { + if (options.rsc_cmd == cmd_colocations || options.rsc_cmd == cmd_colocations_deep || + options.rsc_cmd == cmd_list_resources) { pcmk__force_args(context, &error, "%s --text-fancy", g_get_prgname()); } } @@ -1637,6 +1606,7 @@ main(int argc, char **argv) pe__register_messages(out); crm_resource_register_messages(out); lrmd__register_messages(out); + pcmk__register_lib_messages(out); if (args->version) { out->version(out, false); @@ -1804,11 +1774,11 @@ main(int argc, char **argv) break; case cmd_colocations: - list_stacks_and_constraints(out, rsc, false); + rc = out->message(out, "stacks-constraints", rsc, data_set, false); break; case cmd_colocations_deep: - list_stacks_and_constraints(out, rsc, true); + rc = out->message(out, "stacks-constraints", rsc, data_set, true); break; case cmd_cts: diff --git a/tools/crm_resource.h b/tools/crm_resource.h index 6de2457..5bfadb7 100644 --- a/tools/crm_resource.h +++ b/tools/crm_resource.h @@ -53,10 +53,6 @@ int cli_resource_clear_all_expired(xmlNode *root, cib_t *cib_conn, int cib_optio void cli_resource_print_cts(pcmk__output_t *out, pe_resource_t * rsc); void cli_resource_print_raw(pcmk__output_t *out, pe_resource_t * rsc); void cli_resource_print_cts_constraints(pcmk__output_t *out, pe_working_set_t * data_set); -void cli_resource_print_location(pcmk__output_t *out, pe_resource_t * rsc, - const char *prefix); -void cli_resource_print_colocation(pcmk__output_t *out, pe_resource_t * rsc, - bool dependents, bool recursive, int offset); int cli_resource_print(pcmk__output_t *out, pe_resource_t *rsc, pe_working_set_t *data_set, bool expanded); diff --git a/tools/crm_resource_print.c b/tools/crm_resource_print.c index 5ff3e9b..6303863 100644 --- a/tools/crm_resource_print.c +++ b/tools/crm_resource_print.c @@ -108,97 +108,6 @@ cli_resource_print_operations(pcmk__output_t *out, const char *rsc_id, return rc; } -void -cli_resource_print_location(pcmk__output_t *out, pe_resource_t * rsc, const char *prefix) -{ - GListPtr lpc = NULL; - GListPtr list = rsc->rsc_location; - int offset = 0; - - if (prefix) { - offset = strlen(prefix) - 2; - } - - for (lpc = list; lpc != NULL; lpc = lpc->next) { - pe__location_t *cons = lpc->data; - - GListPtr lpc2 = NULL; - - for (lpc2 = cons->node_list_rh; lpc2 != NULL; lpc2 = lpc2->next) { - pe_node_t *node = (pe_node_t *) lpc2->data; - char *score = score2char(node->weight); - - fprintf(stdout, "%s: Node %-*s (score=%s, id=%s)\n", - prefix ? prefix : " ", 71 - offset, node->details->uname, score, cons->id); - free(score); - } - } -} - -void -cli_resource_print_colocation(pcmk__output_t *out, pe_resource_t * rsc, - bool dependents, bool recursive, int offset) -{ - char *prefix = NULL; - GListPtr lpc = NULL; - GListPtr list = rsc->rsc_cons; - - prefix = calloc(1, (offset * 4) + 1); - memset(prefix, ' ', offset * 4); - - if (dependents) { - list = rsc->rsc_cons_lhs; - } - - if (pcmk_is_set(rsc->flags, pe_rsc_allocating)) { - /* Break colocation loops */ - printf("loop %s\n", rsc->id); - free(prefix); - return; - } - - pe__set_resource_flags(rsc, pe_rsc_allocating); - for (lpc = list; lpc != NULL; lpc = lpc->next) { - rsc_colocation_t *cons = (rsc_colocation_t *) lpc->data; - - char *score = NULL; - pe_resource_t *peer = cons->rsc_rh; - - if (dependents) { - peer = cons->rsc_lh; - } - - if (pcmk_is_set(peer->flags, pe_rsc_allocating)) { - if (dependents == FALSE) { - fprintf(stdout, "%s%-*s (id=%s - loop)\n", prefix, 80 - (4 * offset), peer->id, - cons->id); - } - continue; - } - - if (dependents && recursive) { - cli_resource_print_colocation(out, peer, dependents, recursive, offset + 1); - } - - score = score2char(cons->score); - if (cons->role_rh > RSC_ROLE_STARTED) { - fprintf(stdout, "%s%-*s (score=%s, %s role=%s, id=%s)\n", prefix, 80 - (4 * offset), - peer->id, score, dependents ? "needs" : "with", role2text(cons->role_rh), - cons->id); - } else { - fprintf(stdout, "%s%-*s (score=%s, id=%s)\n", prefix, 80 - (4 * offset), - peer->id, score, cons->id); - } - cli_resource_print_location(out, peer, prefix); - free(score); - - if (!dependents && recursive) { - cli_resource_print_colocation(out, peer, dependents, recursive, offset + 1); - } - } - free(prefix); -} - // \return Standard Pacemaker return code int cli_resource_print(pcmk__output_t *out, pe_resource_t *rsc,