This source file includes following definitions.
- handle_level
- reduce_fence_history
- notify_callback
- fence_callback
- async_fence_helper
- pcmk__request_fencing
- pcmk_request_fencing
- pcmk__fence_history
- pcmk_fence_history
- pcmk__fence_installed
- pcmk_fence_installed
- pcmk__fence_last
- pcmk_fence_last
- pcmk__fence_list_targets
- pcmk_fence_list_targets
- pcmk__fence_metadata
- pcmk_fence_metadata
- pcmk__fence_registered
- pcmk_fence_registered
- pcmk__fence_register_level
- pcmk_fence_register_level
- pcmk__fence_unregister_level
- pcmk_fence_unregister_level
- pcmk__fence_validate
- pcmk_fence_validate
- pcmk__get_fencing_history
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11 #include <crm/common/mainloop.h>
12 #include <crm/common/results.h>
13 #include <crm/common/output.h>
14 #include <crm/common/output_internal.h>
15 #include <crm/stonith-ng.h>
16 #include <crm/fencing/internal.h>
17
18 #include <glib.h>
19 #include <libxml/tree.h>
20 #include <pacemaker.h>
21 #include <pacemaker-internal.h>
22
23 #include "libpacemaker_private.h"
24
25 static const int st_opts = st_opt_sync_call|st_opt_allow_self_fencing;
26
27 static GMainLoop *mainloop = NULL;
28
29 static struct {
30 stonith_t *st;
31 const char *target;
32 const char *action;
33 char *name;
34 unsigned int timeout;
35 unsigned int tolerance;
36 int delay;
37 pcmk__action_result_t result;
38 } async_fence_data = { NULL, };
39
40 static int
41 handle_level(stonith_t *st, const char *target, int fence_level, GList *devices,
42 bool added)
43 {
44 const char *node = NULL;
45 const char *pattern = NULL;
46 const char *name = NULL;
47 char *value = NULL;
48 int rc = pcmk_rc_ok;
49
50 if (target == NULL) {
51
52 return EINVAL;
53 }
54
55
56 value = strchr(target, '=');
57 if (value != NULL) {
58 name = target;
59 *value++ = '\0';
60 } else if (*target == '@') {
61 pattern = target + 1;
62 } else {
63 node = target;
64 }
65
66
67 if (added) {
68 stonith_key_value_t *kvs = NULL;
69
70 for (GList *iter = devices; iter != NULL; iter = iter->next) {
71 kvs = stonith_key_value_add(kvs, NULL, iter->data);
72 }
73
74 rc = st->cmds->register_level_full(st, st_opts, node, pattern, name,
75 value, fence_level, kvs);
76 stonith_key_value_freeall(kvs, 0, 1);
77 } else {
78 rc = st->cmds->remove_level_full(st, st_opts, node, pattern,
79 name, value, fence_level);
80 }
81
82 return pcmk_legacy2rc(rc);
83 }
84
85 static stonith_history_t *
86 reduce_fence_history(stonith_history_t *history)
87 {
88 stonith_history_t *new, *hp, *np;
89
90 if (!history) {
91 return history;
92 }
93
94 new = history;
95 hp = new->next;
96 new->next = NULL;
97
98 while (hp) {
99 stonith_history_t *hp_next = hp->next;
100
101 hp->next = NULL;
102
103 for (np = new; ; np = np->next) {
104 if ((hp->state == st_done) || (hp->state == st_failed)) {
105
106 if (pcmk__str_eq(hp->target, np->target, pcmk__str_casei)
107 && pcmk__str_eq(hp->action, np->action, pcmk__str_none)
108 && (hp->state == np->state)
109 && ((hp->state == st_done)
110 || pcmk__str_eq(hp->delegate, np->delegate,
111 pcmk__str_casei))) {
112
113 stonith_history_free(hp);
114 break;
115 }
116 }
117
118 if (!np->next) {
119 np->next = hp;
120 break;
121 }
122 }
123 hp = hp_next;
124 }
125
126 return new;
127 }
128
129 static void
130 notify_callback(stonith_t * st, stonith_event_t * e)
131 {
132 if (pcmk__str_eq(async_fence_data.target, e->target, pcmk__str_casei)
133 && pcmk__str_eq(async_fence_data.action, e->action, pcmk__str_none)) {
134
135 pcmk__set_result(&async_fence_data.result,
136 stonith__event_exit_status(e),
137 stonith__event_execution_status(e),
138 stonith__event_exit_reason(e));
139 g_main_loop_quit(mainloop);
140 }
141 }
142
143 static void
144 fence_callback(stonith_t * stonith, stonith_callback_data_t * data)
145 {
146 pcmk__set_result(&async_fence_data.result, stonith__exit_status(data),
147 stonith__execution_status(data),
148 stonith__exit_reason(data));
149 g_main_loop_quit(mainloop);
150 }
151
152 static gboolean
153 async_fence_helper(gpointer user_data)
154 {
155 stonith_t *st = async_fence_data.st;
156 int call_id = 0;
157 int rc = stonith_api_connect_retry(st, async_fence_data.name, 10);
158 int timeout = 0;
159
160 if (rc != pcmk_ok) {
161 g_main_loop_quit(mainloop);
162 pcmk__set_result(&async_fence_data.result, CRM_EX_ERROR,
163 PCMK_EXEC_NOT_CONNECTED, pcmk_strerror(rc));
164 return TRUE;
165 }
166
167 st->cmds->register_notification(st, PCMK__VALUE_ST_NOTIFY_FENCE,
168 notify_callback);
169
170 call_id = st->cmds->fence_with_delay(st,
171 st_opt_allow_self_fencing,
172 async_fence_data.target,
173 async_fence_data.action,
174 pcmk__timeout_ms2s(async_fence_data.timeout),
175 pcmk__timeout_ms2s(async_fence_data.tolerance),
176 async_fence_data.delay);
177
178 if (call_id < 0) {
179 g_main_loop_quit(mainloop);
180 pcmk__set_result(&async_fence_data.result, CRM_EX_ERROR,
181 PCMK_EXEC_ERROR, pcmk_strerror(call_id));
182 return TRUE;
183 }
184
185 timeout = pcmk__timeout_ms2s(async_fence_data.timeout);
186 if (async_fence_data.delay > 0) {
187 timeout += async_fence_data.delay;
188 }
189 st->cmds->register_callback(st, call_id, timeout, st_opt_timeout_updates,
190 NULL, "callback", fence_callback);
191 return TRUE;
192 }
193
194 int
195 pcmk__request_fencing(stonith_t *st, const char *target, const char *action,
196 const char *name, unsigned int timeout,
197 unsigned int tolerance, int delay, char **reason)
198 {
199 crm_trigger_t *trig;
200 int rc = pcmk_rc_ok;
201
202 async_fence_data.st = st;
203 async_fence_data.name = strdup(name);
204 async_fence_data.target = target;
205 async_fence_data.action = action;
206 async_fence_data.timeout = timeout;
207 async_fence_data.tolerance = tolerance;
208 async_fence_data.delay = delay;
209 pcmk__set_result(&async_fence_data.result, CRM_EX_ERROR, PCMK_EXEC_UNKNOWN,
210 NULL);
211
212 trig = mainloop_add_trigger(G_PRIORITY_HIGH, async_fence_helper, NULL);
213 mainloop_set_trigger(trig);
214
215 mainloop = g_main_loop_new(NULL, FALSE);
216 g_main_loop_run(mainloop);
217
218 free(async_fence_data.name);
219
220 if (reason != NULL) {
221
222 *reason = async_fence_data.result.exit_reason;
223 async_fence_data.result.exit_reason = NULL;
224 }
225 rc = stonith__result2rc(&async_fence_data.result);
226 pcmk__reset_result(&async_fence_data.result);
227 return rc;
228 }
229
230 int
231 pcmk_request_fencing(xmlNodePtr *xml, const char *target, const char *action,
232 const char *name, unsigned int timeout,
233 unsigned int tolerance, int delay, char **reason)
234 {
235 stonith_t *st = NULL;
236 pcmk__output_t *out = NULL;
237 int rc = pcmk_rc_ok;
238
239 rc = pcmk__setup_output_fencing(&out, &st, xml);
240 if (rc != pcmk_rc_ok) {
241 return rc;
242 }
243
244 rc = pcmk__request_fencing(st, target, action, name, timeout, tolerance,
245 delay, reason);
246 pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
247
248 st->cmds->disconnect(st);
249 stonith_api_delete(st);
250 return rc;
251 }
252
253 int
254 pcmk__fence_history(pcmk__output_t *out, stonith_t *st, const char *target,
255 unsigned int timeout, int verbose, bool broadcast,
256 bool cleanup)
257 {
258 stonith_history_t *history = NULL;
259 stonith_history_t *latest = NULL;
260 int rc = pcmk_rc_ok;
261 int opts = 0;
262
263 if (cleanup) {
264 out->info(out, "cleaning up fencing-history%s%s",
265 target ? " for node " : "", target ? target : "");
266 }
267
268 if (broadcast) {
269 out->info(out, "gather fencing-history from all nodes");
270 }
271
272 stonith__set_call_options(opts, target, st_opts);
273
274 if (cleanup) {
275 stonith__set_call_options(opts, target, st_opt_cleanup);
276 }
277
278 if (broadcast) {
279 stonith__set_call_options(opts, target, st_opt_broadcast);
280 }
281
282 if (pcmk__str_eq(target, "*", pcmk__str_none)) {
283 target = NULL;
284 }
285
286 rc = st->cmds->history(st, opts, target, &history, pcmk__timeout_ms2s(timeout));
287
288 if (cleanup) {
289
290 stonith_history_free(history);
291 return pcmk_legacy2rc(rc);
292 }
293
294 out->begin_list(out, "event", "events", "Fencing history");
295
296 history = stonith__sort_history(history);
297 for (stonith_history_t *hp = history; hp != NULL; hp = hp->next) {
298 if (hp->state == st_done) {
299 latest = hp;
300 }
301
302 if (out->is_quiet(out) || !verbose) {
303 continue;
304 }
305
306 out->message(out, "stonith-event", hp, true, false,
307 stonith__later_succeeded(hp, history),
308 (uint32_t) pcmk_show_failed_detail);
309 out->increment_list(out);
310 }
311
312 if (latest) {
313 if (out->is_quiet(out)) {
314 out->message(out, "stonith-event", latest, false, true, NULL,
315 (uint32_t) pcmk_show_failed_detail);
316 } else if (!verbose) {
317 out->message(out, "stonith-event", latest, false, false, NULL,
318 (uint32_t) pcmk_show_failed_detail);
319 out->increment_list(out);
320 }
321 }
322
323 out->end_list(out);
324
325 stonith_history_free(history);
326 return pcmk_legacy2rc(rc);
327 }
328
329 int
330 pcmk_fence_history(xmlNodePtr *xml, const char *target, unsigned int timeout,
331 bool quiet, int verbose, bool broadcast, bool cleanup)
332 {
333 stonith_t *st = NULL;
334 pcmk__output_t *out = NULL;
335 int rc = pcmk_rc_ok;
336
337 rc = pcmk__setup_output_fencing(&out, &st, xml);
338 if (rc != pcmk_rc_ok) {
339 return rc;
340 }
341
342 out->quiet = quiet;
343
344 rc = pcmk__fence_history(out, st, target, timeout, verbose, broadcast,
345 cleanup);
346 pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
347
348 st->cmds->disconnect(st);
349 stonith_api_delete(st);
350 return rc;
351 }
352
353 int
354 pcmk__fence_installed(pcmk__output_t *out, stonith_t *st, unsigned int timeout)
355 {
356 stonith_key_value_t *devices = NULL;
357 int rc = pcmk_rc_ok;
358
359 rc = st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices,
360 pcmk__timeout_ms2s(timeout));
361
362 if (rc < 0) {
363 return pcmk_legacy2rc(rc);
364 }
365
366 out->begin_list(out, "fence device", "fence devices",
367 "Installed fence devices");
368 for (stonith_key_value_t *iter = devices; iter != NULL; iter = iter->next) {
369 out->list_item(out, "device", "%s", iter->value);
370 }
371 out->end_list(out);
372
373 stonith_key_value_freeall(devices, 1, 1);
374 return pcmk_rc_ok;
375 }
376
377 int
378 pcmk_fence_installed(xmlNodePtr *xml, unsigned int timeout)
379 {
380 stonith_t *st = NULL;
381 pcmk__output_t *out = NULL;
382 int rc = pcmk_rc_ok;
383
384 rc = pcmk__setup_output_fencing(&out, &st, xml);
385 if (rc != pcmk_rc_ok) {
386 return rc;
387 }
388
389 rc = pcmk__fence_installed(out, st, timeout);
390 pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
391
392 st->cmds->disconnect(st);
393 stonith_api_delete(st);
394 return rc;
395 }
396
397 int
398 pcmk__fence_last(pcmk__output_t *out, const char *target, bool as_nodeid)
399 {
400 time_t when = 0;
401
402 if (target == NULL) {
403 return pcmk_rc_ok;
404 }
405
406 if (as_nodeid) {
407 when = stonith_api_time(atol(target), NULL, FALSE);
408 } else {
409 when = stonith_api_time(0, target, FALSE);
410 }
411
412 return out->message(out, "last-fenced", target, when);
413 }
414
415 int
416 pcmk_fence_last(xmlNodePtr *xml, const char *target, bool as_nodeid)
417 {
418 pcmk__output_t *out = NULL;
419 int rc = pcmk_rc_ok;
420
421 rc = pcmk__xml_output_new(&out, xml);
422 if (rc != pcmk_rc_ok) {
423 return rc;
424 }
425
426 stonith__register_messages(out);
427
428 rc = pcmk__fence_last(out, target, as_nodeid);
429 pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
430 return rc;
431 }
432
433 int
434 pcmk__fence_list_targets(pcmk__output_t *out, stonith_t *st,
435 const char *device_id, unsigned int timeout)
436 {
437 GList *targets = NULL;
438 char *lists = NULL;
439 int rc = pcmk_rc_ok;
440
441 rc = st->cmds->list(st, st_opts, device_id, &lists, pcmk__timeout_ms2s(timeout));
442 if (rc != pcmk_rc_ok) {
443 return pcmk_legacy2rc(rc);
444 }
445
446 targets = stonith__parse_targets(lists);
447
448 out->begin_list(out, "fence target", "fence targets", "Fence Targets");
449 while (targets != NULL) {
450 out->list_item(out, NULL, "%s", (const char *) targets->data);
451 targets = targets->next;
452 }
453 out->end_list(out);
454
455 free(lists);
456 return rc;
457 }
458
459 int
460 pcmk_fence_list_targets(xmlNodePtr *xml, const char *device_id, unsigned int timeout)
461 {
462 stonith_t *st = NULL;
463 pcmk__output_t *out = NULL;
464 int rc = pcmk_rc_ok;
465
466 rc = pcmk__setup_output_fencing(&out, &st, xml);
467 if (rc != pcmk_rc_ok) {
468 return rc;
469 }
470
471 rc = pcmk__fence_list_targets(out, st, device_id, timeout);
472 pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
473
474 st->cmds->disconnect(st);
475 stonith_api_delete(st);
476 return rc;
477 }
478
479 int
480 pcmk__fence_metadata(pcmk__output_t *out, stonith_t *st, const char *agent,
481 unsigned int timeout)
482 {
483 char *buffer = NULL;
484 int rc = st->cmds->metadata(st, st_opt_sync_call, agent, NULL, &buffer,
485 pcmk__timeout_ms2s(timeout));
486
487 if (rc != pcmk_rc_ok) {
488 return pcmk_legacy2rc(rc);
489 }
490
491 out->output_xml(out, PCMK_XE_METADATA, buffer);
492 free(buffer);
493 return rc;
494 }
495
496 int
497 pcmk_fence_metadata(xmlNodePtr *xml, const char *agent, unsigned int timeout)
498 {
499 stonith_t *st = NULL;
500 pcmk__output_t *out = NULL;
501 int rc = pcmk_rc_ok;
502
503 rc = pcmk__setup_output_fencing(&out, &st, xml);
504 if (rc != pcmk_rc_ok) {
505 return rc;
506 }
507
508 rc = pcmk__fence_metadata(out, st, agent, timeout);
509 pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
510
511 st->cmds->disconnect(st);
512 stonith_api_delete(st);
513 return rc;
514 }
515
516 int
517 pcmk__fence_registered(pcmk__output_t *out, stonith_t *st, const char *target,
518 unsigned int timeout)
519 {
520 stonith_key_value_t *devices = NULL;
521 int rc = pcmk_rc_ok;
522
523 rc = st->cmds->query(st, st_opts, target, &devices, pcmk__timeout_ms2s(timeout));
524
525 if (rc < 0) {
526 return pcmk_legacy2rc(rc);
527 }
528
529 out->begin_list(out, "fence device", "fence devices",
530 "Registered fence devices");
531 for (stonith_key_value_t *iter = devices; iter != NULL; iter = iter->next) {
532 out->list_item(out, "device", "%s", iter->value);
533 }
534 out->end_list(out);
535
536 stonith_key_value_freeall(devices, 1, 1);
537
538
539
540
541 return pcmk_rc_ok;
542 }
543
544 int
545 pcmk_fence_registered(xmlNodePtr *xml, const char *target, unsigned int timeout)
546 {
547 stonith_t *st = NULL;
548 pcmk__output_t *out = NULL;
549 int rc = pcmk_rc_ok;
550
551 rc = pcmk__setup_output_fencing(&out, &st, xml);
552 if (rc != pcmk_rc_ok) {
553 return rc;
554 }
555
556 rc = pcmk__fence_registered(out, st, target, timeout);
557 pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
558
559 st->cmds->disconnect(st);
560 stonith_api_delete(st);
561 return rc;
562 }
563
564 int
565 pcmk__fence_register_level(stonith_t *st, const char *target, int fence_level,
566 GList *devices)
567 {
568 return handle_level(st, target, fence_level, devices, true);
569 }
570
571 int
572 pcmk_fence_register_level(xmlNodePtr *xml, const char *target, int fence_level,
573 GList *devices)
574 {
575 stonith_t* st = NULL;
576 pcmk__output_t *out = NULL;
577 int rc = pcmk_rc_ok;
578
579 rc = pcmk__setup_output_fencing(&out, &st, xml);
580 if (rc != pcmk_rc_ok) {
581 return rc;
582 }
583
584 rc = pcmk__fence_register_level(st, target, fence_level, devices);
585 pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
586
587 st->cmds->disconnect(st);
588 stonith_api_delete(st);
589 return rc;
590 }
591
592 int
593 pcmk__fence_unregister_level(stonith_t *st, const char *target, int fence_level)
594 {
595 return handle_level(st, target, fence_level, NULL, false);
596 }
597
598 int
599 pcmk_fence_unregister_level(xmlNodePtr *xml, const char *target, int fence_level)
600 {
601 stonith_t* st = NULL;
602 pcmk__output_t *out = NULL;
603 int rc = pcmk_rc_ok;
604
605 rc = pcmk__setup_output_fencing(&out, &st, xml);
606 if (rc != pcmk_rc_ok) {
607 return rc;
608 }
609
610 rc = pcmk__fence_unregister_level(st, target, fence_level);
611 pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
612
613 st->cmds->disconnect(st);
614 stonith_api_delete(st);
615 return rc;
616 }
617
618 int
619 pcmk__fence_validate(pcmk__output_t *out, stonith_t *st, const char *agent,
620 const char *id, GHashTable *params, unsigned int timeout)
621 {
622 char *output = NULL;
623 char *error_output = NULL;
624 int rc;
625
626 rc = stonith__validate(st, st_opt_sync_call, id, NULL, agent, params,
627 pcmk__timeout_ms2s(timeout), &output, &error_output);
628 out->message(out, "validate", agent, id, output, error_output, rc);
629 return pcmk_legacy2rc(rc);
630 }
631
632 int
633 pcmk_fence_validate(xmlNodePtr *xml, const char *agent, const char *id,
634 GHashTable *params, unsigned int timeout)
635 {
636 stonith_t *st = NULL;
637 pcmk__output_t *out = NULL;
638 int rc = pcmk_rc_ok;
639
640 rc = pcmk__setup_output_fencing(&out, &st, xml);
641 if (rc != pcmk_rc_ok) {
642 return rc;
643 }
644
645 rc = pcmk__fence_validate(out, st, agent, id, params, timeout);
646 pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
647
648 st->cmds->disconnect(st);
649 stonith_api_delete(st);
650 return rc;
651 }
652
653 int
654 pcmk__get_fencing_history(stonith_t *st, stonith_history_t **stonith_history,
655 enum pcmk__fence_history fence_history)
656 {
657 int rc = pcmk_rc_ok;
658
659 if ((st == NULL) || (st->state == stonith_disconnected)) {
660 rc = ENOTCONN;
661 } else if (fence_history != pcmk__fence_history_none) {
662 rc = st->cmds->history(st, st_opt_sync_call, NULL, stonith_history,
663 120);
664
665 rc = pcmk_legacy2rc(rc);
666 if (rc != pcmk_rc_ok) {
667 return rc;
668 }
669
670 *stonith_history = stonith__sort_history(*stonith_history);
671 if (fence_history == pcmk__fence_history_reduced) {
672 *stonith_history = reduce_fence_history(*stonith_history);
673 }
674 }
675
676 return rc;
677 }