Line data Source code
1 : /*
2 : * Copyright 2019-2024 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/common/iso8601.h>
16 : #include <crm/common/util.h>
17 : #include <crm/common/xml.h>
18 : #include <crm/common/output.h>
19 : #include <crm/common/output_internal.h>
20 : #include <crm/common/xml_internal.h>
21 : #include <crm/fencing/internal.h>
22 : #include <crm/pengine/internal.h>
23 :
24 : /*!
25 : * \internal
26 : * \brief Convert seconds and nanoseconds to a date/time/time-zone string
27 : *
28 : * \param[in] sec Seconds
29 : * \param[in] nsec Nanoseconds
30 : * \param[in] show_usec Whether to show time in microseconds resolution (if
31 : * false, use seconds resolution)
32 : *
33 : * \return A string representation of \p sec and \nsec
34 : *
35 : * \note The caller is responsible for freeing the return value using \p free().
36 : */
37 : static char *
38 0 : timespec_string(time_t sec, long nsec, bool show_usec) {
39 0 : const struct timespec ts = {
40 : .tv_sec = sec,
41 : .tv_nsec = nsec,
42 : };
43 :
44 0 : return pcmk__timespec2str(&ts,
45 : crm_time_log_date
46 : |crm_time_log_timeofday
47 : |crm_time_log_with_timezone
48 : |(show_usec? crm_time_usecs : 0));
49 : }
50 :
51 : /*!
52 : * \internal
53 : * \brief Return a status-friendly description of fence history entry state
54 : *
55 : * \param[in] history Fence history entry to describe
56 : *
57 : * \return One-word description of history entry state
58 : * \note This is similar to stonith_op_state_str() except user-oriented (i.e.
59 : * for cluster status) instead of developer-oriented (for debug logs).
60 : */
61 : static const char *
62 0 : state_str(const stonith_history_t *history)
63 : {
64 0 : switch (history->state) {
65 0 : case st_failed: return "failed";
66 0 : case st_done: return "successful";
67 0 : default: return "pending";
68 : }
69 : }
70 :
71 : /*!
72 : * \internal
73 : * \brief Create a description of a fencing history entry for status displays
74 : *
75 : * \param[in] history Fencing history entry to describe
76 : * \param[in] full_history Whether this is for full or condensed history
77 : * \param[in] later_succeeded Node that a later equivalent attempt succeeded
78 : * from, or NULL if none
79 : * \param[in] show_opts Flag group of pcmk_show_opt_e
80 : *
81 : * \return Newly created string with fencing history entry description
82 : *
83 : * \note The caller is responsible for freeing the return value with g_free().
84 : * \note This is similar to stonith__event_description(), except this is used
85 : * for history entries (stonith_history_t) in status displays rather than
86 : * event notifications (stonith_event_t) in log messages.
87 : */
88 : gchar *
89 0 : stonith__history_description(const stonith_history_t *history,
90 : bool full_history, const char *later_succeeded,
91 : uint32_t show_opts)
92 : {
93 0 : GString *str = g_string_sized_new(256); // Generous starting size
94 0 : char *completed_time_s = NULL;
95 :
96 0 : if ((history->state == st_failed) || (history->state == st_done)) {
97 0 : completed_time_s = timespec_string(history->completed,
98 0 : history->completed_nsec, true);
99 : }
100 :
101 0 : pcmk__g_strcat(str,
102 0 : stonith_action_str(history->action), " of ", history->target,
103 : NULL);
104 :
105 0 : if (!pcmk_is_set(show_opts, pcmk_show_failed_detail)) {
106 : // More human-friendly
107 0 : if (((history->state == st_failed) || (history->state == st_done))
108 0 : && (history->delegate != NULL)) {
109 :
110 0 : pcmk__g_strcat(str, " by ", history->delegate, NULL);
111 : }
112 0 : pcmk__g_strcat(str, " for ", history->client, "@", history->origin,
113 : NULL);
114 0 : if (!full_history) {
115 0 : g_string_append(str, " last"); // For example, "last failed at ..."
116 : }
117 : }
118 :
119 0 : pcmk__add_word(&str, 0, state_str(history));
120 :
121 : // For failed actions, add exit reason if available
122 0 : if ((history->state == st_failed) && (history->exit_reason != NULL)) {
123 0 : pcmk__g_strcat(str, " (", history->exit_reason, ")", NULL);
124 : }
125 :
126 0 : if (pcmk_is_set(show_opts, pcmk_show_failed_detail)) {
127 : // More technical
128 0 : g_string_append(str, ": ");
129 :
130 : // For completed actions, add delegate if available
131 0 : if (((history->state == st_failed) || (history->state == st_done))
132 0 : && (history->delegate != NULL)) {
133 :
134 0 : pcmk__g_strcat(str, PCMK_XA_DELEGATE "=", history->delegate, ", ",
135 : NULL);
136 : }
137 :
138 : // Add information about originator
139 0 : pcmk__g_strcat(str,
140 0 : PCMK_XA_CLIENT "=", history->client, ", "
141 0 : PCMK_XA_ORIGIN "=", history->origin, NULL);
142 :
143 : // For completed actions, add completion time
144 0 : if (completed_time_s != NULL) {
145 0 : if (full_history) {
146 0 : g_string_append(str, ", completed");
147 0 : } else if (history->state == st_failed) {
148 0 : g_string_append(str, ", last-failed");
149 : } else {
150 0 : g_string_append(str, ", last-successful");
151 : }
152 0 : pcmk__g_strcat(str, "='", completed_time_s, "'", NULL);
153 : }
154 0 : } else if (completed_time_s != NULL) {
155 : // More human-friendly
156 0 : pcmk__g_strcat(str, " at ", completed_time_s, NULL);
157 : }
158 :
159 0 : if ((history->state == st_failed) && (later_succeeded != NULL)) {
160 0 : pcmk__g_strcat(str,
161 : " (a later attempt from ", later_succeeded,
162 : " succeeded)", NULL);
163 : }
164 :
165 0 : free(completed_time_s);
166 0 : return g_string_free(str, FALSE);
167 : }
168 :
169 : PCMK__OUTPUT_ARGS("failed-fencing-list", "stonith_history_t *", "GList *",
170 : "uint32_t", "uint32_t", "bool")
171 : static int
172 0 : failed_history(pcmk__output_t *out, va_list args)
173 : {
174 0 : stonith_history_t *history = va_arg(args, stonith_history_t *);
175 0 : GList *only_node = va_arg(args, GList *);
176 0 : uint32_t section_opts = va_arg(args, uint32_t);
177 0 : uint32_t show_opts = va_arg(args, uint32_t);
178 0 : bool print_spacer = va_arg(args, int);
179 :
180 0 : int rc = pcmk_rc_no_output;
181 :
182 0 : for (stonith_history_t *hp = history; hp; hp = hp->next) {
183 0 : if (hp->state != st_failed) {
184 0 : continue;
185 : }
186 :
187 0 : if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
188 0 : continue;
189 : }
190 :
191 0 : PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Failed Fencing Actions");
192 0 : out->message(out, "stonith-event", hp,
193 0 : pcmk_all_flags_set(section_opts, pcmk_section_fencing_all),
194 : false, stonith__later_succeeded(hp, history), show_opts);
195 0 : out->increment_list(out);
196 : }
197 :
198 0 : PCMK__OUTPUT_LIST_FOOTER(out, rc);
199 0 : return rc;
200 : }
201 :
202 : PCMK__OUTPUT_ARGS("fencing-list", "stonith_history_t *", "GList *", "uint32_t",
203 : "uint32_t", "bool")
204 : static int
205 0 : stonith_history(pcmk__output_t *out, va_list args)
206 : {
207 0 : stonith_history_t *history = va_arg(args, stonith_history_t *);
208 0 : GList *only_node = va_arg(args, GList *);
209 0 : uint32_t section_opts = va_arg(args, uint32_t);
210 0 : uint32_t show_opts = va_arg(args, uint32_t);
211 0 : bool print_spacer = va_arg(args, int);
212 :
213 0 : int rc = pcmk_rc_no_output;
214 :
215 0 : for (stonith_history_t *hp = history; hp; hp = hp->next) {
216 0 : if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
217 0 : continue;
218 : }
219 :
220 0 : if (hp->state != st_failed) {
221 0 : PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Fencing History");
222 0 : out->message(out, "stonith-event", hp,
223 0 : pcmk_all_flags_set(section_opts,
224 : pcmk_section_fencing_all),
225 : false, stonith__later_succeeded(hp, history), show_opts);
226 0 : out->increment_list(out);
227 : }
228 : }
229 :
230 0 : PCMK__OUTPUT_LIST_FOOTER(out, rc);
231 0 : return rc;
232 : }
233 :
234 : PCMK__OUTPUT_ARGS("full-fencing-list", "crm_exit_t", "stonith_history_t *",
235 : "GList *", "uint32_t", "uint32_t", "bool")
236 : static int
237 0 : full_history(pcmk__output_t *out, va_list args)
238 : {
239 0 : crm_exit_t history_rc G_GNUC_UNUSED = va_arg(args, crm_exit_t);
240 0 : stonith_history_t *history = va_arg(args, stonith_history_t *);
241 0 : GList *only_node = va_arg(args, GList *);
242 0 : uint32_t section_opts = va_arg(args, uint32_t);
243 0 : uint32_t show_opts = va_arg(args, uint32_t);
244 0 : bool print_spacer = va_arg(args, int);
245 :
246 0 : int rc = pcmk_rc_no_output;
247 :
248 0 : for (stonith_history_t *hp = history; hp; hp = hp->next) {
249 0 : if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
250 0 : continue;
251 : }
252 :
253 0 : PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Fencing History");
254 0 : out->message(out, "stonith-event", hp,
255 0 : pcmk_all_flags_set(section_opts, pcmk_section_fencing_all),
256 : false, stonith__later_succeeded(hp, history), show_opts);
257 0 : out->increment_list(out);
258 : }
259 :
260 0 : PCMK__OUTPUT_LIST_FOOTER(out, rc);
261 0 : return rc;
262 : }
263 :
264 : PCMK__OUTPUT_ARGS("full-fencing-list", "crm_exit_t", "stonith_history_t *",
265 : "GList *", "uint32_t", "uint32_t", "bool")
266 : static int
267 0 : full_history_xml(pcmk__output_t *out, va_list args)
268 : {
269 0 : crm_exit_t history_rc = va_arg(args, crm_exit_t);
270 0 : stonith_history_t *history = va_arg(args, stonith_history_t *);
271 0 : GList *only_node = va_arg(args, GList *);
272 0 : uint32_t section_opts = va_arg(args, uint32_t);
273 0 : uint32_t show_opts = va_arg(args, uint32_t);
274 0 : bool print_spacer G_GNUC_UNUSED = va_arg(args, int);
275 :
276 0 : int rc = pcmk_rc_no_output;
277 :
278 0 : if (history_rc == 0) {
279 0 : for (stonith_history_t *hp = history; hp; hp = hp->next) {
280 0 : if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
281 0 : continue;
282 : }
283 :
284 0 : PCMK__OUTPUT_LIST_HEADER(out, false, rc, "Fencing History");
285 0 : out->message(out, "stonith-event", hp,
286 0 : pcmk_all_flags_set(section_opts,
287 : pcmk_section_fencing_all),
288 : false, stonith__later_succeeded(hp, history), show_opts);
289 0 : out->increment_list(out);
290 : }
291 :
292 0 : PCMK__OUTPUT_LIST_FOOTER(out, rc);
293 : } else {
294 0 : char *rc_s = pcmk__itoa(history_rc);
295 :
296 0 : pcmk__output_create_xml_node(out, PCMK_XE_FENCE_HISTORY,
297 : PCMK_XA_STATUS, rc_s,
298 : NULL);
299 0 : free(rc_s);
300 :
301 0 : rc = pcmk_rc_ok;
302 : }
303 :
304 0 : return rc;
305 : }
306 :
307 : PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
308 : static int
309 0 : last_fenced_html(pcmk__output_t *out, va_list args) {
310 0 : const char *target = va_arg(args, const char *);
311 0 : time_t when = va_arg(args, time_t);
312 :
313 0 : if (when) {
314 0 : char *buf = crm_strdup_printf("Node %s last fenced at: %s", target, ctime(&when));
315 0 : pcmk__output_create_html_node(out, PCMK__XE_DIV, NULL, NULL, buf);
316 0 : free(buf);
317 0 : return pcmk_rc_ok;
318 : } else {
319 0 : return pcmk_rc_no_output;
320 : }
321 : }
322 :
323 : PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
324 : static int
325 0 : last_fenced_text(pcmk__output_t *out, va_list args) {
326 0 : const char *target = va_arg(args, const char *);
327 0 : time_t when = va_arg(args, time_t);
328 :
329 0 : if (when) {
330 0 : pcmk__indented_printf(out, "Node %s last fenced at: %s", target, ctime(&when));
331 : } else {
332 0 : pcmk__indented_printf(out, "Node %s has never been fenced\n", target);
333 : }
334 :
335 0 : return pcmk_rc_ok;
336 : }
337 :
338 : PCMK__OUTPUT_ARGS("last-fenced", "const char *", "time_t")
339 : static int
340 0 : last_fenced_xml(pcmk__output_t *out, va_list args) {
341 0 : const char *target = va_arg(args, const char *);
342 0 : time_t when = va_arg(args, time_t);
343 :
344 0 : if (when) {
345 0 : char *buf = timespec_string(when, 0, false);
346 :
347 0 : pcmk__output_create_xml_node(out, PCMK_XE_LAST_FENCED,
348 : PCMK_XA_TARGET, target,
349 : PCMK_XA_WHEN, buf,
350 : NULL);
351 :
352 0 : free(buf);
353 0 : return pcmk_rc_ok;
354 : } else {
355 0 : return pcmk_rc_no_output;
356 : }
357 : }
358 :
359 : PCMK__OUTPUT_ARGS("pending-fencing-list", "stonith_history_t *", "GList *",
360 : "uint32_t", "uint32_t", "bool")
361 : static int
362 0 : pending_actions(pcmk__output_t *out, va_list args)
363 : {
364 0 : stonith_history_t *history = va_arg(args, stonith_history_t *);
365 0 : GList *only_node = va_arg(args, GList *);
366 0 : uint32_t section_opts = va_arg(args, uint32_t);
367 0 : uint32_t show_opts = va_arg(args, uint32_t);
368 0 : bool print_spacer = va_arg(args, int);
369 :
370 0 : int rc = pcmk_rc_no_output;
371 :
372 0 : for (stonith_history_t *hp = history; hp; hp = hp->next) {
373 0 : if (!pcmk__str_in_list(hp->target, only_node, pcmk__str_star_matches|pcmk__str_casei)) {
374 0 : continue;
375 : }
376 :
377 : /* Skip the rest of the history after we see a failed/done action */
378 0 : if ((hp->state == st_failed) || (hp->state == st_done)) {
379 : break;
380 : }
381 :
382 0 : PCMK__OUTPUT_LIST_HEADER(out, print_spacer, rc, "Pending Fencing Actions");
383 0 : out->message(out, "stonith-event", hp,
384 0 : pcmk_all_flags_set(section_opts, pcmk_section_fencing_all),
385 : false, stonith__later_succeeded(hp, history), show_opts);
386 0 : out->increment_list(out);
387 : }
388 :
389 0 : PCMK__OUTPUT_LIST_FOOTER(out, rc);
390 0 : return rc;
391 : }
392 :
393 : PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "bool", "bool",
394 : "const char *", "uint32_t")
395 : static int
396 0 : stonith_event_html(pcmk__output_t *out, va_list args)
397 : {
398 0 : stonith_history_t *event = va_arg(args, stonith_history_t *);
399 0 : bool full_history = va_arg(args, int);
400 0 : bool completed_only G_GNUC_UNUSED = va_arg(args, int);
401 0 : const char *succeeded = va_arg(args, const char *);
402 0 : uint32_t show_opts = va_arg(args, uint32_t);
403 :
404 0 : gchar *desc = stonith__history_description(event, full_history, succeeded,
405 : show_opts);
406 :
407 0 : switch(event->state) {
408 0 : case st_done:
409 0 : out->list_item(out, "successful-stonith-event", "%s", desc);
410 0 : break;
411 :
412 0 : case st_failed:
413 0 : out->list_item(out, "failed-stonith-event", "%s", desc);
414 0 : break;
415 :
416 0 : default:
417 0 : out->list_item(out, "pending-stonith-event", "%s", desc);
418 0 : break;
419 : }
420 0 : g_free(desc);
421 0 : return pcmk_rc_ok;
422 : }
423 :
424 : PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "bool", "bool",
425 : "const char *", "uint32_t")
426 : static int
427 0 : stonith_event_text(pcmk__output_t *out, va_list args)
428 : {
429 0 : stonith_history_t *event = va_arg(args, stonith_history_t *);
430 0 : bool full_history = va_arg(args, int);
431 0 : bool completed_only = va_arg(args, int);
432 0 : const char *succeeded = va_arg(args, const char *);
433 0 : uint32_t show_opts = va_arg(args, uint32_t);
434 :
435 0 : if (completed_only) {
436 0 : pcmk__formatted_printf(out, "%lld\n", (long long) event->completed);
437 : } else {
438 0 : gchar *desc = stonith__history_description(event, full_history, succeeded,
439 : show_opts);
440 :
441 0 : pcmk__indented_printf(out, "%s\n", desc);
442 0 : g_free(desc);
443 : }
444 :
445 0 : return pcmk_rc_ok;
446 : }
447 :
448 : PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "bool", "bool",
449 : "const char *", "uint32_t")
450 : static int
451 0 : stonith_event_xml(pcmk__output_t *out, va_list args)
452 : {
453 0 : stonith_history_t *event = va_arg(args, stonith_history_t *);
454 0 : bool full_history G_GNUC_UNUSED = va_arg(args, int);
455 0 : bool completed_only G_GNUC_UNUSED = va_arg(args, int);
456 0 : const char *succeeded G_GNUC_UNUSED = va_arg(args, const char *);
457 0 : uint32_t show_opts G_GNUC_UNUSED = va_arg(args, uint32_t);
458 :
459 0 : xmlNodePtr node = NULL;
460 :
461 0 : node = pcmk__output_create_xml_node(out, PCMK_XE_FENCE_EVENT,
462 : PCMK_XA_ACTION, event->action,
463 : PCMK_XA_TARGET, event->target,
464 : PCMK_XA_CLIENT, event->client,
465 : PCMK_XA_ORIGIN, event->origin,
466 : NULL);
467 :
468 0 : switch (event->state) {
469 0 : case st_failed:
470 0 : pcmk__xe_set_props(node,
471 : PCMK_XA_STATUS, PCMK_VALUE_FAILED,
472 : PCMK_XA_EXIT_REASON, event->exit_reason,
473 : NULL);
474 0 : break;
475 :
476 0 : case st_done:
477 0 : crm_xml_add(node, PCMK_XA_STATUS, PCMK_VALUE_SUCCESS);
478 0 : break;
479 :
480 0 : default: {
481 0 : char *state = pcmk__itoa(event->state);
482 0 : pcmk__xe_set_props(node,
483 : PCMK_XA_STATUS, PCMK_VALUE_PENDING,
484 : PCMK_XA_EXTENDED_STATUS, state,
485 : NULL);
486 0 : free(state);
487 0 : break;
488 : }
489 : }
490 :
491 0 : if (event->delegate != NULL) {
492 0 : crm_xml_add(node, PCMK_XA_DELEGATE, event->delegate);
493 : }
494 :
495 0 : if ((event->state == st_failed) || (event->state == st_done)) {
496 0 : char *time_s = timespec_string(event->completed, event->completed_nsec,
497 : true);
498 :
499 0 : crm_xml_add(node, PCMK_XA_COMPLETED, time_s);
500 0 : free(time_s);
501 : }
502 :
503 0 : return pcmk_rc_ok;
504 : }
505 :
506 : PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "const char *",
507 : "const char *", "int")
508 : static int
509 0 : validate_agent_html(pcmk__output_t *out, va_list args) {
510 0 : const char *agent = va_arg(args, const char *);
511 0 : const char *device = va_arg(args, const char *);
512 0 : const char *output = va_arg(args, const char *);
513 0 : const char *error_output = va_arg(args, const char *);
514 0 : int rc = va_arg(args, int);
515 :
516 0 : if (device) {
517 0 : char *buf = crm_strdup_printf("Validation of %s on %s %s", agent, device,
518 : rc ? "failed" : "succeeded");
519 0 : pcmk__output_create_html_node(out, PCMK__XE_DIV, NULL, NULL, buf);
520 0 : free(buf);
521 : } else {
522 0 : char *buf = crm_strdup_printf("Validation of %s %s", agent,
523 : rc ? "failed" : "succeeded");
524 0 : pcmk__output_create_html_node(out, PCMK__XE_DIV, NULL, NULL, buf);
525 0 : free(buf);
526 : }
527 :
528 0 : out->subprocess_output(out, rc, output, error_output);
529 0 : return rc;
530 : }
531 :
532 : PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "const char *",
533 : "const char *", "int")
534 : static int
535 0 : validate_agent_text(pcmk__output_t *out, va_list args) {
536 0 : const char *agent = va_arg(args, const char *);
537 0 : const char *device = va_arg(args, const char *);
538 0 : const char *output = va_arg(args, const char *);
539 0 : const char *error_output = va_arg(args, const char *);
540 0 : int rc = va_arg(args, int);
541 :
542 0 : if (device) {
543 0 : pcmk__indented_printf(out, "Validation of %s on %s %s\n", agent, device,
544 : rc ? "failed" : "succeeded");
545 : } else {
546 0 : pcmk__indented_printf(out, "Validation of %s %s\n", agent,
547 : rc ? "failed" : "succeeded");
548 : }
549 :
550 0 : out->subprocess_output(out, rc, output, error_output);
551 0 : return rc;
552 : }
553 :
554 : PCMK__OUTPUT_ARGS("validate", "const char *", "const char *", "const char *",
555 : "const char *", "int")
556 : static int
557 0 : validate_agent_xml(pcmk__output_t *out, va_list args) {
558 0 : const char *agent = va_arg(args, const char *);
559 0 : const char *device = va_arg(args, const char *);
560 0 : const char *output = va_arg(args, const char *);
561 0 : const char *error_output = va_arg(args, const char *);
562 0 : int rc = va_arg(args, int);
563 :
564 0 : const char *valid = pcmk__btoa(rc == pcmk_ok);
565 0 : xmlNodePtr node = pcmk__output_create_xml_node(out, PCMK_XE_VALIDATE,
566 : PCMK_XA_AGENT, agent,
567 : PCMK_XA_VALID, valid,
568 : NULL);
569 :
570 0 : if (device != NULL) {
571 0 : crm_xml_add(node, PCMK_XA_DEVICE, device);
572 : }
573 :
574 0 : pcmk__output_xml_push_parent(out, node);
575 0 : out->subprocess_output(out, rc, output, error_output);
576 0 : pcmk__output_xml_pop_parent(out);
577 :
578 0 : return rc;
579 : }
580 :
581 : static pcmk__message_entry_t fmt_functions[] = {
582 : { "failed-fencing-list", "default", failed_history },
583 : { "fencing-list", "default", stonith_history },
584 : { "full-fencing-list", "default", full_history },
585 : { "full-fencing-list", "xml", full_history_xml },
586 : { "last-fenced", "html", last_fenced_html },
587 : { "last-fenced", "log", last_fenced_text },
588 : { "last-fenced", "text", last_fenced_text },
589 : { "last-fenced", "xml", last_fenced_xml },
590 : { "pending-fencing-list", "default", pending_actions },
591 : { "stonith-event", "html", stonith_event_html },
592 : { "stonith-event", "log", stonith_event_text },
593 : { "stonith-event", "text", stonith_event_text },
594 : { "stonith-event", "xml", stonith_event_xml },
595 : { "validate", "html", validate_agent_html },
596 : { "validate", "log", validate_agent_text },
597 : { "validate", "text", validate_agent_text },
598 : { "validate", "xml", validate_agent_xml },
599 :
600 : { NULL, NULL, NULL }
601 : };
602 :
603 : void
604 0 : stonith__register_messages(pcmk__output_t *out) {
605 0 : pcmk__register_messages(out, fmt_functions);
606 0 : }
|