diff --git a/lib/pacemaker/pcmk_fence.c b/lib/pacemaker/pcmk_fence.c index 7beedff3f1..d591379922 100644 --- a/lib/pacemaker/pcmk_fence.c +++ b/lib/pacemaker/pcmk_fence.c @@ -1,508 +1,522 @@ /* * Copyright 2009-2020 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include #include #include #include #include #include static const int st_opts = st_opt_sync_call | st_opt_allow_suicide; static GMainLoop *mainloop = NULL; static struct { stonith_t *st; const char *target; const char *action; char *name; unsigned int timeout; unsigned int tolerance; int delay; int rc; } async_fence_data; static int handle_level(stonith_t *st, char *target, int fence_level, stonith_key_value_t *devices, bool added) { char *node = NULL; char *pattern = NULL; char *name = NULL; char *value = NULL; int rc = pcmk_rc_ok; if (target == NULL) { // Not really possible, but makes static analysis happy return EINVAL; } /* Determine if targeting by attribute, node name pattern or node name */ value = strchr(target, '='); if (value != NULL) { name = target; *value++ = '\0'; } else if (*target == '@') { pattern = target + 1; } else { node = target; } /* Register or unregister level as appropriate */ if (added) { rc = st->cmds->register_level_full(st, st_opts, node, pattern, name, value, fence_level, devices); } else { rc = st->cmds->remove_level_full(st, st_opts, node, pattern, name, value, fence_level); } return pcmk_legacy2rc(rc); } static void notify_callback(stonith_t * st, stonith_event_t * e) { if (e->result != pcmk_ok) { return; } if (pcmk__str_eq(async_fence_data.target, e->target, pcmk__str_casei) && pcmk__str_eq(async_fence_data.action, e->action, pcmk__str_casei)) { async_fence_data.rc = e->result; g_main_loop_quit(mainloop); } } static void fence_callback(stonith_t * stonith, stonith_callback_data_t * data) { async_fence_data.rc = data->rc; g_main_loop_quit(mainloop); } static gboolean async_fence_helper(gpointer user_data) { stonith_t *st = async_fence_data.st; int call_id = 0; int rc = stonith_api_connect_retry(st, async_fence_data.name, 10); if (rc != pcmk_ok) { fprintf(stderr, "Could not connect to fencer: %s\n", pcmk_strerror(rc)); g_main_loop_quit(mainloop); return TRUE; } st->cmds->register_notification(st, T_STONITH_NOTIFY_FENCE, notify_callback); call_id = st->cmds->fence_with_delay(st, st_opt_allow_suicide, async_fence_data.target, async_fence_data.action, async_fence_data.timeout/1000, async_fence_data.tolerance/1000, async_fence_data.delay); if (call_id < 0) { g_main_loop_quit(mainloop); return TRUE; } st->cmds->register_callback(st, call_id, async_fence_data.timeout/1000, st_opt_timeout_updates, NULL, "callback", fence_callback); return TRUE; } int pcmk__fence_action(stonith_t *st, const char *target, const char *action, const char *name, unsigned int timeout, unsigned int tolerance, int delay) { crm_trigger_t *trig; async_fence_data.st = st; async_fence_data.name = strdup(name); async_fence_data.target = target; async_fence_data.action = action; async_fence_data.timeout = timeout; async_fence_data.tolerance = tolerance; async_fence_data.delay = delay; async_fence_data.rc = pcmk_err_generic; trig = mainloop_add_trigger(G_PRIORITY_HIGH, async_fence_helper, NULL); mainloop_set_trigger(trig); mainloop = g_main_loop_new(NULL, FALSE); g_main_loop_run(mainloop); free(async_fence_data.name); return pcmk_legacy2rc(async_fence_data.rc); } #ifdef BUILD_PUBLIC_LIBPACEMAKER int pcmk_fence_action(stonith_t *st, const char *target, const char *action, const char *name, unsigned int timeout, unsigned int tolerance, int delay) { return pcmk__fence_action(st, target, action, name, timeout, tolerance, delay); } #endif int pcmk__fence_history(pcmk__output_t *out, stonith_t *st, char *target, unsigned int timeout, int verbose, bool broadcast, bool cleanup) { stonith_history_t *history = NULL, *hp, *latest = NULL; int rc = pcmk_rc_ok; int opts = 0; if (!out->is_quiet(out)) { if (cleanup) { out->info(out, "cleaning up fencing-history%s%s", target ? " for node " : "", target ? target : ""); } if (broadcast) { out->info(out, "gather fencing-history from all nodes"); } } stonith__set_call_options(opts, target, st_opts); if (cleanup) { stonith__set_call_options(opts, target, st_opt_cleanup); } if (broadcast) { stonith__set_call_options(opts, target, st_opt_broadcast); } rc = st->cmds->history(st, opts, pcmk__str_eq(target, "*", pcmk__str_none)? NULL : target, &history, timeout/1000); if (cleanup) { // Cleanup doesn't return a history list stonith_history_free(history); return pcmk_legacy2rc(rc); } out->begin_list(out, "event", "events", "Fencing history"); history = stonith__sort_history(history); for (hp = history; hp; hp = hp->next) { if (hp->state == st_done) { latest = hp; } if (out->is_quiet(out) || !verbose) { continue; } out->message(out, "stonith-event", hp, 1, stonith__later_succeeded(hp, history)); out->increment_list(out); } if (latest) { if (out->is_quiet(out)) { out->info(out, "%lld", (long long) latest->completed); } else if (!verbose) { // already printed if verbose out->message(out, "stonith-event", latest, 0, FALSE); out->increment_list(out); } } out->end_list(out); stonith_history_free(history); return pcmk_legacy2rc(rc); } #ifdef BUILD_PUBLIC_LIBPACEMAKER int pcmk_fence_history(xmlNodePtr *xml, stonith_t *st, char *target, unsigned int timeout, bool quiet, int verbose, bool broadcast, bool cleanup) { pcmk__output_t *out = NULL; int rc = pcmk_rc_ok; rc = pcmk__out_prologue(&out, xml); if (rc != pcmk_rc_ok) { return rc; } + stonith__register_messages(out); + out->quiet = quiet; rc = pcmk__fence_history(out, st, target, timeout, verbose, broadcast, cleanup); pcmk__out_epilogue(out, xml, rc); return rc; } #endif int pcmk__fence_installed(pcmk__output_t *out, stonith_t *st, unsigned int timeout) { stonith_key_value_t *devices = NULL; int rc = pcmk_rc_ok; rc = st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, timeout/1000); /* list_agents returns a negative error code or a positive number of agents. */ if (rc < 0) { return pcmk_legacy2rc(rc); } out->begin_list(out, "fence device", "fence devices", "Installed fence devices"); for (stonith_key_value_t *dIter = devices; dIter; dIter = dIter->next) { out->list_item(out, "device", "%s", dIter->value); } out->end_list(out); stonith_key_value_freeall(devices, 1, 1); return pcmk_rc_ok; } #ifdef BUILD_PUBLIC_LIBPACEMAKER int pcmk_fence_installed(xmlNodePtr *xml, stonith_t *st, unsigned int timeout) { pcmk__output_t *out = NULL; int rc = pcmk_rc_ok; rc = pcmk__out_prologue(&out, xml); if (rc != pcmk_rc_ok) { return rc; } + stonith__register_messages(out); + rc = pcmk__fence_installed(out, st, timeout); pcmk__out_epilogue(out, xml, rc); return rc; } #endif int pcmk__fence_last(pcmk__output_t *out, const char *target, bool as_nodeid) { time_t when = 0; if (target == NULL) { return pcmk_rc_ok; } if (as_nodeid) { when = stonith_api_time(atol(target), NULL, FALSE); } else { when = stonith_api_time(0, target, FALSE); } return out->message(out, "last-fenced", target, when); } #ifdef BUILD_PUBLIC_LIBPACEMAKER int pcmk_fence_last(xmlNodePtr *xml, const char *target, bool as_nodeid) { pcmk__output_t *out = NULL; int rc = pcmk_rc_ok; rc = pcmk__out_prologue(&out, xml); if (rc != pcmk_rc_ok) { return rc; } + stonith__register_messages(out); + rc = pcmk__fence_last(out, target, as_nodeid); pcmk__out_epilogue(out, xml, rc); return rc; } #endif int pcmk__fence_list_targets(pcmk__output_t *out, stonith_t *st, const char *device_id, unsigned int timeout) { GList *targets = NULL; char *lists = NULL; int rc = pcmk_rc_ok; rc = st->cmds->list(st, st_opts, device_id, &lists, timeout/1000); if (rc != pcmk_rc_ok) { return pcmk_legacy2rc(rc); } targets = stonith__parse_targets(lists); out->begin_list(out, "fence target", "fence targets", "Fence Targets"); while (targets != NULL) { out->list_item(out, NULL, "%s", (const char *) targets->data); targets = targets->next; } out->end_list(out); free(lists); return rc; } #ifdef BUILD_PUBLIC_LIBPACEMAKER int pcmk_fence_list_targets(xmlNodePtr *xml, stonith_t *st, const char *device_id, unsigned int timeout) { pcmk__output_t *out = NULL; int rc = pcmk_rc_ok; rc = pcmk__out_prologue(&out, xml); if (rc != pcmk_rc_ok) { return rc; } + stonith__register_messages(out); + rc = pcmk__fence_list_targets(out, st, device_id, timeout); pcmk__out_epilogue(out, xml, rc); return rc; } #endif int pcmk__fence_metadata(pcmk__output_t *out, stonith_t *st, char *agent, unsigned int timeout) { char *buffer = NULL; int rc = st->cmds->metadata(st, st_opt_sync_call, agent, NULL, &buffer, timeout/1000); if (rc != pcmk_rc_ok) { return pcmk_legacy2rc(rc); } out->output_xml(out, "metadata", buffer); free(buffer); return rc; } #ifdef BUILD_PUBLIC_LIBPACEMAKER int pcmk_fence_metadata(xmlNodePtr *xml, stonith_t *st, char *agent, unsigned int timeout) { pcmk__output_t *out = NULL; int rc = pcmk_rc_ok; rc = pcmk__out_prologue(&out, xml); if (rc != pcmk_rc_ok) { return rc; } + stonith__register_messages(out); + rc = pcmk__fence_metadata(out, st, agent, timeout); pcmk__out_epilogue(out, xml, rc); return rc; } #endif int pcmk__fence_registered(pcmk__output_t *out, stonith_t *st, char *target, unsigned int timeout) { stonith_key_value_t *devices = NULL; int rc = pcmk_rc_ok; rc = st->cmds->query(st, st_opts, target, &devices, timeout/1000); /* query returns a negative error code or a positive number of results. */ if (rc < 0) { return pcmk_legacy2rc(rc); } out->begin_list(out, "fence device", "fence devices", "Registered fence devices"); for (stonith_key_value_t *dIter = devices; dIter; dIter = dIter->next) { out->list_item(out, "device", "%s", dIter->value); } out->end_list(out); stonith_key_value_freeall(devices, 1, 1); /* Return pcmk_rc_ok here, not the number of results. Callers probably * don't care. */ return pcmk_rc_ok; } #ifdef BUILD_PUBLIC_LIBPACEMAKER int pcmk_fence_registered(xmlNodePtr *xml, stonith_t *st, char *target, unsigned int timeout) { pcmk__output_t *out = NULL; int rc = pcmk_rc_ok; rc = pcmk__out_prologue(&out, xml); if (rc != pcmk_rc_ok) { return rc; } + stonith__register_messages(out); + rc = pcmk__fence_registered(out, st, target, timeout); pcmk__out_epilogue(out, xml, rc); return rc; } #endif int pcmk__fence_register_level(stonith_t *st, char *target, int fence_level, stonith_key_value_t *devices) { return handle_level(st, target, fence_level, devices, true); } #ifdef BUILD_PUBLIC_LIBPACEMAKER int pcmk_fence_register_level(stonith_t *st, char *target, int fence_level, stonith_key_value_t *devices) { return pcmk__fence_register_level(st, target, fence_level, devices); } #endif int pcmk__fence_unregister_level(stonith_t *st, char *target, int fence_level) { return handle_level(st, target, fence_level, NULL, false); } #ifdef BUILD_PUBLIC_LIBPACEMAKER int pcmk_fence_unregister_level(stonith_t *st, char *target, int fence_level) { return pcmk__fence_unregister_level(st, target, fence_level); } #endif int pcmk__fence_validate(pcmk__output_t *out, stonith_t *st, const char *agent, const char *id, stonith_key_value_t *params, unsigned int timeout) { char *output = NULL; char *error_output = NULL; int rc; rc = st->cmds->validate(st, st_opt_sync_call, id, NULL, agent, params, timeout/1000, &output, &error_output); out->message(out, "validate", agent, id, output, error_output, rc); return pcmk_legacy2rc(rc); } #ifdef BUILD_PUBLIC_LIBPACEMAKER int pcmk_fence_validate(xmlNodePtr *xml, stonith_t *st, const char *agent, const char *id, stonith_key_value_t *params, unsigned int timeout) { pcmk__output_t *out = NULL; int rc = pcmk_rc_ok; rc = pcmk__out_prologue(&out, xml); if (rc != pcmk_rc_ok) { return rc; } + stonith__register_messages(out); + rc = pcmk__fence_validate(out, st, agent, id, params, timeout); pcmk__out_epilogue(out, xml, rc); return rc; } #endif diff --git a/lib/pacemaker/pcmk_output.c b/lib/pacemaker/pcmk_output.c index 74a7c59326..a637031916 100644 --- a/lib/pacemaker/pcmk_output.c +++ b/lib/pacemaker/pcmk_output.c @@ -1,550 +1,549 @@ /* * Copyright 2019-2020 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include #include pcmk__supported_format_t pcmk__out_formats[] = { PCMK__SUPPORTED_FORMAT_XML, { NULL, NULL, NULL } }; int pcmk__out_prologue(pcmk__output_t **out, xmlNodePtr *xml) { int rc = pcmk_rc_ok; if (*xml != NULL) { xmlFreeNode(*xml); } pcmk__register_formats(NULL, pcmk__out_formats); rc = pcmk__output_new(out, "xml", NULL, NULL); if (rc != pcmk_rc_ok) { return rc; } - stonith__register_messages(*out); return rc; } void pcmk__out_epilogue(pcmk__output_t *out, xmlNodePtr *xml, int retval) { if (retval == pcmk_rc_ok) { out->finish(out, 0, FALSE, (void **) xml); } 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) { if (!printed_header) { pcmk__output_xml_create_parent(out, "colocations", NULL); printed_header = true; } pcmk__output_create_xml_node(out, "colocation", "peer", peer->id, "id", cons->id, NULL); } continue; } if (dependents && recursive) { if (!printed_header) { pcmk__output_xml_create_parent(out, "colocations", NULL); printed_header = true; } out->message(out, "colocations-list", rsc, dependents, recursive); } if (!printed_header) { pcmk__output_xml_create_parent(out, "colocations", NULL); printed_header = true; } score = score2char(cons->score); if (cons->role_rh > RSC_ROLE_STARTED) { pcmk__output_create_xml_node(out, "colocation", "peer", peer->id, "id", cons->id, "score", score, "dependents", dependents ? "needs" : "with", "role", role2text(cons->role_rh), NULL); } else { pcmk__output_create_xml_node(out, "colocation", "peer", peer->id, "id", cons->id, "score", score, NULL); } 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", NULL); 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); pcmk__output_create_xml_node(out, "location", "host", node->details->uname, "id", cons->id, "score", score, NULL); 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; 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", NULL); out->message(out, "colocations-list", rsc, TRUE, recursive); pcmk__output_xml_create_parent(out, "resource", "id", rsc->id, NULL); 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; } PCMK__OUTPUT_ARGS("health", "char *", "char *", "char *", "char *") static int health_text(pcmk__output_t *out, va_list args) { char *sys_from = va_arg(args, char *); char *host_from = va_arg(args, char *); char *fsa_state = va_arg(args, char *); char *result = va_arg(args, char *); if (!out->is_quiet(out)) { out->info(out, "Status of %s@%s: %s (%s)", crm_str(sys_from), crm_str(host_from), crm_str(fsa_state), crm_str(result)); } else if (fsa_state != NULL) { out->info(out, "%s", fsa_state); } return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("health", "char *", "char *", "char *", "char *") static int health_xml(pcmk__output_t *out, va_list args) { char *sys_from = va_arg(args, char *); char *host_from = va_arg(args, char *); char *fsa_state = va_arg(args, char *); char *result = va_arg(args, char *); pcmk__output_create_xml_node(out, crm_str(sys_from), "node_name", crm_str(host_from), "state", crm_str(fsa_state), "result", crm_str(result), NULL); return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("pacemakerd-health", "char *", "char *", "char *") static int pacemakerd_health_text(pcmk__output_t *out, va_list args) { char *sys_from = va_arg(args, char *); char *state = va_arg(args, char *); char *last_updated = va_arg(args, char *); if (!out->is_quiet(out)) { out->info(out, "Status of %s: '%s' %s %s", crm_str(sys_from), crm_str(state), (!pcmk__str_empty(last_updated))? "last updated":"", crm_str(last_updated)); } else { out->info(out, "%s", crm_str(state)); } return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("pacemakerd-health", "char *", "char *", "char *") static int pacemakerd_health_xml(pcmk__output_t *out, va_list args) { char *sys_from = va_arg(args, char *); char *state = va_arg(args, char *); char *last_updated = va_arg(args, char *); pcmk__output_create_xml_node(out, crm_str(sys_from), "state", crm_str(state), "last_updated", crm_str(last_updated), NULL); return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("dc", "char *") static int dc_text(pcmk__output_t *out, va_list args) { char *dc = va_arg(args, char *); if (!out->is_quiet(out)) { out->info(out, "Designated Controller is: %s", crm_str(dc)); } else if (dc != NULL) { out->info(out, "%s", dc); } return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("dc", "char *") static int dc_xml(pcmk__output_t *out, va_list args) { char *dc = va_arg(args, char *); pcmk__output_create_xml_node(out, "dc", "node_name", crm_str(dc), NULL); return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("crmadmin-node-list", "pcmk__output_t *", "xmlNode *") static int crmadmin_node_list(pcmk__output_t *out, va_list args) { xmlNode *xml_node = va_arg(args, xmlNode *); int found = 0; xmlNode *node = NULL; xmlNode *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node); gboolean BASH_EXPORT = va_arg(args, gboolean); out->begin_list(out, NULL, NULL, "nodes"); for (node = first_named_child(nodes, XML_CIB_TAG_NODE); node != NULL; node = crm_next_same_xml(node)) { const char *node_type = BASH_EXPORT ? NULL : crm_element_value(node, XML_ATTR_TYPE); out->message(out, "crmadmin-node", node_type, crm_str(crm_element_value(node, XML_ATTR_UNAME)), crm_str(crm_element_value(node, XML_ATTR_ID)), BASH_EXPORT); found++; } // @TODO List Pacemaker Remote nodes that don't have a entry out->end_list(out); if (found == 0) { out->info(out, "No nodes configured"); } return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("crmadmin-node", "char *", "char *", "char *", "gboolean") static int crmadmin_node_text(pcmk__output_t *out, va_list args) { char *type = va_arg(args, char *); char *name = va_arg(args, char *); char *id = va_arg(args, char *); gboolean BASH_EXPORT = va_arg(args, gboolean); if (BASH_EXPORT) { out->info(out, "export %s=%s", crm_str(name), crm_str(id)); } else { out->info(out, "%s node: %s (%s)", type ? type : "member", crm_str(name), crm_str(id)); } return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("crmadmin-node", "char *", "char *", "char *", "gboolean") static int crmadmin_node_xml(pcmk__output_t *out, va_list args) { char *type = va_arg(args, char *); char *name = va_arg(args, char *); char *id = va_arg(args, char *); pcmk__output_create_xml_node(out, "node", "type", type ? type : "member", "name", crm_str(name), "id", crm_str(id), NULL); 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 }, { "health", "default", health_text }, { "health", "xml", health_xml }, { "pacemakerd-health", "default", pacemakerd_health_text }, { "pacemakerd-health", "xml", pacemakerd_health_xml }, { "dc", "default", dc_text }, { "dc", "xml", dc_xml }, { "crmadmin-node-list", "default", crmadmin_node_list }, { "crmadmin-node", "default", crmadmin_node_text }, { "crmadmin-node", "xml", crmadmin_node_xml }, { NULL, NULL, NULL } }; void pcmk__register_lib_messages(pcmk__output_t *out) { pcmk__register_messages(out, fmt_functions); }