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