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