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