pacemaker 2.1.4-dc6eb4362e
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>
24
25static char *
26time_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
36PCMK__OUTPUT_ARGS("failed-fencing-list", "stonith_history_t *", "GList *", "uint32_t",
37 "gboolean")
38int
39stonith__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
63 return rc;
64}
65
66PCMK__OUTPUT_ARGS("fencing-list", "stonith_history_t *", "GList *", "uint32_t", "gboolean")
67int
68stonith__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
90 return rc;
91}
92
93PCMK__OUTPUT_ARGS("full-fencing-list", "crm_exit_t", "stonith_history_t *", "GList *",
94 "uint32_t", "gboolean")
95int
96stonith__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
117 return rc;
118}
119
120PCMK__OUTPUT_ARGS("full-fencing-list", "crm_exit_t", "stonith_history_t *", "GList *",
121 "uint32_t", "gboolean")
122static int
123full_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
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
159PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
160static int
161last_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
175PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
176static int
177last_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
190PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
191static int
192last_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
211PCMK__OUTPUT_ARGS("pending-fencing-list", "stonith_history_t *", "GList *", "uint32_t",
212 "gboolean")
213int
214stonith__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
239 return rc;
240}
241
242PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "gboolean", "gboolean")
243static int
244stonith_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
294PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "gboolean", "gboolean")
295static int
296stonith_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
337PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "gboolean", "gboolean")
338static int
339stonith_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
387PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "char *", "char *", "int")
388static int
389validate_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
412PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "char *", "char *", "int")
413static int
414validate_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
433PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "char *", "char *", "int")
434static int
435validate_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
452 out->subprocess_output(out, rc, output, error_output);
454
455 return rc;
456}
457
458static 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
480void
482 pcmk__register_messages(out, fmt_functions);
483}
Utility functions.
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
int stonith__pending_actions(pcmk__output_t *out, va_list args)
gboolean stonith__later_succeeded(stonith_history_t *event, stonith_history_t *top_history)
Definition: st_client.c:2190
int stonith__failed_history(pcmk__output_t *out, va_list args)
int stonith__full_history(pcmk__output_t *out, va_list args)
ISO_8601 Date handling.
#define crm_time_log_timeofday
Definition: iso8601.h:67
char * crm_time_as_string(crm_time_t *dt, int flags)
Definition: iso8601.c:496
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:140
void crm_time_set_timet(crm_time_t *target, time_t *source)
Definition: iso8601.c:1255
#define crm_time_log_with_timezone
Definition: iso8601.h:68
#define crm_time_log_date
Definition: iso8601.h:66
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:92
struct crm_time_s crm_time_t
Definition: iso8601.h:32
#define XML_LRM_ATTR_EXIT_REASON
Definition: msg_xml.h:321
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
Control output from tools.
#define pcmk_section_fencing_all
Definition: output.h:46
Formatted output for pacemaker tools.
void pcmk__output_xml_pop_parent(pcmk__output_t *out)
Definition: output_xml.c:512
void pcmk__register_messages(pcmk__output_t *out, pcmk__message_entry_t *table)
Definition: output.c:145
#define PCMK__OUTPUT_LIST_HEADER(out_obj, cond, retcode, title...)
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
void pcmk__indented_printf(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
xmlNodePtr pcmk__output_create_xml_node(pcmk__output_t *out, const char *name,...) G_GNUC_NULL_TERMINATED
Definition: output_xml.c:466
void pcmk__output_xml_push_parent(pcmk__output_t *out, xmlNodePtr node)
Definition: output_xml.c:496
#define PCMK__OUTPUT_LIST_FOOTER(out_obj, retcode)
const char * target
Definition: pcmk_fence.c:28
@ pcmk_rc_no_output
Definition: results.h:116
@ pcmk_rc_ok
Definition: results.h:146
enum crm_exit_e crm_exit_t
PCMK__OUTPUT_ARGS("failed-fencing-list", "stonith_history_t *", "GList *", "uint32_t", "gboolean")
Definition: st_output.c:36
int stonith__history(pcmk__output_t *out, va_list args)
Definition: st_output.c:68
void stonith__register_messages(pcmk__output_t *out)
Definition: st_output.c:481
Fencing aka. STONITH.
const char * stonith_action_str(const char *action)
Turn stonith action into a more readable string.
Definition: st_client.c:2042
@ st_failed
Definition: stonith-ng.h:77
@ st_done
Definition: stonith-ng.h:75
gboolean pcmk__str_in_list(const gchar *s, GList *lst, uint32_t flags)
Definition: strings.c:886
@ pcmk__str_star_matches
@ pcmk__str_casei
This structure contains everything that makes up a single output formatter.
struct stonith_history_s * next
Definition: stonith-ng.h:112
Wrappers for and extensions to libxml2.
void pcmk__xe_set_props(xmlNodePtr node,...) G_GNUC_NULL_TERMINATED
Definition: xml.c:2974