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