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