pacemaker  2.1.4-dc6eb4362
Scalable High-Availability cluster resource manager
st_output.c
Go to the documentation of this file.
1 /*
2  * Copyright 2019-2022 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 #include <stdarg.h>
12 #include <stdint.h>
13 
14 #include <crm/stonith-ng.h>
15 #include <crm/msg_xml.h>
16 #include <crm/common/iso8601.h>
17 #include <crm/common/util.h>
18 #include <crm/common/xml.h>
19 #include <crm/common/output.h>
22 #include <crm/fencing/internal.h>
23 #include <crm/pengine/internal.h>
24 
25 static char *
26 time_t_string(time_t when) {
27  crm_time_t *crm_when = crm_time_new(NULL);
28  char *buf = NULL;
29 
30  crm_time_set_timet(crm_when, &when);
32  crm_time_free(crm_when);
33  return buf;
34 }
35 
36 PCMK__OUTPUT_ARGS("failed-fencing-list", "stonith_history_t *", "GList *", "uint32_t",
37  "gboolean")
38 int
39 stonith__failed_history(pcmk__output_t *out, va_list args) {
40  stonith_history_t *history = va_arg(args, stonith_history_t *);
41  GList *only_node = va_arg(args, GList *);
42  uint32_t section_opts = va_arg(args, uint32_t);
43  gboolean print_spacer = va_arg(args, gboolean);
44 
45  int rc = pcmk_rc_no_output;
46 
47  for (stonith_history_t *hp = history; hp; hp = hp->next) {
48  if (hp->state != st_failed) {
49  continue;
50  }
51 
52  if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
53  continue;
54  }
55 
56  PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Failed Fencing Actions");
57  out->message(out, "stonith-event", hp, pcmk_all_flags_set(section_opts, pcmk_section_fencing_all),
58  stonith__later_succeeded(hp, history));
59  out->increment_list(out);
60  }
61 
62  PCMK__OUTPUT_LIST_FOOTER(out, rc);
63  return rc;
64 }
65 
66 PCMK__OUTPUT_ARGS("fencing-list", "stonith_history_t *", "GList *", "uint32_t", "gboolean")
67 int
68 stonith__history(pcmk__output_t *out, va_list args) {
69  stonith_history_t *history = va_arg(args, stonith_history_t *);
70  GList *only_node = va_arg(args, GList *);
71  uint32_t section_opts = va_arg(args, uint32_t);
72  gboolean print_spacer = va_arg(args, gboolean);
73 
74  int rc = pcmk_rc_no_output;
75 
76  for (stonith_history_t *hp = history; hp; hp = hp->next) {
77  if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
78  continue;
79  }
80 
81  if (hp->state != st_failed) {
82  PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Fencing History");
83  out->message(out, "stonith-event", hp, pcmk_all_flags_set(section_opts, pcmk_section_fencing_all),
84  stonith__later_succeeded(hp, history));
85  out->increment_list(out);
86  }
87  }
88 
89  PCMK__OUTPUT_LIST_FOOTER(out, rc);
90  return rc;
91 }
92 
93 PCMK__OUTPUT_ARGS("full-fencing-list", "crm_exit_t", "stonith_history_t *", "GList *",
94  "uint32_t", "gboolean")
95 int
96 stonith__full_history(pcmk__output_t *out, va_list args) {
97  crm_exit_t history_rc G_GNUC_UNUSED = va_arg(args, crm_exit_t);
98  stonith_history_t *history = va_arg(args, stonith_history_t *);
99  GList *only_node = va_arg(args, GList *);
100  uint32_t section_opts = va_arg(args, uint32_t);
101  gboolean print_spacer = va_arg(args, gboolean);
102 
103  int rc = pcmk_rc_no_output;
104 
105  for (stonith_history_t *hp = history; hp; hp = hp->next) {
106  if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
107  continue;
108  }
109 
110  PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Fencing History");
111  out->message(out, "stonith-event", hp, pcmk_all_flags_set(section_opts, pcmk_section_fencing_all),
112  stonith__later_succeeded(hp, history));
113  out->increment_list(out);
114  }
115 
116  PCMK__OUTPUT_LIST_FOOTER(out, rc);
117  return rc;
118 }
119 
120 PCMK__OUTPUT_ARGS("full-fencing-list", "crm_exit_t", "stonith_history_t *", "GList *",
121  "uint32_t", "gboolean")
122 static int
123 full_history_xml(pcmk__output_t *out, va_list args) {
124  crm_exit_t history_rc = va_arg(args, crm_exit_t);
125  stonith_history_t *history = va_arg(args, stonith_history_t *);
126  GList *only_node = va_arg(args, GList *);
127  uint32_t section_opts = va_arg(args, uint32_t);
128  gboolean print_spacer G_GNUC_UNUSED = va_arg(args, gboolean);
129 
130  int rc = pcmk_rc_no_output;
131 
132  if (history_rc == 0) {
133  for (stonith_history_t *hp = history; hp; hp = hp->next) {
134  if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
135  continue;
136  }
137 
138  PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Fencing History");
139  out->message(out, "stonith-event", hp, pcmk_all_flags_set(section_opts, pcmk_section_fencing_all),
140  stonith__later_succeeded(hp, history));
141  out->increment_list(out);
142  }
143 
144  PCMK__OUTPUT_LIST_FOOTER(out, rc);
145  } else {
146  char *rc_s = pcmk__itoa(history_rc);
147 
148  pcmk__output_create_xml_node(out, "fence_history",
149  "status", rc_s,
150  NULL);
151  free(rc_s);
152 
153  rc = pcmk_rc_ok;
154  }
155 
156  return rc;
157 }
158 
159 PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
160 static int
161 last_fenced_html(pcmk__output_t *out, va_list args) {
162  const char *target = va_arg(args, const char *);
163  time_t when = va_arg(args, time_t);
164 
165  if (when) {
166  char *buf = crm_strdup_printf("Node %s last fenced at: %s", target, ctime(&when));
167  pcmk__output_create_html_node(out, "div", NULL, NULL, buf);
168  free(buf);
169  return pcmk_rc_ok;
170  } else {
171  return pcmk_rc_no_output;
172  }
173 }
174 
175 PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
176 static int
177 last_fenced_text(pcmk__output_t *out, va_list args) {
178  const char *target = va_arg(args, const char *);
179  time_t when = va_arg(args, time_t);
180 
181  if (when) {
182  pcmk__indented_printf(out, "Node %s last fenced at: %s", target, ctime(&when));
183  } else {
184  pcmk__indented_printf(out, "Node %s has never been fenced\n", target);
185  }
186 
187  return pcmk_rc_ok;
188 }
189 
190 PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
191 static int
192 last_fenced_xml(pcmk__output_t *out, va_list args) {
193  const char *target = va_arg(args, const char *);
194  time_t when = va_arg(args, time_t);
195 
196  if (when) {
197  char *buf = time_t_string(when);
198 
199  pcmk__output_create_xml_node(out, "last-fenced",
200  "target", target,
201  "when", buf,
202  NULL);
203 
204  free(buf);
205  return pcmk_rc_ok;
206  } else {
207  return pcmk_rc_no_output;
208  }
209 }
210 
211 PCMK__OUTPUT_ARGS("pending-fencing-list", "stonith_history_t *", "GList *", "uint32_t",
212  "gboolean")
213 int
214 stonith__pending_actions(pcmk__output_t *out, va_list args) {
215  stonith_history_t *history = va_arg(args, stonith_history_t *);
216  GList *only_node = va_arg(args, GList *);
217  uint32_t section_opts = va_arg(args, uint32_t);
218  gboolean print_spacer = va_arg(args, gboolean);
219 
220  int rc = pcmk_rc_no_output;
221 
222  for (stonith_history_t *hp = history; hp; hp = hp->next) {
223  if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
224  continue;
225  }
226 
227  /* Skip the rest of the history after we see a failed/done action */
228  if ((hp->state == st_failed) || (hp->state == st_done)) {
229  break;
230  }
231 
232  PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Pending Fencing Actions");
233  out->message(out, "stonith-event", hp, pcmk_all_flags_set(section_opts, pcmk_section_fencing_all),
234  stonith__later_succeeded(hp, history));
235  out->increment_list(out);
236  }
237 
238  PCMK__OUTPUT_LIST_FOOTER(out, rc);
239  return rc;
240 }
241 
242 PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "gboolean", "gboolean")
243 static int
244 stonith_event_html(pcmk__output_t *out, va_list args) {
245  stonith_history_t *event = va_arg(args, stonith_history_t *);
246  gboolean full_history = va_arg(args, gboolean);
247  gboolean later_succeeded = va_arg(args, gboolean);
248 
249  switch(event->state) {
250  case st_done: {
251  char *completed_s = time_t_string(event->completed);
252 
253  out->list_item(out, "successful-stonith-event",
254  "%s of %s successful: delegate=%s, client=%s, origin=%s, %s='%s'",
255  stonith_action_str(event->action), event->target,
256  event->delegate ? event->delegate : "",
257  event->client, event->origin,
258  full_history ? "completed" : "last-successful",
259  completed_s);
260  free(completed_s);
261  break;
262  }
263 
264  case st_failed: {
265  char *failed_s = time_t_string(event->completed);
266 
267  out->list_item(out, "failed-stonith-event",
268  "%s of %s failed%s%s%s: "
269  "delegate=%s, client=%s, origin=%s, %s='%s' %s",
270  stonith_action_str(event->action), event->target,
271  (event->exit_reason == NULL)? "" : " (",
272  (event->exit_reason == NULL)? "" : event->exit_reason,
273  (event->exit_reason == NULL)? "" : ")",
274  event->delegate ? event->delegate : "",
275  event->client, event->origin,
276  full_history ? "completed" : "last-failed",
277  failed_s,
278  later_succeeded ? "(a later attempt succeeded)" : "");
279  free(failed_s);
280  break;
281  }
282 
283  default:
284  out->list_item(out, "pending-stonith-event",
285  "%s of %s pending: client=%s, origin=%s",
286  stonith_action_str(event->action), event->target,
287  event->client, event->origin);
288  break;
289  }
290 
291  return pcmk_rc_ok;
292 }
293 
294 PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "gboolean", "gboolean")
295 static int
296 stonith_event_text(pcmk__output_t *out, va_list args) {
297  stonith_history_t *event = va_arg(args, stonith_history_t *);
298  gboolean full_history = va_arg(args, gboolean);
299  gboolean later_succeeded = va_arg(args, gboolean);
300 
301  char *buf = time_t_string(event->completed);
302 
303  switch (event->state) {
304  case st_failed:
306  "%s of %s failed%s%s%s: "
307  "delegate=%s, client=%s, origin=%s, %s='%s' %s\n",
308  stonith_action_str(event->action), event->target,
309  (event->exit_reason == NULL)? "" : " (",
310  (event->exit_reason == NULL)? "" : event->exit_reason,
311  (event->exit_reason == NULL)? "" : ")",
312  event->delegate ? event->delegate : "",
313  event->client, event->origin,
314  full_history ? "completed" : "last-failed", buf,
315  later_succeeded ? "(a later attempt succeeded)" : "");
316  break;
317 
318  case st_done:
319  pcmk__indented_printf(out, "%s of %s successful: delegate=%s, client=%s, origin=%s, %s='%s'\n",
320  stonith_action_str(event->action), event->target,
321  event->delegate ? event->delegate : "",
322  event->client, event->origin,
323  full_history ? "completed" : "last-successful", buf);
324  break;
325 
326  default:
327  pcmk__indented_printf(out, "%s of %s pending: client=%s, origin=%s\n",
328  stonith_action_str(event->action), event->target,
329  event->client, event->origin);
330  break;
331  }
332 
333  free(buf);
334  return pcmk_rc_ok;
335 }
336 
337 PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "gboolean", "gboolean")
338 static int
339 stonith_event_xml(pcmk__output_t *out, va_list args) {
340  stonith_history_t *event = va_arg(args, stonith_history_t *);
341  gboolean full_history G_GNUC_UNUSED = va_arg(args, gboolean);
342  gboolean later_succeeded G_GNUC_UNUSED = va_arg(args, gboolean);
343 
344  char *buf = NULL;
345 
346  xmlNodePtr node = pcmk__output_create_xml_node(out, "fence_event",
347  "action", event->action,
348  "target", event->target,
349  "client", event->client,
350  "origin", event->origin,
351  NULL);
352 
353  switch (event->state) {
354  case st_failed:
355  pcmk__xe_set_props(node, "status", "failed",
356  XML_LRM_ATTR_EXIT_REASON, event->exit_reason,
357  NULL);
358  break;
359 
360  case st_done:
361  crm_xml_add(node, "status", "success");
362  break;
363 
364  default: {
365  char *state = pcmk__itoa(event->state);
366  pcmk__xe_set_props(node, "status", "pending",
367  "extended-status", state,
368  NULL);
369  free(state);
370  break;
371  }
372  }
373 
374  if (event->delegate != NULL) {
375  crm_xml_add(node, "delegate", event->delegate);
376  }
377 
378  if (event->state == st_failed || event->state == st_done) {
379  buf = time_t_string(event->completed);
380  crm_xml_add(node, "completed", buf);
381  free(buf);
382  }
383 
384  return pcmk_rc_ok;
385 }
386 
387 PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "char *", "char *", "int")
388 static int
389 validate_agent_html(pcmk__output_t *out, va_list args) {
390  const char *agent = va_arg(args, const char *);
391  const char *device = va_arg(args, const char *);
392  char *output = va_arg(args, char *);
393  char *error_output = va_arg(args, char *);
394  int rc = va_arg(args, int);
395 
396  if (device) {
397  char *buf = crm_strdup_printf("Validation of %s on %s %s", agent, device,
398  rc ? "failed" : "succeeded");
399  pcmk__output_create_html_node(out, "div", NULL, NULL, buf);
400  free(buf);
401  } else {
402  char *buf = crm_strdup_printf("Validation of %s %s", agent,
403  rc ? "failed" : "succeeded");
404  pcmk__output_create_html_node(out, "div", NULL, NULL, buf);
405  free(buf);
406  }
407 
408  out->subprocess_output(out, rc, output, error_output);
409  return rc;
410 }
411 
412 PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "char *", "char *", "int")
413 static int
414 validate_agent_text(pcmk__output_t *out, va_list args) {
415  const char *agent = va_arg(args, const char *);
416  const char *device = va_arg(args, const char *);
417  char *output = va_arg(args, char *);
418  char *error_output = va_arg(args, char *);
419  int rc = va_arg(args, int);
420 
421  if (device) {
422  pcmk__indented_printf(out, "Validation of %s on %s %s\n", agent, device,
423  rc ? "failed" : "succeeded");
424  } else {
425  pcmk__indented_printf(out, "Validation of %s %s\n", agent,
426  rc ? "failed" : "succeeded");
427  }
428 
429  out->subprocess_output(out, rc, output, error_output);
430  return rc;
431 }
432 
433 PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "char *", "char *", "int")
434 static int
435 validate_agent_xml(pcmk__output_t *out, va_list args) {
436  const char *agent = va_arg(args, const char *);
437  const char *device = va_arg(args, const char *);
438  char *output = va_arg(args, char *);
439  char *error_output = va_arg(args, char *);
440  int rc = va_arg(args, int);
441 
442  xmlNodePtr node = pcmk__output_create_xml_node(out, "validate",
443  "agent", agent,
444  "valid", pcmk__btoa(rc),
445  NULL);
446 
447  if (device != NULL) {
448  crm_xml_add(node, "device", device);
449  }
450 
451  pcmk__output_xml_push_parent(out, node);
452  out->subprocess_output(out, rc, output, error_output);
454 
455  return rc;
456 }
457 
458 static pcmk__message_entry_t fmt_functions[] = {
459  { "failed-fencing-list", "default", stonith__failed_history },
460  { "fencing-list", "default", stonith__history },
461  { "full-fencing-list", "default", stonith__full_history },
462  { "full-fencing-list", "xml", full_history_xml },
463  { "last-fenced", "html", last_fenced_html },
464  { "last-fenced", "log", last_fenced_text },
465  { "last-fenced", "text", last_fenced_text },
466  { "last-fenced", "xml", last_fenced_xml },
467  { "pending-fencing-list", "default", stonith__pending_actions },
468  { "stonith-event", "html", stonith_event_html },
469  { "stonith-event", "log", stonith_event_text },
470  { "stonith-event", "text", stonith_event_text },
471  { "stonith-event", "xml", stonith_event_xml },
472  { "validate", "html", validate_agent_html },
473  { "validate", "log", validate_agent_text },
474  { "validate", "text", validate_agent_text },
475  { "validate", "xml", validate_agent_xml },
476 
477  { NULL, NULL, NULL }
478 };
479 
480 void
482  pcmk__register_messages(out, fmt_functions);
483 }
struct stonith_history_s * next
Definition: stonith-ng.h:112
Control output from tools.
#define crm_time_log_timeofday
Definition: iso8601.h:67
struct crm_time_s crm_time_t
Definition: iso8601.h:32
int stonith__full_history(pcmk__output_t *out, va_list args)
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:323
enum crm_exit_e crm_exit_t
xmlNodePtr pcmk__output_create_html_node(pcmk__output_t *out, const char *element_name, const char *id, const char *class_name, const char *text)
Definition: output_html.c:424
PCMK__OUTPUT_ARGS("failed-fencing-list", "stonith_history_t *", "GList *", "uint32_t", "gboolean")
Definition: st_output.c:36
Formatted output for pacemaker tools.
int stonith__history(pcmk__output_t *out, va_list args)
Definition: st_output.c:68
void pcmk__output_xml_push_parent(pcmk__output_t *out, xmlNodePtr node)
Definition: output_xml.c:496
const char * stonith_action_str(const char *action)
Turn stonith action into a more readable string.
Definition: st_client.c:2042
Utility functions.
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
void crm_time_set_timet(crm_time_t *target, time_t *source)
Definition: iso8601.c:1255
void stonith__register_messages(pcmk__output_t *out)
Definition: st_output.c:481
gboolean stonith__later_succeeded(stonith_history_t *event, stonith_history_t *top_history)
Definition: st_client.c:2190
Wrappers for and extensions to libxml2.
void pcmk__indented_printf(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
gboolean pcmk__str_in_list(const gchar *s, GList *lst, uint32_t flags)
Definition: strings.c:886
ISO_8601 Date handling.
xmlNodePtr pcmk__output_create_xml_node(pcmk__output_t *out, const char *name,...) G_GNUC_NULL_TERMINATED
Definition: output_xml.c:466
#define XML_LRM_ATTR_EXIT_REASON
Definition: msg_xml.h:321
#define pcmk_section_fencing_all
Definition: output.h:46
#define crm_time_log_with_timezone
Definition: iso8601.h:68
void pcmk__output_xml_pop_parent(pcmk__output_t *out)
Definition: output_xml.c:512
void pcmk__xe_set_props(xmlNodePtr node,...) G_GNUC_NULL_TERMINATED
Definition: xml.c:2974
char * crm_time_as_string(crm_time_t *dt, int flags)
Definition: iso8601.c:496
#define PCMK__OUTPUT_LIST_FOOTER(out_obj, retcode)
const char * target
Definition: pcmk_fence.c:28
#define PCMK__OUTPUT_LIST_HEADER(out_obj, cond, retcode, title...)
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:92
Fencing aka. STONITH.
This structure contains everything that makes up a single output formatter.
int stonith__failed_history(pcmk__output_t *out, va_list args)
void pcmk__register_messages(pcmk__output_t *out, pcmk__message_entry_t *table)
Definition: output.c:145
int stonith__pending_actions(pcmk__output_t *out, va_list args)
#define crm_time_log_date
Definition: iso8601.h:66
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:140