From 33c212c7a3ef37543ab0b5aaed99b3c962d42ab6 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 2 Nov 2022 09:02:08 -0700 Subject: [PATCH] Fix: tools: crm_mon --daemonize should update when disconnected With crm_mon --daemonize, currently the output will continue to show the last known status after the cluster is stopped on the local node. This commit causes it to write "Not connected to CIB" (and more specific details) to the output file: * before the initial connection; * as soon as the CIB connection is destroyed; and * every time a reconnection attempt fails; External agents are notified via traps rather than via output, so we can ignore them. We register the new message formatter functions directly instead of via crm_mon_register_messages(). The reason is that crm_mon_register_messages() is used for messages specific to the curses format, so that they can be registered from within crm_mon.c. The new crm-mon-disconnected formatter isn't used with console output; it's not really necessary, and it's more complicated to implement (attempts so far led to display issues after connection loss). In the future it might make sense to rename crm_mon_register_messages() in crm_mon_curses.c and reuse that name in crm_mon.c. Closes T15 Signed-off-by: Reid Wahl --- tools/crm_mon.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 2 deletions(-) diff --git a/tools/crm_mon.c b/tools/crm_mon.c index 57e8161ecec..5ab73351fbc 100644 --- a/tools/crm_mon.c +++ b/tools/crm_mon.c @@ -100,6 +100,104 @@ static pcmk__supported_format_t formats[] = { { NULL, NULL, NULL } }; +PCMK__OUTPUT_ARGS("crm-mon-disconnected", "const char *", "int") +static int +crm_mon_disconnected_default(pcmk__output_t *out, va_list args) +{ + return pcmk_rc_no_output; +} + +PCMK__OUTPUT_ARGS("crm-mon-disconnected", "const char *", "int") +static int +crm_mon_disconnected_html(pcmk__output_t *out, va_list args) +{ + const char *desc = va_arg(args, const char *); + enum pcmk_pacemakerd_state state = + (enum pcmk_pacemakerd_state) va_arg(args, int); + + if (out->dest != stdout) { + out->reset(out); + } + + pcmk__output_create_xml_text_node(out, "span", "Not connected to CIB"); + + if (desc != NULL) { + pcmk__output_create_xml_text_node(out, "span", ": "); + pcmk__output_create_xml_text_node(out, "span", desc); + } + + if (state != pcmk_pacemakerd_state_invalid) { + const char *state_s = pcmk__pcmkd_state_enum2friendly(state); + + pcmk__output_create_xml_text_node(out, "span", " ("); + pcmk__output_create_xml_text_node(out, "span", state_s); + pcmk__output_create_xml_text_node(out, "span", ")"); + } + + out->finish(out, CRM_EX_DISCONNECT, true, NULL); + return pcmk_rc_ok; +} + +PCMK__OUTPUT_ARGS("crm-mon-disconnected", "const char *", "int") +static int +crm_mon_disconnected_text(pcmk__output_t *out, va_list args) +{ + const char *desc = va_arg(args, const char *); + enum pcmk_pacemakerd_state state = + (enum pcmk_pacemakerd_state) va_arg(args, int); + int rc = pcmk_rc_ok; + + if (out->dest != stdout) { + out->reset(out); + } + + if (state != pcmk_pacemakerd_state_invalid) { + rc = out->info(out, "Not connected to CIB%s%s (%s)", + (desc != NULL)? ": " : "", pcmk__s(desc, ""), + pcmk__pcmkd_state_enum2friendly(state)); + } else { + rc = out->info(out, "Not connected to CIB%s%s", + (desc != NULL)? ": " : "", pcmk__s(desc, "")); + } + + out->finish(out, CRM_EX_DISCONNECT, true, NULL); + return rc; +} + +PCMK__OUTPUT_ARGS("crm-mon-disconnected", "const char *", "int") +static int +crm_mon_disconnected_xml(pcmk__output_t *out, va_list args) +{ + const char *desc = va_arg(args, const char *); + enum pcmk_pacemakerd_state state = + (enum pcmk_pacemakerd_state) va_arg(args, int); + const char *state_s = NULL; + + if (out->dest != stdout) { + out->reset(out); + } + + if (state != pcmk_pacemakerd_state_invalid) { + state_s = pcmk_pacemakerd_api_daemon_state_enum2text(state); + } + + pcmk__output_create_xml_node(out, "crm-mon-disconnected", + XML_ATTR_DESC, desc, + "pacemakerd-state", state_s, + NULL); + + out->finish(out, CRM_EX_DISCONNECT, true, NULL); + return pcmk_rc_ok; +} + +static pcmk__message_entry_t fmt_functions[] = { + { "crm-mon-disconnected", "default", crm_mon_disconnected_default }, + { "crm-mon-disconnected", "html", crm_mon_disconnected_html }, + { "crm-mon-disconnected", "text", crm_mon_disconnected_text }, + { "crm-mon-disconnected", "xml", crm_mon_disconnected_xml }, + { NULL, NULL, NULL }, +}; + /* Define exit codes for monitoring-compatible output * For nagios plugins, the possibilities are * OK=0, WARN=1, CRIT=2, and UNKNOWN=3 @@ -661,6 +759,9 @@ reconnect_after_timeout(gpointer data) return G_SOURCE_REMOVE; } + out->message(out, "crm-mon-disconnected", + "Latest connection attempt failed", pcmkd_state); + reconnect_timer = g_timeout_add(options.reconnect_ms, reconnect_after_timeout, NULL); return G_SOURCE_REMOVE; @@ -673,7 +774,16 @@ reconnect_after_timeout(gpointer data) static void mon_cib_connection_destroy(gpointer user_data) { - out->transient(out, "\nConnection to the cluster lost"); + const char *msg = "Connection to the cluster lost"; + + pcmkd_state = pcmk_pacemakerd_state_invalid; + + /* No crm-mon-disconnected message for console; a working implementation + * is not currently worth the effort + */ + out->transient(out, "\n%s", msg); + + out->message(out, "crm-mon-disconnected", msg, pcmkd_state); if (refresh_timer != NULL) { /* we'll trigger a refresh after reconnect */ @@ -696,7 +806,6 @@ mon_cib_connection_destroy(gpointer user_data) reconnect_timer = g_timeout_add(options.reconnect_ms, reconnect_after_timeout, NULL); } - return; } /* Signal handler installed into the mainloop for normal program shutdown */ @@ -1443,6 +1552,9 @@ main(int argc, char **argv) pe__register_messages(out); stonith__register_messages(out); + // Messages internal to this file, nothing curses-specific + pcmk__register_messages(out, fmt_functions); + if (args->version) { out->version(out, false); return clean_up(CRM_EX_OK); @@ -1489,6 +1601,8 @@ main(int argc, char **argv) one_shot(); } + out->message(out, "crm-mon-disconnected", + "Waiting for initial connection", pcmkd_state); do { out->transient(out, "Connecting to cluster..."); rc = setup_api_connections();