Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/lib/fencing/st_output.c b/lib/fencing/st_output.c
index dc276a44b0..ff708e9401 100644
--- a/lib/fencing/st_output.c
+++ b/lib/fencing/st_output.c
@@ -1,298 +1,442 @@
/*
* Copyright 2019 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include <stdarg.h>
#include <crm/stonith-ng.h>
#include <crm/common/iso8601.h>
#include <crm/common/output.h>
#include <crm/common/util.h>
#include <crm/common/xml.h>
#include <crm/fencing/internal.h>
static char *
time_t_string(time_t when) {
crm_time_t *crm_when = crm_time_new(NULL);
char *buf = NULL;
crm_time_set_timet(crm_when, &when);
buf = crm_time_as_string(crm_when, crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
crm_time_free(crm_when);
return buf;
}
+static int
+failed_fencing_history(pcmk__output_t *out, va_list args) {
+ stonith_history_t *history = va_arg(args, stonith_history_t *);
+ gboolean full_history = va_arg(args, gboolean);
+ gboolean print_spacer = va_arg(args, gboolean);
+
+ int rc = pcmk_rc_no_output;
+
+ for (stonith_history_t *hp = history; hp; hp = hp->next) {
+ if (hp->state != st_failed) {
+ continue;
+ }
+
+ if (rc == pcmk_rc_no_output) {
+ if (print_spacer) {
+ out->info(out, "%s", "");
+ }
+
+ rc = pcmk_rc_ok;
+ out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
+ }
+
+ out->message(out, "stonith-event", hp, full_history, stonith__later_succeeded(hp, history));
+ out->increment_list(out);
+ }
+
+ if (rc == pcmk_rc_ok) {
+ out->end_list(out);
+ }
+
+ return rc;
+}
+
+static int
+fencing_history(pcmk__output_t *out, va_list args) {
+ stonith_history_t *history = va_arg(args, stonith_history_t *);
+ gboolean full_history = va_arg(args, gboolean);
+ gboolean print_spacer = va_arg(args, gboolean);
+
+ int rc = pcmk_rc_no_output;
+
+ for (stonith_history_t *hp = history; hp; hp = hp->next) {
+ if (hp->state != st_failed) {
+ /* Print the header the first time we have an event to print out to
+ * prevent printing headers with empty sections underneath.
+ */
+ if (rc == pcmk_rc_no_output) {
+ /* Add a blank line between this section and the one before it. */
+ if (print_spacer) {
+ out->info(out, "%s", "");
+ }
+
+ rc = pcmk_rc_ok;
+ out->begin_list(out, NULL, NULL, "Fencing History");
+ }
+
+ out->message(out, "stonith-event", hp, full_history, stonith__later_succeeded(hp, history));
+ out->increment_list(out);
+ }
+ }
+
+ if (rc == pcmk_rc_ok) {
+ out->end_list(out);
+ }
+
+ return rc;
+}
+
+static int
+full_fencing_history(pcmk__output_t *out, va_list args) {
+ stonith_history_t *history = va_arg(args, stonith_history_t *);
+ gboolean full_history = va_arg(args, gboolean);
+ gboolean print_spacer = va_arg(args, gboolean);
+
+ int rc = pcmk_rc_no_output;
+
+ for (stonith_history_t *hp = history; hp; hp = hp->next) {
+ if (rc == pcmk_rc_no_output) {
+ /* Add a blank line between this section and the one before it. */
+ if (print_spacer) {
+ out->info(out, "%s", "");
+ }
+
+ rc = pcmk_rc_ok;
+ out->begin_list(out, NULL, NULL, "Fencing History");
+ }
+
+ out->message(out, "stonith-event", hp, full_history, stonith__later_succeeded(hp, history));
+ out->increment_list(out);
+ }
+
+ if (rc == pcmk_rc_ok) {
+ out->end_list(out);
+ }
+
+ return rc;
+}
+
static int
last_fenced_html(pcmk__output_t *out, va_list args) {
const char *target = va_arg(args, const char *);
time_t when = va_arg(args, time_t);
if (when) {
char *buf = crm_strdup_printf("Node %s last fenced at: %s", target, ctime(&when));
pcmk__output_create_html_node(out, "div", NULL, NULL, buf);
free(buf);
return pcmk_rc_ok;
} else {
return pcmk_rc_no_output;
}
}
static int
last_fenced_text(pcmk__output_t *out, va_list args) {
const char *target = va_arg(args, const char *);
time_t when = va_arg(args, time_t);
if (when) {
pcmk__indented_printf(out, "Node %s last fenced at: %s", target, ctime(&when));
} else {
pcmk__indented_printf(out, "Node %s has never been fenced\n", target);
}
return pcmk_rc_ok;
}
static int
last_fenced_xml(pcmk__output_t *out, va_list args) {
const char *target = va_arg(args, const char *);
time_t when = va_arg(args, time_t);
if (when) {
xmlNodePtr node = pcmk__output_create_xml_node(out, "last-fenced");
char *buf = time_t_string(when);
xmlSetProp(node, (pcmkXmlStr) "target", (pcmkXmlStr) target);
xmlSetProp(node, (pcmkXmlStr) "when", (pcmkXmlStr) buf);
free(buf);
return pcmk_rc_ok;
} else {
return pcmk_rc_no_output;
}
}
+static int
+pending_fencing_actions(pcmk__output_t *out, va_list args) {
+ stonith_history_t *history = va_arg(args, stonith_history_t *);
+ gboolean full_history = va_arg(args, gboolean);
+ gboolean print_spacer = va_arg(args, gboolean);
+
+ int rc = pcmk_rc_no_output;
+
+ for (stonith_history_t *hp = history; hp; hp = hp->next) {
+ /* Skip the rest of the history after we see a failed/done action */
+ if ((hp->state == st_failed) || (hp->state == st_done)) {
+ break;
+ }
+
+ if (rc == pcmk_rc_no_output) {
+ if (print_spacer) {
+ out->info(out, "%s", "");
+ }
+
+ rc = pcmk_rc_ok;
+ out->begin_list(out, NULL, NULL, "Pending Fencing Actions");
+ }
+
+ out->message(out, "stonith-event", hp, full_history, stonith__later_succeeded(hp, history));
+ out->increment_list(out);
+ }
+
+ if (rc == pcmk_rc_ok) {
+ out->end_list(out);
+ }
+
+ return rc;
+}
+
static int
stonith_event_html(pcmk__output_t *out, va_list args) {
stonith_history_t *event = va_arg(args, stonith_history_t *);
gboolean full_history = va_arg(args, gboolean);
gboolean later_succeeded = va_arg(args, gboolean);
switch(event->state) {
case st_done: {
char *completed_s = time_t_string(event->completed);
out->list_item(out, "successful-stonith-event",
"%s of %s successful: delegate=%s, client=%s, origin=%s, %s='%s'",
stonith_action_str(event->action), event->target,
event->delegate ? event->delegate : "",
event->client, event->origin,
full_history ? "completed" : "last-successful",
completed_s);
free(completed_s);
break;
}
case st_failed: {
char *failed_s = time_t_string(event->completed);
out->list_item(out, "failed-stonith-event",
"%s of %s failed : delegate=%s, client=%s, origin=%s, %s='%s' %s",
stonith_action_str(event->action), event->target,
event->delegate ? event->delegate : "",
event->client, event->origin,
full_history ? "completed" : "last-failed",
failed_s,
later_succeeded ? "(a later attempt succeeded)" : "");
free(failed_s);
break;
}
default:
out->list_item(out, "pending-stonith-event",
"%s of %s pending: client=%s, origin=%s",
stonith_action_str(event->action), event->target,
event->client, event->origin);
break;
}
return pcmk_rc_ok;
}
static int
stonith_event_text(pcmk__output_t *out, va_list args) {
stonith_history_t *event = va_arg(args, stonith_history_t *);
gboolean full_history = va_arg(args, gboolean);
gboolean later_succeeded = va_arg(args, gboolean);
char *buf = time_t_string(event->completed);
switch (event->state) {
case st_failed:
pcmk__indented_printf(out, "%s of %s failed: delegate=%s, client=%s, origin=%s, %s='%s' %s\n",
stonith_action_str(event->action), event->target,
event->delegate ? event->delegate : "",
event->client, event->origin,
full_history ? "completed" : "last-failed", buf,
later_succeeded ? "(a later attempt succeeded)" : "");
break;
case st_done:
pcmk__indented_printf(out, "%s of %s successful: delegate=%s, client=%s, origin=%s, %s='%s'\n",
stonith_action_str(event->action), event->target,
event->delegate ? event->delegate : "",
event->client, event->origin,
full_history ? "completed" : "last-successful", buf);
break;
default:
pcmk__indented_printf(out, "%s of %s pending: client=%s, origin=%s\n",
stonith_action_str(event->action), event->target,
event->client, event->origin);
break;
}
free(buf);
return pcmk_rc_ok;
}
static int
stonith_event_xml(pcmk__output_t *out, va_list args) {
xmlNodePtr node = pcmk__output_create_xml_node(out, "fence_event");
stonith_history_t *event = va_arg(args, stonith_history_t *);
gboolean full_history G_GNUC_UNUSED = va_arg(args, gboolean);
gboolean later_succeeded G_GNUC_UNUSED = va_arg(args, gboolean);
char *buf = NULL;
switch (event->state) {
case st_failed:
xmlSetProp(node, (pcmkXmlStr) "status", (pcmkXmlStr) "failed");
break;
case st_done:
xmlSetProp(node, (pcmkXmlStr) "status", (pcmkXmlStr) "success");
break;
default: {
char *state = crm_itoa(event->state);
xmlSetProp(node, (pcmkXmlStr) "status", (pcmkXmlStr) "pending");
xmlSetProp(node, (pcmkXmlStr) "extended-status", (pcmkXmlStr) state);
free(state);
break;
}
}
if (event->delegate != NULL) {
xmlSetProp(node, (pcmkXmlStr) "delegate", (pcmkXmlStr) event->delegate);
}
xmlSetProp(node, (pcmkXmlStr) "action", (pcmkXmlStr) event->action);
xmlSetProp(node, (pcmkXmlStr) "target", (pcmkXmlStr) event->target);
xmlSetProp(node, (pcmkXmlStr) "client", (pcmkXmlStr) event->client);
xmlSetProp(node, (pcmkXmlStr) "origin", (pcmkXmlStr) event->origin);
if (event->state == st_failed || event->state == st_done) {
buf = time_t_string(event->completed);
xmlSetProp(node, (pcmkXmlStr) "completed", (pcmkXmlStr) buf);
free(buf);
}
return pcmk_rc_ok;
}
static int
validate_agent_html(pcmk__output_t *out, va_list args) {
const char *agent = va_arg(args, const char *);
const char *device = va_arg(args, const char *);
char *output = va_arg(args, char *);
char *error_output = va_arg(args, char *);
int rc = va_arg(args, int);
if (device) {
char *buf = crm_strdup_printf("Validation of %s on %s %s", agent, device,
rc ? "failed" : "succeeded");
pcmk__output_create_html_node(out, "div", NULL, NULL, buf);
free(buf);
} else {
char *buf = crm_strdup_printf("Validation of %s %s", agent,
rc ? "failed" : "succeeded");
pcmk__output_create_html_node(out, "div", NULL, NULL, buf);
free(buf);
}
out->subprocess_output(out, rc, output, error_output);
return rc;
}
static int
validate_agent_text(pcmk__output_t *out, va_list args) {
const char *agent = va_arg(args, const char *);
const char *device = va_arg(args, const char *);
char *output = va_arg(args, char *);
char *error_output = va_arg(args, char *);
int rc = va_arg(args, int);
if (device) {
pcmk__indented_printf(out, "Validation of %s on %s %s\n", agent, device,
rc ? "failed" : "succeeded");
} else {
pcmk__indented_printf(out, "Validation of %s %s\n", agent,
rc ? "failed" : "succeeded");
}
if (output) {
puts(output);
}
if (error_output) {
puts(error_output);
}
return rc;
}
static int
validate_agent_xml(pcmk__output_t *out, va_list args) {
xmlNodePtr node = pcmk__output_create_xml_node(out, "validate");
const char *agent = va_arg(args, const char *);
const char *device = va_arg(args, const char *);
char *output = va_arg(args, char *);
char *error_output = va_arg(args, char *);
int rc = va_arg(args, int);
xmlSetProp(node, (pcmkXmlStr) "agent", (pcmkXmlStr) agent);
if (device != NULL) {
xmlSetProp(node, (pcmkXmlStr) "device", (pcmkXmlStr) device);
}
xmlSetProp(node, (pcmkXmlStr) "valid", (pcmkXmlStr) (rc ? "false" : "true"));
pcmk__output_xml_push_parent(out, node);
out->subprocess_output(out, rc, output, error_output);
pcmk__output_xml_pop_parent(out);
return rc;
}
static pcmk__message_entry_t fmt_functions[] = {
+ { "failed-fencing-history", "html", failed_fencing_history },
+ { "failed-fencing-history", "text", failed_fencing_history },
+ { "failed-fencing-history", "xml", failed_fencing_history },
+ { "fencing-history", "html", fencing_history },
+ { "fencing-history", "text", fencing_history },
+ { "fencing-history", "xml", fencing_history },
+ { "full-fencing-history", "html", full_fencing_history },
+ { "full-fencing-history", "text", full_fencing_history },
+ { "full-fencing-history", "xml", full_fencing_history },
{ "last-fenced", "html", last_fenced_html },
{ "last-fenced", "text", last_fenced_text },
{ "last-fenced", "xml", last_fenced_xml },
+ { "pending-fencing-actions", "html", pending_fencing_actions },
+ { "pending-fencing-actions", "text", pending_fencing_actions },
+ { "pending-fencing-actions", "xml", pending_fencing_actions },
{ "stonith-event", "html", stonith_event_html },
{ "stonith-event", "text", stonith_event_text },
{ "stonith-event", "xml", stonith_event_xml },
{ "validate", "html", validate_agent_html },
{ "validate", "text", validate_agent_text },
{ "validate", "xml", validate_agent_xml },
{ NULL, NULL, NULL }
};
void
stonith__register_messages(pcmk__output_t *out) {
pcmk__register_messages(out, fmt_functions);
}
diff --git a/tools/crm_mon_print.c b/tools/crm_mon_print.c
index b9a1e581e6..244caaf1a4 100644
--- a/tools/crm_mon_print.c
+++ b/tools/crm_mon_print.c
@@ -1,1243 +1,1088 @@
/*
* 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 <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <config.h>
#include <crm/cib/util.h>
#include <crm/common/curses_internal.h>
#include <crm/common/iso8601_internal.h>
#include <crm/common/xml.h>
#include <crm/msg_xml.h>
#include <crm/pengine/internal.h>
#include <crm/pengine/pe_types.h>
#include <crm/stonith-ng.h>
#include <crm/common/internal.h>
#include <crm/common/util.h>
#include <crm/fencing/internal.h>
#include "crm_mon.h"
static void print_resources_heading(pcmk__output_t *out, unsigned int mon_ops);
static void print_resources_closing(pcmk__output_t *out, unsigned int mon_ops);
static int print_resources(pcmk__output_t *out, pe_working_set_t *data_set,
unsigned int print_opts, unsigned int mon_ops, gboolean brief_output,
gboolean print_summary, gboolean print_spacer);
static int print_rsc_history(pcmk__output_t *out, pe_working_set_t *data_set,
node_t *node, xmlNode *rsc_entry, unsigned int mon_ops,
GListPtr op_list);
static int print_node_history(pcmk__output_t *out, pe_working_set_t *data_set,
xmlNode *node_state, gboolean operations,
unsigned int mon_ops);
static gboolean add_extra_info(pcmk__output_t *out, node_t * node, GListPtr rsc_list,
const char *attrname, int *expected_score);
static void print_node_attribute(gpointer name, gpointer user_data);
static int print_node_summary(pcmk__output_t *out, pe_working_set_t * data_set,
gboolean operations, unsigned int mon_ops,
gboolean print_spacer);
static int print_cluster_tickets(pcmk__output_t *out, pe_working_set_t * data_set,
gboolean print_spacer);
static int print_neg_locations(pcmk__output_t *out, pe_working_set_t *data_set,
unsigned int mon_ops, const char *prefix,
gboolean print_spacer);
static int print_node_attributes(pcmk__output_t *out, pe_working_set_t *data_set,
unsigned int mon_ops, gboolean print_spacer);
static int print_failed_actions(pcmk__output_t *out, pe_working_set_t *data_set,
gboolean print_spacer);
-static int print_failed_stonith_actions(pcmk__output_t *out, stonith_history_t *history,
- unsigned int mon_ops, gboolean print_spacer);
-static int print_stonith_pending(pcmk__output_t *out, stonith_history_t *history,
- unsigned int mon_ops, gboolean print_spacer);
-static int print_stonith_history(pcmk__output_t *out, stonith_history_t *history,
- unsigned int mon_ops, gboolean print_spacer);
-static int print_stonith_history_full(pcmk__output_t *out, stonith_history_t *history,
- unsigned int mon_ops);
/*!
* \internal
* \brief Print resources section heading appropriate to options
*
* \param[in] out The output functions structure.
* \param[in] mon_ops Bitmask of mon_op_*.
*/
static void
print_resources_heading(pcmk__output_t *out, unsigned int mon_ops)
{
const char *heading;
if (is_set(mon_ops, mon_op_group_by_node)) {
/* Active resources have already been printed by node */
heading = is_set(mon_ops, mon_op_inactive_resources) ? "Inactive Resources" : NULL;
} else if (is_set(mon_ops, mon_op_inactive_resources)) {
heading = "Full List of Resources";
} else {
heading = "Active Resources";
}
/* Print section heading */
out->begin_list(out, NULL, NULL, "%s", heading);
}
/*!
* \internal
* \brief Print whatever resource section closing is appropriate
*
* \param[in] out The output functions structure.
* \param[in] mon_ops Bitmask of mon_op_*.
*/
static void
print_resources_closing(pcmk__output_t *out, unsigned int mon_ops)
{
const char *heading;
/* What type of resources we did or did not display */
if (is_set(mon_ops, mon_op_group_by_node)) {
heading = "inactive ";
} else if (is_set(mon_ops, mon_op_inactive_resources)) {
heading = "";
} else {
heading = "active ";
}
out->list_item(out, NULL, "No %sresources", heading);
}
/*!
* \internal
* \brief Print whatever resource section(s) are appropriate
*
* \param[in] out The output functions structure.
* \param[in] data_set Cluster state to display.
* \param[in] print_opts Bitmask of pe_print_*.
* \param[in] mon_ops Bitmask of mon_op_*.
* \param[in] brief_output Whether to display full or brief output.
* \param[in] print_summary Whether to display a failure summary.
*/
static int
print_resources(pcmk__output_t *out, pe_working_set_t *data_set,
unsigned int print_opts, unsigned int mon_ops, gboolean brief_output,
gboolean print_summary, gboolean print_spacer)
{
GListPtr rsc_iter;
int rc = pcmk_rc_no_output;
/* If we already showed active resources by node, and
* we're not showing inactive resources, we have nothing to do
*/
if (is_set(mon_ops, mon_op_group_by_node) && is_not_set(mon_ops, mon_op_inactive_resources)) {
return rc;
}
/* Add a blank line between this section and the one before it. */
if (print_spacer) {
out->info(out, "%s", "");
}
print_resources_heading(out, mon_ops);
/* If we haven't already printed resources grouped by node,
* and brief output was requested, print resource summary */
if (brief_output && is_not_set(mon_ops, mon_op_group_by_node)) {
pe__rscs_brief_output(out, data_set->resources, print_opts,
is_set(mon_ops, mon_op_inactive_resources));
}
/* For each resource, display it if appropriate */
for (rsc_iter = data_set->resources; rsc_iter != NULL; rsc_iter = rsc_iter->next) {
pe_resource_t *rsc = (pe_resource_t *) rsc_iter->data;
/* Complex resources may have some sub-resources active and some inactive */
gboolean is_active = rsc->fns->active(rsc, TRUE);
gboolean partially_active = rsc->fns->active(rsc, FALSE);
/* Skip inactive orphans (deleted but still in CIB) */
if (is_set(rsc->flags, pe_rsc_orphan) && !is_active) {
continue;
/* Skip active resources if we already displayed them by node */
} else if (is_set(mon_ops, mon_op_group_by_node)) {
if (is_active) {
continue;
}
/* Skip primitives already counted in a brief summary */
} else if (brief_output && (rsc->variant == pe_native)) {
continue;
/* Skip resources that aren't at least partially active,
* unless we're displaying inactive resources
*/
} else if (!partially_active && is_not_set(mon_ops, mon_op_inactive_resources)) {
continue;
}
/* Print this resource */
rc = pcmk_rc_ok;
out->message(out, crm_map_element_name(rsc->xml), print_opts, rsc);
}
if (print_summary && rc != pcmk_rc_ok) {
print_resources_closing(out, mon_ops);
}
out->end_list(out);
return pcmk_rc_ok;
}
static int
failure_count(pe_working_set_t *data_set, node_t *node, resource_t *rsc, time_t *last_failure) {
return rsc ? pe_get_failcount(node, rsc, last_failure, pe_fc_default,
NULL, data_set)
: 0;
}
static GListPtr
get_operation_list(xmlNode *rsc_entry) {
GListPtr op_list = NULL;
xmlNode *rsc_op = NULL;
for (rsc_op = __xml_first_child_element(rsc_entry); rsc_op != NULL;
rsc_op = __xml_next_element(rsc_op)) {
if (crm_str_eq((const char *) rsc_op->name, XML_LRM_TAG_RSC_OP, TRUE)) {
op_list = g_list_append(op_list, rsc_op);
}
}
op_list = g_list_sort(op_list, sort_op_by_callid);
return op_list;
}
/*!
* \internal
* \brief Print resource operation/failure history
*
* \param[in] out The output functions structure.
* \param[in] data_set Cluster state to display.
* \param[in] node Node that ran this resource.
* \param[in] rsc_entry Root of XML tree describing resource status.
* \param[in] mon_ops Bitmask of mon_op_*.
* \param[in] op_list A list of operations to print.
*/
static int
print_rsc_history(pcmk__output_t *out, pe_working_set_t *data_set, node_t *node,
xmlNode *rsc_entry, unsigned int mon_ops, GListPtr op_list)
{
GListPtr gIter = NULL;
int rc = pcmk_rc_no_output;
const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID);
resource_t *rsc = pe_find_resource(data_set->resources, rsc_id);
/* Print each operation */
for (gIter = op_list; gIter != NULL; gIter = gIter->next) {
xmlNode *xml_op = (xmlNode *) gIter->data;
const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
const char *interval_ms_s = crm_element_value(xml_op,
XML_LRM_ATTR_INTERVAL_MS);
const char *op_rc = crm_element_value(xml_op, XML_LRM_ATTR_RC);
int op_rc_i = crm_parse_int(op_rc, "0");
/* Display 0-interval monitors as "probe" */
if (safe_str_eq(task, CRMD_ACTION_STATUS)
&& ((interval_ms_s == NULL) || safe_str_eq(interval_ms_s, "0"))) {
task = "probe";
}
/* Ignore notifies and some probes */
if (safe_str_eq(task, CRMD_ACTION_NOTIFY) || (safe_str_eq(task, "probe") && (op_rc_i == 7))) {
continue;
}
/* If this is the first printed operation, print heading for resource */
if (rc == pcmk_rc_no_output) {
time_t last_failure = 0;
int failcount = failure_count(data_set, node, rsc, &last_failure);
out->message(out, "resource-history", rsc, rsc_id, TRUE, failcount, last_failure, TRUE);
rc = pcmk_rc_ok;
}
/* Print the operation */
out->message(out, "op-history", xml_op, task, interval_ms_s,
op_rc_i, is_set(mon_ops, mon_op_print_timing));
}
/* Free the list we created (no need to free the individual items) */
g_list_free(op_list);
/* If we printed anything, close the resource */
if (rc == pcmk_rc_ok) {
out->end_list(out);
}
return rc;
}
/*!
* \internal
* \brief Print node operation/failure history
*
* \param[in] out The output functions structure.
* \param[in] data_set Cluster state to display.
* \param[in] node_state Root of XML tree describing node status.
* \param[in] operations Whether to print operations or just failcounts.
* \param[in] mon_ops Bitmask of mon_op_*.
*/
static int
print_node_history(pcmk__output_t *out, pe_working_set_t *data_set,
xmlNode *node_state, gboolean operations,
unsigned int mon_ops)
{
node_t *node = pe_find_node_id(data_set->nodes, ID(node_state));
xmlNode *lrm_rsc = NULL;
xmlNode *rsc_entry = NULL;
int rc = pcmk_rc_no_output;
if (!node || !node->details || !node->details->online) {
return rc;
}
lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE);
lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES, FALSE);
/* Print history of each of the node's resources */
for (rsc_entry = __xml_first_child_element(lrm_rsc); rsc_entry != NULL;
rsc_entry = __xml_next_element(rsc_entry)) {
if (!crm_str_eq((const char *)rsc_entry->name, XML_LRM_TAG_RESOURCE, TRUE)) {
continue;
}
if (operations == FALSE) {
const char *rsc_id = crm_element_value(rsc_entry, XML_ATTR_ID);
resource_t *rsc = pe_find_resource(data_set->resources, rsc_id);
time_t last_failure = 0;
int failcount = failure_count(data_set, node, rsc, &last_failure);
if (failcount > 0) {
if (rc == pcmk_rc_no_output) {
rc = pcmk_rc_ok;
out->message(out, "node", node, get_resource_display_options(mon_ops),
FALSE, NULL, is_set(mon_ops, mon_op_print_clone_detail),
is_set(mon_ops, mon_op_print_brief), is_set(mon_ops, mon_op_group_by_node));
}
out->message(out, "resource-history", rsc, rsc_id, FALSE,
failcount, last_failure, FALSE);
}
} else {
GListPtr op_list = get_operation_list(rsc_entry);
if (rc == pcmk_rc_no_output) {
rc = pcmk_rc_ok;
out->message(out, "node", node, get_resource_display_options(mon_ops),
FALSE, NULL, is_set(mon_ops, mon_op_print_clone_detail),
is_set(mon_ops, mon_op_print_brief), is_set(mon_ops, mon_op_group_by_node));
}
if (op_list != NULL) {
print_rsc_history(out, data_set, node, rsc_entry, mon_ops, op_list);
}
}
}
if (rc == pcmk_rc_ok) {
out->end_list(out);
}
return rc;
}
/*!
* \internal
* \brief Determine whether extended information about an attribute should be added.
*
* \param[in] out The output functions structure.
* \param[in] node Node that ran this resource.
* \param[in] rsc_list The list of resources for this node.
* \param[in] attrname The attribute to find.
* \param[out] expected_score The expected value for this attribute.
*
* \return TRUE if extended information should be printed, FALSE otherwise
* \note Currently, extended information is only supported for ping/pingd
* resources, for which a message will be printed if connectivity is lost
* or degraded.
*/
static gboolean
add_extra_info(pcmk__output_t *out, node_t *node, GListPtr rsc_list,
const char *attrname, int *expected_score)
{
GListPtr gIter = NULL;
for (gIter = rsc_list; gIter != NULL; gIter = gIter->next) {
resource_t *rsc = (resource_t *) gIter->data;
const char *type = g_hash_table_lookup(rsc->meta, "type");
const char *name = NULL;
if (rsc->children != NULL) {
if (add_extra_info(out, node, rsc->children, attrname, expected_score)) {
return TRUE;
}
}
if (safe_str_neq(type, "ping") && safe_str_neq(type, "pingd")) {
return FALSE;
}
name = g_hash_table_lookup(rsc->parameters, "name");
if (name == NULL) {
name = "pingd";
}
/* To identify the resource with the attribute name. */
if (safe_str_eq(name, attrname)) {
int host_list_num = 0;
/* int value = crm_parse_int(attrvalue, "0"); */
const char *hosts = g_hash_table_lookup(rsc->parameters, "host_list");
const char *multiplier = g_hash_table_lookup(rsc->parameters, "multiplier");
if (hosts) {
char **host_list = g_strsplit(hosts, " ", 0);
host_list_num = g_strv_length(host_list);
g_strfreev(host_list);
}
/* pingd multiplier is the same as the default value. */
*expected_score = host_list_num * crm_parse_int(multiplier, "1");
return TRUE;
}
}
return FALSE;
}
/* structure for passing multiple user data to g_list_foreach() */
struct mon_attr_data {
pcmk__output_t *out;
node_t *node;
};
static void
print_node_attribute(gpointer name, gpointer user_data)
{
const char *value = NULL;
int expected_score = 0;
gboolean add_extra = FALSE;
struct mon_attr_data *data = (struct mon_attr_data *) user_data;
value = pe_node_attribute_raw(data->node, name);
add_extra = add_extra_info(data->out, data->node, data->node->details->running_rsc,
name, &expected_score);
/* Print attribute name and value */
data->out->message(data->out, "node-attribute", name, value, add_extra,
expected_score);
}
/*!
* \internal
* \brief Print history for all nodes.
*
* \param[in] out The output functions structure.
* \param[in] data_set Cluster state to display.
* \param[in] operations Whether to print operations or just failcounts.
* \param[in] mon_ops Bitmask of mon_op_*.
*/
static int
print_node_summary(pcmk__output_t *out, pe_working_set_t * data_set,
gboolean operations, unsigned int mon_ops,
gboolean print_spacer)
{
xmlNode *node_state = NULL;
xmlNode *cib_status = get_object_root(XML_CIB_TAG_STATUS, data_set->input);
int rc = pcmk_rc_no_output;
if (xmlChildElementCount(cib_status) == 0) {
return rc;
}
/* Print each node in the CIB status */
for (node_state = __xml_first_child_element(cib_status); node_state != NULL;
node_state = __xml_next_element(node_state)) {
if (!crm_str_eq((const char *)node_state->name, XML_CIB_TAG_STATE, TRUE)) {
continue;
}
if (rc == pcmk_rc_no_output) {
/* Add a blank line between this section and the one before it. */
if (print_spacer) {
out->info(out, "%s", "");
}
if (operations) {
out->begin_list(out, NULL, NULL, "Operations");
} else {
out->begin_list(out, NULL, NULL, "Migration Summary");
}
rc = pcmk_rc_ok;
}
print_node_history(out, data_set, node_state, operations, mon_ops);
}
if (rc == pcmk_rc_ok) {
out->end_list(out);
}
return rc;
}
/*!
* \internal
* \brief Print all tickets.
*
* \param[in] out The output functions structure.
* \param[in] data_set Cluster state to display.
*/
static int
print_cluster_tickets(pcmk__output_t *out, pe_working_set_t * data_set,
gboolean print_spacer)
{
GHashTableIter iter;
gpointer key, value;
if (g_hash_table_size(data_set->tickets) == 0) {
return pcmk_rc_no_output;
}
/* Add a blank line between this section and the one before it. */
if (print_spacer) {
out->info(out, "%s", "");
}
/* Print section heading */
out->begin_list(out, NULL, NULL, "Tickets");
/* Print each ticket */
g_hash_table_iter_init(&iter, data_set->tickets);
while (g_hash_table_iter_next(&iter, &key, &value)) {
ticket_t *ticket = (ticket_t *) value;
out->message(out, "ticket", ticket);
}
/* Close section */
out->end_list(out);
return pcmk_rc_ok;
}
/*!
* \internal
* \brief Print section for negative location constraints
*
* \param[in] out The output functions structure.
* \param[in] data_set Cluster state to display.
* \param[in] mon_ops Bitmask of mon_op_*.
* \param[in] prefix ID prefix to filter results by.
*/
static int
print_neg_locations(pcmk__output_t *out, pe_working_set_t *data_set,
unsigned int mon_ops, const char *prefix, gboolean print_spacer)
{
GListPtr gIter, gIter2;
int rc = pcmk_rc_no_output;
/* Print each ban */
for (gIter = data_set->placement_constraints; gIter != NULL; gIter = gIter->next) {
pe__location_t *location = gIter->data;
if (prefix != NULL && !g_str_has_prefix(location->id, prefix))
continue;
for (gIter2 = location->node_list_rh; gIter2 != NULL; gIter2 = gIter2->next) {
pe_node_t *node = (pe_node_t *) gIter2->data;
if (node->weight < 0) {
if (rc == pcmk_rc_no_output) {
/* Add a blank line between this section and the one before it. */
if (print_spacer) {
out->info(out, "%s", "");
}
rc = pcmk_rc_ok;
out->begin_list(out, NULL, NULL, "Negative Location Constraints");
}
out->message(out, "ban", node, location, is_set(mon_ops, mon_op_print_clone_detail));
}
}
}
if (rc == pcmk_rc_ok) {
out->end_list(out);
}
return rc;
}
/*!
* \internal
* \brief Print node attributes section
*
* \param[in] out The output functions structure.
* \param[in] data_set Cluster state to display.
* \param[in] mon_ops Bitmask of mon_op_*.
*/
static int
print_node_attributes(pcmk__output_t *out, pe_working_set_t *data_set,
unsigned int mon_ops, gboolean print_spacer)
{
GListPtr gIter = NULL;
int rc = pcmk_rc_no_output;
/* Unpack all resource parameters (it would be more efficient to do this
* only when needed for the first time in add_extra_info())
*/
for (gIter = data_set->resources; gIter != NULL; gIter = gIter->next) {
crm_mon_get_parameters(gIter->data, data_set);
}
/* Display each node's attributes */
for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
struct mon_attr_data data;
data.out = out;
data.node = (node_t *) gIter->data;
if (data.node && data.node->details && data.node->details->online) {
GList *attr_list = NULL;
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init(&iter, data.node->details->attrs);
while (g_hash_table_iter_next (&iter, &key, &value)) {
attr_list = append_attr_list(attr_list, key);
}
if (attr_list == NULL) {
continue;
}
if (rc == pcmk_rc_no_output) {
/* Add a blank line between this section and the one before it. */
if (print_spacer) {
out->info(out, "%s", "");
}
rc = pcmk_rc_ok;
out->begin_list(out, NULL, NULL, "Node Attributes");
}
out->message(out, "node", data.node, get_resource_display_options(mon_ops),
FALSE, NULL, is_set(mon_ops, mon_op_print_clone_detail),
is_set(mon_ops, mon_op_print_brief), is_set(mon_ops, mon_op_group_by_node));
g_list_foreach(attr_list, print_node_attribute, &data);
g_list_free(attr_list);
out->end_list(out);
}
}
/* Print section footer */
if (rc == pcmk_rc_ok) {
out->end_list(out);
}
return rc;
}
/*!
* \internal
* \brief Print a section for failed actions
*
* \param[in] out The output functions structure.
* \param[in] data_set Cluster state to display.
*/
static int
print_failed_actions(pcmk__output_t *out, pe_working_set_t *data_set,
gboolean print_spacer)
{
xmlNode *xml_op = NULL;
if (xmlChildElementCount(data_set->failed) == 0) {
return pcmk_rc_no_output;
}
/* Add a blank line between this section and the one before it. */
if (print_spacer) {
out->info(out, "%s", "");
}
/* Print section heading */
out->begin_list(out, NULL, NULL, "Failed Resource Actions");
/* Print each failed action */
for (xml_op = __xml_first_child(data_set->failed); xml_op != NULL;
xml_op = __xml_next(xml_op)) {
out->message(out, "failed-action", xml_op);
}
/* End section */
out->end_list(out);
return pcmk_rc_ok;
}
-/*!
- * \internal
- * \brief Print a section for failed stonith actions
- *
- * \note This function should not be called for XML output.
- *
- * \param[in] out The output functions structure.
- * \param[in] history List of stonith actions.
- * \param[in] mon_ops Bitmask of mon_op_*.
- */
-static int
-print_failed_stonith_actions(pcmk__output_t *out, stonith_history_t *history,
- unsigned int mon_ops, gboolean print_spacer)
-{
- stonith_history_t *hp;
-
- for (hp = history; hp; hp = hp->next) {
- if (hp->state == st_failed) {
- break;
- }
- }
- if (!hp) {
- return pcmk_rc_no_output;
- }
-
- /* Add a blank line between this section and the one before it. */
- if (print_spacer) {
- out->info(out, "%s", "");
- }
-
- /* Print section heading */
- out->begin_list(out, NULL, NULL, "Failed Fencing Actions");
-
- /* Print each failed stonith action */
- for (hp = history; hp; hp = hp->next) {
- if (hp->state == st_failed) {
- out->message(out, "stonith-event", hp, is_set(mon_ops, mon_op_fence_full_history),
- stonith__later_succeeded(hp, history));
- out->increment_list(out);
- }
- }
-
- /* End section */
- out->end_list(out);
- return pcmk_rc_ok;
-}
-
-/*!
- * \internal
- * \brief Print pending stonith actions
- *
- * \note This function should not be called for XML output.
- *
- * \param[in] out The output functions structure.
- * \param[in] history List of stonith actions.
- * \param[in] mon_ops Bitmask of mon_op_*.
- */
-static int
-print_stonith_pending(pcmk__output_t *out, stonith_history_t *history,
- unsigned int mon_ops, gboolean print_spacer)
-{
- int rc = pcmk_rc_no_output;
-
- /* xml-output always shows the full history
- * so we'll never have to show pending-actions
- * separately
- */
- if (history && (history->state != st_failed) &&
- (history->state != st_done)) {
- stonith_history_t *hp;
-
- /* Print section heading */
- if (rc == pcmk_rc_no_output) {
- /* Add a blank line between this section and the one before it. */
- if (print_spacer) {
- out->info(out, "%s", "");
- }
-
- rc = pcmk_rc_ok;
- out->begin_list(out, NULL, NULL, "Pending Fencing Actions");
- }
-
- for (hp = history; hp; hp = hp->next) {
- if ((hp->state == st_failed) || (hp->state == st_done)) {
- break;
- }
- out->message(out, "stonith-event", hp, is_set(mon_ops, mon_op_fence_full_history),
- stonith__later_succeeded(hp, history));
- out->increment_list(out);
- }
-
- /* End section */
- if (rc == pcmk_rc_ok) {
- out->end_list(out);
- }
- }
-
- return rc;
-}
-
-/*!
- * \internal
- * \brief Print fencing history, skipping all failed actions.
- *
- * \note This function should not be called for XML output.
- *
- * \param[in] out The output functions structure.
- * \param[in] history List of stonith actions.
- * \param[in] mon_ops Bitmask of mon_op_*.
- */
-static int
-print_stonith_history(pcmk__output_t *out, stonith_history_t *history,
- unsigned int mon_ops, gboolean print_spacer)
-{
- stonith_history_t *hp;
- int rc = pcmk_rc_no_output;
-
- if (history == NULL) {
- return rc;
- }
-
- for (hp = history; hp; hp = hp->next) {
- if (hp->state != st_failed) {
- /* Print the header the first time we have an event to print out to
- * prevent printing headers with empty sections underneath.
- */
- if (rc == pcmk_rc_no_output) {
- /* Add a blank line between this section and the one before it. */
- if (print_spacer) {
- out->info(out, "%s", "");
- }
-
- rc = pcmk_rc_ok;
- out->begin_list(out, NULL, NULL, "Fencing History");
- }
-
- out->message(out, "stonith-event", hp, is_set(mon_ops, mon_op_fence_full_history),
- stonith__later_succeeded(hp, history));
- out->increment_list(out);
- }
- }
-
- if (rc == pcmk_rc_ok) {
- out->end_list(out);
- }
-
- return rc;
-}
-
-/*!
- * \internal
- * \brief Print fencing history, including failed actions.
- *
- * \note This function should be called for XML output. It may also be
- * interesting for other output formats.
- *
- * \param[in] out The output functions structure.
- * \param[in] history List of stonith actions.
- * \param[in] mon_ops Bitmask of mon_op_*.
- */
-static int
-print_stonith_history_full(pcmk__output_t *out, stonith_history_t *history, unsigned int mon_ops)
-{
- stonith_history_t *hp;
-
- if (history == NULL) {
- return pcmk_rc_no_output;
- }
-
- /* Print section heading */
- out->begin_list(out, NULL, NULL, "Fencing History");
-
- for (hp = history; hp; hp = hp->next) {
- out->message(out, "stonith-event", hp, is_set(mon_ops, mon_op_fence_full_history),
- stonith__later_succeeded(hp, history));
- out->increment_list(out);
- }
-
- /* End section */
- out->end_list(out);
- return pcmk_rc_ok;
-}
-
/*!
* \internal
* \brief Top-level printing function for text/curses output.
*
* \param[in] out The output functions structure.
* \param[in] data_set Cluster state to display.
* \param[in] stonith_history List of stonith actions.
* \param[in] mon_ops Bitmask of mon_op_*.
* \param[in] show Bitmask of mon_show_*.
* \param[in] prefix ID prefix to filter results by.
*/
void
print_status(pcmk__output_t *out, pe_working_set_t *data_set,
stonith_history_t *stonith_history, unsigned int mon_ops,
unsigned int show, char *prefix)
{
GListPtr gIter = NULL;
unsigned int print_opts = get_resource_display_options(mon_ops);
int rc = pcmk_rc_no_output;
/* space-separated lists of node names */
char *online_nodes = NULL;
char *online_remote_nodes = NULL;
char *online_guest_nodes = NULL;
char *offline_nodes = NULL;
char *offline_remote_nodes = NULL;
rc = out->message(out, "cluster-summary", data_set,
is_set(mon_ops, mon_op_print_clone_detail),
is_set(show, mon_show_stack),
is_set(show, mon_show_dc),
is_set(show, mon_show_times),
is_set(show, mon_show_counts),
is_set(show, mon_show_options));
/* Gather node information (and print if in bad state or grouping by node) */
if (is_set(show, mon_show_nodes)) {
if (rc == pcmk_rc_ok) {
out->info(out, "%s", "");
} else {
rc = pcmk_rc_ok;
}
out->begin_list(out, NULL, NULL, "Node List");
for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
node_t *node = (node_t *) gIter->data;
const char *node_mode = NULL;
char *node_name = pe__node_display_name(node, is_set(mon_ops, mon_op_print_clone_detail));
/* Get node mode */
if (node->details->unclean) {
if (node->details->online) {
node_mode = "UNCLEAN (online)";
} else if (node->details->pending) {
node_mode = "UNCLEAN (pending)";
} else {
node_mode = "UNCLEAN (offline)";
}
} else if (node->details->pending) {
node_mode = "pending";
} else if (node->details->standby_onfail && node->details->online) {
node_mode = "standby (on-fail)";
} else if (node->details->standby) {
if (node->details->online) {
if (node->details->running_rsc) {
node_mode = "standby (with active resources)";
} else {
node_mode = "standby";
}
} else {
node_mode = "OFFLINE (standby)";
}
} else if (node->details->maintenance) {
if (node->details->online) {
node_mode = "maintenance";
} else {
node_mode = "OFFLINE (maintenance)";
}
} else if (node->details->online) {
node_mode = "online";
if (is_not_set(mon_ops, mon_op_group_by_node)) {
if (pe__is_guest_node(node)) {
online_guest_nodes = pcmk__add_word(online_guest_nodes,
node_name);
} else if (pe__is_remote_node(node)) {
online_remote_nodes = pcmk__add_word(online_remote_nodes,
node_name);
} else {
online_nodes = pcmk__add_word(online_nodes, node_name);
}
free(node_name);
continue;
}
} else {
node_mode = "OFFLINE";
if (is_not_set(mon_ops, mon_op_group_by_node)) {
if (pe__is_remote_node(node)) {
offline_remote_nodes = pcmk__add_word(offline_remote_nodes,
node_name);
} else if (pe__is_guest_node(node)) {
/* ignore offline guest nodes */
} else {
offline_nodes = pcmk__add_word(offline_nodes, node_name);
}
free(node_name);
continue;
}
}
/* If we get here, node is in bad state, or we're grouping by node */
out->message(out, "node", node, get_resource_display_options(mon_ops), TRUE,
node_mode, is_set(mon_ops, mon_op_print_clone_detail),
is_set(mon_ops, mon_op_print_brief), is_set(mon_ops, mon_op_group_by_node));
free(node_name);
}
/* If we're not grouping by node, summarize nodes by status */
if (online_nodes) {
out->list_item(out, "Online", "[%s ]", online_nodes);
free(online_nodes);
}
if (offline_nodes) {
out->list_item(out, "OFFLINE", "[%s ]", offline_nodes);
free(offline_nodes);
}
if (online_remote_nodes) {
out->list_item(out, "RemoteOnline", "[%s ]", online_remote_nodes);
free(online_remote_nodes);
}
if (offline_remote_nodes) {
out->list_item(out, "RemoteOFFLINE", "[%s ]", offline_remote_nodes);
free(offline_remote_nodes);
}
if (online_guest_nodes) {
out->list_item(out, "GuestOnline", "[%s ]", online_guest_nodes);
free(online_guest_nodes);
}
out->end_list(out);
}
/* Print resources section, if needed */
if (is_set(show, mon_show_resources)) {
rc = print_resources(out, data_set, print_opts, mon_ops,
is_set(mon_ops, mon_op_print_brief), TRUE,
rc == pcmk_rc_ok);
}
/* print Node Attributes section if requested */
if (is_set(show, mon_show_attributes)) {
rc = print_node_attributes(out, data_set, mon_ops,
rc == pcmk_rc_ok);
}
/* If requested, print resource operations (which includes failcounts)
* or just failcounts
*/
if (is_set(show, mon_show_operations) || is_set(show, mon_show_failcounts)) {
rc = print_node_summary(out, data_set, is_set(show, mon_show_operations),
mon_ops, rc == pcmk_rc_ok);
}
/* If there were any failed actions, print them */
if (is_set(show, mon_show_failures) && xml_has_children(data_set->failed)) {
rc = print_failed_actions(out, data_set, rc == pcmk_rc_ok);
}
/* Print failed stonith actions */
if (is_set(show, mon_show_fence_failed) && is_set(mon_ops, mon_op_fence_history)) {
- rc = print_failed_stonith_actions(out, stonith_history, mon_ops,
- rc == pcmk_rc_ok);
+ for (stonith_history_t *hp = stonith_history; hp; hp = hp->next) {
+ if (hp->state == st_failed) {
+ rc = out->message(out, "failed-fencing-history", hp,
+ is_set(mon_ops, mon_op_fence_full_history), rc = pcmk_rc_ok);
+ break;
+ }
+ }
}
/* Print tickets if requested */
if (is_set(show, mon_show_tickets)) {
rc = print_cluster_tickets(out, data_set, rc == pcmk_rc_ok);
}
/* Print negative location constraints if requested */
if (is_set(show, mon_show_bans)) {
rc = print_neg_locations(out, data_set, mon_ops, prefix, rc == pcmk_rc_ok);
}
/* Print stonith history */
if (is_set(mon_ops, mon_op_fence_history)) {
if (is_set(show, mon_show_fence_worked)) {
- rc = print_stonith_history(out, stonith_history, mon_ops, rc == pcmk_rc_ok);
+ for (stonith_history_t *hp = stonith_history; hp; hp = hp->next) {
+ if (hp->state != st_failed) {
+ rc = out->message(out, "fencing-history", hp,
+ is_set(mon_ops, mon_op_fence_full_history), rc == pcmk_rc_ok);
+ break;
+ }
+ }
} else if (is_set(show, mon_show_fence_pending)) {
- rc = print_stonith_pending(out, stonith_history, mon_ops, rc == pcmk_rc_ok);
+ for (stonith_history_t *hp = stonith_history; hp; hp = hp->next) {
+ if (hp->state != st_failed && hp->state != st_done) {
+ rc = out->message(out, "pending-fencing-actions", hp,
+ is_set(mon_ops, mon_op_fence_full_history), rc == pcmk_rc_ok);
+ break;
+ }
+ }
}
}
}
/*!
* \internal
* \brief Top-level printing function for XML output.
*
* \param[in] out The output functions structure.
* \param[in] data_set Cluster state to display.
* \param[in] stonith_history List of stonith actions.
* \param[in] mon_ops Bitmask of mon_op_*.
* \param[in] show Bitmask of mon_show_*.
* \param[in] prefix ID prefix to filter results by.
*/
void
print_xml_status(pcmk__output_t *out, pe_working_set_t *data_set,
stonith_history_t *stonith_history, unsigned int mon_ops,
unsigned int show, char *prefix)
{
GListPtr gIter = NULL;
unsigned int print_opts = get_resource_display_options(mon_ops);
out->message(out, "cluster-summary", data_set,
is_set(mon_ops, mon_op_print_clone_detail),
is_set(show, mon_show_stack),
is_set(show, mon_show_dc),
is_set(show, mon_show_times),
is_set(show, mon_show_counts),
is_set(show, mon_show_options));
/*** NODES ***/
if (is_set(show, mon_show_nodes)) {
out->begin_list(out, NULL, NULL, "nodes");
for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
node_t *node = (node_t *) gIter->data;
out->message(out, "node", node, get_resource_display_options(mon_ops), TRUE,
NULL, is_set(mon_ops, mon_op_print_clone_detail),
is_set(mon_ops, mon_op_print_brief), is_set(mon_ops, mon_op_group_by_node));
}
out->end_list(out);
}
/* Print resources section, if needed */
if (is_set(show, mon_show_resources)) {
print_resources(out, data_set, print_opts, mon_ops, FALSE, FALSE, FALSE);
}
/* print Node Attributes section if requested */
if (is_set(show, mon_show_attributes)) {
print_node_attributes(out, data_set, mon_ops, FALSE);
}
/* If requested, print resource operations (which includes failcounts)
* or just failcounts
*/
if (is_set(show, mon_show_operations) || is_set(show, mon_show_failcounts)) {
print_node_summary(out, data_set, is_set(show, mon_show_operations), mon_ops, FALSE);
}
/* If there were any failed actions, print them */
if (is_set(show, mon_show_failures) && xml_has_children(data_set->failed)) {
print_failed_actions(out, data_set, FALSE);
}
/* Print stonith history */
if (is_set(show, mon_show_fencing_all) && is_set(mon_ops, mon_op_fence_history)) {
- print_stonith_history_full(out, stonith_history, mon_ops);
+ out->message(out, "full-fencing-history", stonith_history,
+ is_set(mon_ops, mon_op_fence_full_history), FALSE);
}
/* Print tickets if requested */
if (is_set(show, mon_show_tickets)) {
print_cluster_tickets(out, data_set, FALSE);
}
/* Print negative location constraints if requested */
if (is_set(show, mon_show_bans)) {
print_neg_locations(out, data_set, mon_ops, prefix, FALSE);
}
}
/*!
* \internal
* \brief Top-level printing function for HTML output.
*
* \param[in] out The output functions structure.
* \param[in] data_set Cluster state to display.
* \param[in] stonith_history List of stonith actions.
* \param[in] mon_ops Bitmask of mon_op_*.
* \param[in] show Bitmask of mon_show_*.
* \param[in] prefix ID prefix to filter results by.
*/
int
print_html_status(pcmk__output_t *out, pe_working_set_t *data_set,
stonith_history_t *stonith_history, unsigned int mon_ops,
unsigned int show, char *prefix)
{
GListPtr gIter = NULL;
unsigned int print_opts = get_resource_display_options(mon_ops);
out->message(out, "cluster-summary", data_set,
is_set(mon_ops, mon_op_print_clone_detail),
is_set(show, mon_show_stack),
is_set(show, mon_show_dc),
is_set(show, mon_show_times),
is_set(show, mon_show_counts),
is_set(show, mon_show_options));
/*** NODE LIST ***/
if (is_set(show, mon_show_nodes)) {
out->begin_list(out, NULL, NULL, "Node List");
for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
node_t *node = (node_t *) gIter->data;
out->message(out, "node", node, get_resource_display_options(mon_ops), TRUE,
NULL, is_set(mon_ops, mon_op_print_clone_detail),
is_set(mon_ops, mon_op_print_brief), is_set(mon_ops, mon_op_group_by_node));
}
out->end_list(out);
}
/* Print resources section, if needed */
if (is_set(show, mon_show_resources)) {
print_resources(out, data_set, print_opts, mon_ops,
is_set(mon_ops, mon_op_print_brief), TRUE, FALSE);
}
/* print Node Attributes section if requested */
if (is_set(show, mon_show_attributes)) {
print_node_attributes(out, data_set, mon_ops, FALSE);
}
/* If requested, print resource operations (which includes failcounts)
* or just failcounts
*/
if (is_set(show, mon_show_operations) || is_set(show, mon_show_failcounts)) {
print_node_summary(out, data_set, is_set(show, mon_show_operations), mon_ops, FALSE);
}
/* If there were any failed actions, print them */
if (is_set(show, mon_show_failures) && xml_has_children(data_set->failed)) {
print_failed_actions(out, data_set, FALSE);
}
/* Print failed stonith actions */
if (is_set(show, mon_show_fence_failed) && is_set(mon_ops, mon_op_fence_history)) {
- print_failed_stonith_actions(out, stonith_history, mon_ops, FALSE);
+ for (stonith_history_t *hp = stonith_history; hp; hp = hp->next) {
+ if (hp->state == st_failed) {
+ out->message(out, "failed-fencing-history", hp,
+ is_set(mon_ops, mon_op_fence_full_history), FALSE);
+ break;
+ }
+ }
}
/* Print stonith history */
if (is_set(mon_ops, mon_op_fence_history)) {
if (is_set(show, mon_show_fence_worked)) {
- print_stonith_history(out, stonith_history, mon_ops, FALSE);
+ for (stonith_history_t *hp = stonith_history; hp; hp = hp->next) {
+ if (hp->state != st_failed) {
+ out->message(out, "fencing-history", hp,
+ is_set(mon_ops, mon_op_fence_full_history), FALSE);
+ break;
+ }
+ }
} else if (is_set(show, mon_show_fence_pending)) {
- print_stonith_pending(out, stonith_history, mon_ops, FALSE);
+ for (stonith_history_t *hp = stonith_history; hp; hp = hp->next) {
+ if (hp->state != st_failed && hp->state != st_done) {
+ out->message(out, "pending-fencing-actions", hp,
+ is_set(mon_ops, mon_op_fence_full_history), FALSE);
+ break;
+ }
+ }
}
}
/* Print tickets if requested */
if (is_set(show, mon_show_tickets)) {
print_cluster_tickets(out, data_set, FALSE);
}
/* Print negative location constraints if requested */
if (is_set(show, mon_show_bans)) {
print_neg_locations(out, data_set, mon_ops, prefix, FALSE);
}
return 0;
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 23, 5:02 PM (14 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1019034
Default Alt Text
(61 KB)

Event Timeline