pacemaker 2.1.1-77db578727
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_fence.c
Go to the documentation of this file.
1/*
2 * Copyright 2009-2021 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 General Public License version 2
7 * or later (GPLv2+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11#include <crm/common/mainloop.h>
12#include <crm/common/results.h>
14#include <crm/stonith-ng.h>
16
17#include <glib.h>
18#include <libxml/tree.h>
19#include <pacemaker.h>
20#include <pcmki/pcmki_output.h>
21#include <pcmki/pcmki_fence.h>
22
23static const int st_opts = st_opt_sync_call | st_opt_allow_suicide;
24
25static GMainLoop *mainloop = NULL;
26
27static struct {
29 const char *target;
30 const char *action;
31 char *name;
32 unsigned int timeout;
33 unsigned int tolerance;
34 int delay;
35 int rc;
36} async_fence_data;
37
38static int
39handle_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 // Not really possible, but makes static analysis happy
49 return EINVAL;
50 }
51
52 /* Determine if targeting by attribute, node name pattern or node name */
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 /* Register or unregister level as appropriate */
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
76static void
77notify_callback(stonith_t * st, stonith_event_t * e)
78{
79 if (e->result != pcmk_ok) {
80 return;
81 }
82
83 if (pcmk__str_eq(async_fence_data.target, e->target, pcmk__str_casei) &&
84 pcmk__str_eq(async_fence_data.action, e->action, pcmk__str_casei)) {
85
86 async_fence_data.rc = e->result;
87 g_main_loop_quit(mainloop);
88 }
89}
90
91static void
92fence_callback(stonith_t * stonith, stonith_callback_data_t * data)
93{
94 async_fence_data.rc = data->rc;
95
96 g_main_loop_quit(mainloop);
97}
98
99static gboolean
100async_fence_helper(gpointer user_data)
101{
102 stonith_t *st = async_fence_data.st;
103 int call_id = 0;
104 int rc = stonith_api_connect_retry(st, async_fence_data.name, 10);
105
106 if (rc != pcmk_ok) {
107 fprintf(stderr, "Could not connect to fencer: %s\n", pcmk_strerror(rc));
108 g_main_loop_quit(mainloop);
109 return TRUE;
110 }
111
113
114 call_id = st->cmds->fence_with_delay(st,
116 async_fence_data.target,
117 async_fence_data.action,
118 async_fence_data.timeout/1000,
119 async_fence_data.tolerance/1000,
120 async_fence_data.delay);
121
122 if (call_id < 0) {
123 g_main_loop_quit(mainloop);
124 return TRUE;
125 }
126
128 call_id,
129 async_fence_data.timeout/1000,
130 st_opt_timeout_updates, NULL, "callback", fence_callback);
131
132 return TRUE;
133}
134
135int
136pcmk__fence_action(stonith_t *st, const char *target, const char *action,
137 const char *name, unsigned int timeout, unsigned int tolerance,
138 int delay)
139{
140 crm_trigger_t *trig;
141
142 async_fence_data.st = st;
143 async_fence_data.name = strdup(name);
144 async_fence_data.target = target;
145 async_fence_data.action = action;
146 async_fence_data.timeout = timeout;
147 async_fence_data.tolerance = tolerance;
148 async_fence_data.delay = delay;
149 async_fence_data.rc = pcmk_err_generic;
150
151 trig = mainloop_add_trigger(G_PRIORITY_HIGH, async_fence_helper, NULL);
153
154 mainloop = g_main_loop_new(NULL, FALSE);
155 g_main_loop_run(mainloop);
156
157 free(async_fence_data.name);
158
159 return pcmk_legacy2rc(async_fence_data.rc);
160}
161
162#ifdef BUILD_PUBLIC_LIBPACEMAKER
163int
164pcmk_fence_action(stonith_t *st, const char *target, const char *action,
165 const char *name, unsigned int timeout, unsigned int tolerance,
166 int delay)
167{
169}
170#endif
171
172int
174 unsigned int timeout, int verbose, bool broadcast,
175 bool cleanup) {
176 stonith_history_t *history = NULL, *hp, *latest = NULL;
177 int rc = pcmk_rc_ok;
178 int opts = 0;
179
180 if (cleanup) {
181 out->info(out, "cleaning up fencing-history%s%s",
182 target ? " for node " : "", target ? target : "");
183 }
184 if (broadcast) {
185 out->info(out, "gather fencing-history from all nodes");
186 }
187
188 stonith__set_call_options(opts, target, st_opts);
189 if (cleanup) {
191 }
192 if (broadcast) {
194 }
195 rc = st->cmds->history(st, opts,
196 pcmk__str_eq(target, "*", pcmk__str_none)? NULL : target,
197 &history, timeout/1000);
198
199 if (cleanup) {
200 // Cleanup doesn't return a history list
201 stonith_history_free(history);
202 return pcmk_legacy2rc(rc);
203 }
204
205 out->begin_list(out, "event", "events", "Fencing history");
206
207 history = stonith__sort_history(history);
208 for (hp = history; hp; hp = hp->next) {
209 if (hp->state == st_done) {
210 latest = hp;
211 }
212
213 if (out->is_quiet(out) || !verbose) {
214 continue;
215 }
216
217 out->message(out, "stonith-event", hp, 1, stonith__later_succeeded(hp, history));
218 out->increment_list(out);
219 }
220
221 if (latest) {
222 if (out->is_quiet(out)) {
223 pcmk__formatted_printf(out, "%lld\n", (long long) latest->completed);
224 } else if (!verbose) { // already printed if verbose
225 out->message(out, "stonith-event", latest, 0, FALSE);
226 out->increment_list(out);
227 }
228 }
229
230 out->end_list(out);
231
232 stonith_history_free(history);
233 return pcmk_legacy2rc(rc);
234}
235
236#ifdef BUILD_PUBLIC_LIBPACEMAKER
237int
238pcmk_fence_history(xmlNodePtr *xml, stonith_t *st, char *target, unsigned int timeout,
239 bool quiet, int verbose, bool broadcast, bool cleanup) {
240 pcmk__output_t *out = NULL;
241 int rc = pcmk_rc_ok;
242
243 rc = pcmk__out_prologue(&out, xml);
244 if (rc != pcmk_rc_ok) {
245 return rc;
246 }
247
249
250 out->quiet = quiet;
251
252 rc = pcmk__fence_history(out, st, target, timeout, verbose, broadcast, cleanup);
253 pcmk__out_epilogue(out, xml, rc);
254 return rc;
255}
256#endif
257
258int
260 stonith_key_value_t *devices = NULL;
261 int rc = pcmk_rc_ok;
262
263 rc = st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, timeout/1000);
264 /* list_agents returns a negative error code or a positive number of agents. */
265 if (rc < 0) {
266 return pcmk_legacy2rc(rc);
267 }
268
269 out->begin_list(out, "fence device", "fence devices", "Installed fence devices");
270 for (stonith_key_value_t *dIter = devices; dIter; dIter = dIter->next) {
271 out->list_item(out, "device", "%s", dIter->value);
272 }
273 out->end_list(out);
274
275 stonith_key_value_freeall(devices, 1, 1);
276 return pcmk_rc_ok;
277}
278
279#ifdef BUILD_PUBLIC_LIBPACEMAKER
280int
281pcmk_fence_installed(xmlNodePtr *xml, stonith_t *st, unsigned int timeout) {
282 pcmk__output_t *out = NULL;
283 int rc = pcmk_rc_ok;
284
285 rc = pcmk__out_prologue(&out, xml);
286 if (rc != pcmk_rc_ok) {
287 return rc;
288 }
289
291
293 pcmk__out_epilogue(out, xml, rc);
294 return rc;
295}
296#endif
297
298int
299pcmk__fence_last(pcmk__output_t *out, const char *target, bool as_nodeid) {
300 time_t when = 0;
301
302 if (target == NULL) {
303 return pcmk_rc_ok;
304 }
305
306 if (as_nodeid) {
307 when = stonith_api_time(atol(target), NULL, FALSE);
308 } else {
309 when = stonith_api_time(0, target, FALSE);
310 }
311
312 return out->message(out, "last-fenced", target, when);
313}
314
315#ifdef BUILD_PUBLIC_LIBPACEMAKER
316int
317pcmk_fence_last(xmlNodePtr *xml, const char *target, bool as_nodeid) {
318 pcmk__output_t *out = NULL;
319 int rc = pcmk_rc_ok;
320
321 rc = pcmk__out_prologue(&out, xml);
322 if (rc != pcmk_rc_ok) {
323 return rc;
324 }
325
327
328 rc = pcmk__fence_last(out, target, as_nodeid);
329 pcmk__out_epilogue(out, xml, rc);
330 return rc;
331}
332#endif
333
334int
336 const char *device_id, unsigned int timeout) {
337 GList *targets = NULL;
338 char *lists = NULL;
339 int rc = pcmk_rc_ok;
340
341 rc = st->cmds->list(st, st_opts, device_id, &lists, timeout/1000);
342 if (rc != pcmk_rc_ok) {
343 return pcmk_legacy2rc(rc);
344 }
345
346 targets = stonith__parse_targets(lists);
347
348 out->begin_list(out, "fence target", "fence targets", "Fence Targets");
349 while (targets != NULL) {
350 out->list_item(out, NULL, "%s", (const char *) targets->data);
351 targets = targets->next;
352 }
353 out->end_list(out);
354
355 free(lists);
356 return rc;
357}
358
359#ifdef BUILD_PUBLIC_LIBPACEMAKER
360int
361pcmk_fence_list_targets(xmlNodePtr *xml, stonith_t *st, const char *device_id,
362 unsigned int timeout) {
363 pcmk__output_t *out = NULL;
364 int rc = pcmk_rc_ok;
365
366 rc = pcmk__out_prologue(&out, xml);
367 if (rc != pcmk_rc_ok) {
368 return rc;
369 }
370
372
373 rc = pcmk__fence_list_targets(out, st, device_id, timeout);
374 pcmk__out_epilogue(out, xml, rc);
375 return rc;
376}
377#endif
378
379int
381 unsigned int timeout) {
382 char *buffer = NULL;
383 int rc = st->cmds->metadata(st, st_opt_sync_call, agent, NULL, &buffer,
384 timeout/1000);
385
386 if (rc != pcmk_rc_ok) {
387 return pcmk_legacy2rc(rc);
388 }
389
390 out->output_xml(out, "metadata", buffer);
391 free(buffer);
392 return rc;
393}
394
395#ifdef BUILD_PUBLIC_LIBPACEMAKER
396int
397pcmk_fence_metadata(xmlNodePtr *xml, stonith_t *st, char *agent,
398 unsigned int timeout) {
399 pcmk__output_t *out = NULL;
400 int rc = pcmk_rc_ok;
401
402 rc = pcmk__out_prologue(&out, xml);
403 if (rc != pcmk_rc_ok) {
404 return rc;
405 }
406
408
409 rc = pcmk__fence_metadata(out, st, agent, timeout);
410 pcmk__out_epilogue(out, xml, rc);
411 return rc;
412}
413#endif
414
415int
417 unsigned int timeout) {
418 stonith_key_value_t *devices = NULL;
419 int rc = pcmk_rc_ok;
420
421 rc = st->cmds->query(st, st_opts, target, &devices, timeout/1000);
422 /* query returns a negative error code or a positive number of results. */
423 if (rc < 0) {
424 return pcmk_legacy2rc(rc);
425 }
426
427 out->begin_list(out, "fence device", "fence devices", "Registered fence devices");
428 for (stonith_key_value_t *dIter = devices; dIter; dIter = dIter->next) {
429 out->list_item(out, "device", "%s", dIter->value);
430 }
431 out->end_list(out);
432
433 stonith_key_value_freeall(devices, 1, 1);
434
435 /* Return pcmk_rc_ok here, not the number of results. Callers probably
436 * don't care.
437 */
438 return pcmk_rc_ok;
439}
440
441#ifdef BUILD_PUBLIC_LIBPACEMAKER
442int
443pcmk_fence_registered(xmlNodePtr *xml, stonith_t *st, char *target,
444 unsigned int timeout) {
445 pcmk__output_t *out = NULL;
446 int rc = pcmk_rc_ok;
447
448 rc = pcmk__out_prologue(&out, xml);
449 if (rc != pcmk_rc_ok) {
450 return rc;
451 }
452
454
456 pcmk__out_epilogue(out, xml, rc);
457 return rc;
458}
459#endif
460
461int
463 stonith_key_value_t *devices) {
464 return handle_level(st, target, fence_level, devices, true);
465}
466
467#ifdef BUILD_PUBLIC_LIBPACEMAKER
468int
469pcmk_fence_register_level(stonith_t *st, char *target, int fence_level,
470 stonith_key_value_t *devices) {
471 return pcmk__fence_register_level(st, target, fence_level, devices);
472}
473#endif
474
475int
477 return handle_level(st, target, fence_level, NULL, false);
478}
479
480#ifdef BUILD_PUBLIC_LIBPACEMAKER
481int
482pcmk_fence_unregister_level(stonith_t *st, char *target, int fence_level) {
483 return pcmk__fence_unregister_level(st, target, fence_level);
484}
485#endif
486
487int
489 const char *id, stonith_key_value_t *params,
490 unsigned int timeout) {
491 char *output = NULL;
492 char *error_output = NULL;
493 int rc;
494
495 rc = st->cmds->validate(st, st_opt_sync_call, id, NULL, agent, params,
496 timeout/1000, &output, &error_output);
497 out->message(out, "validate", agent, id, output, error_output, rc);
498 return pcmk_legacy2rc(rc);
499}
500
501#ifdef BUILD_PUBLIC_LIBPACEMAKER
502int
503pcmk_fence_validate(xmlNodePtr *xml, stonith_t *st, const char *agent,
504 const char *id, stonith_key_value_t *params,
505 unsigned int timeout) {
506 pcmk__output_t *out = NULL;
507 int rc = pcmk_rc_ok;
508
509 rc = pcmk__out_prologue(&out, xml);
510 if (rc != pcmk_rc_ok) {
511 return rc;
512 }
513
515
516 rc = pcmk__fence_validate(out, st, agent, id, params, timeout);
517 pcmk__out_epilogue(out, xml, rc);
518 return rc;
519}
520#endif
521
524{
525 stonith_history_t *new, *hp, *np;
526
527 if (!history) {
528 return history;
529 }
530
531 new = history;
532 hp = new->next;
533 new->next = NULL;
534
535 while (hp) {
536 stonith_history_t *hp_next = hp->next;
537
538 hp->next = NULL;
539
540 for (np = new; ; np = np->next) {
541 if ((hp->state == st_done) || (hp->state == st_failed)) {
542 /* action not in progress */
543 if (pcmk__str_eq(hp->target, np->target, pcmk__str_casei) &&
544 pcmk__str_eq(hp->action, np->action, pcmk__str_casei) &&
545 (hp->state == np->state) &&
546 ((hp->state == st_done) ||
547 pcmk__str_eq(hp->delegate, np->delegate, pcmk__str_casei))) {
548 /* purge older hp */
550 break;
551 }
552 }
553
554 if (!np->next) {
555 np->next = hp;
556 break;
557 }
558 }
559 hp = hp_next;
560 }
561
562 return new;
563}
char data[0]
Definition cpg.c:10
GList * stonith__parse_targets(const char *hosts)
Definition st_client.c:2489
gboolean stonith__later_succeeded(stonith_history_t *event, stonith_history_t *top_history)
Definition st_client.c:2529
stonith_history_t * stonith__sort_history(stonith_history_t *history)
Definition st_client.c:2560
#define stonith__set_call_options(st_call_opts, call_for, flags_to_set)
Definition internal.h:35
void stonith__register_messages(pcmk__output_t *out)
Definition st_output.c:468
Wrappers for and extensions to glib mainloop.
void mainloop_set_trigger(crm_trigger_t *source)
Definition mainloop.c:198
crm_trigger_t * mainloop_add_trigger(int priority, int(*dispatch)(gpointer user_data), gpointer userdata)
Create a trigger to be used as a mainloop source.
Definition mainloop.c:186
struct trigger_s crm_trigger_t
Definition mainloop.h:31
Formatted output for pacemaker tools.
void void void pcmk__formatted_printf(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
High Level API.
int pcmk__fence_validate(pcmk__output_t *out, stonith_t *st, const char *agent, const char *id, stonith_key_value_t *params, unsigned int timeout)
Validate a STONITH device configuration.
Definition pcmk_fence.c:488
int pcmk__fence_register_level(stonith_t *st, char *target, int fence_level, stonith_key_value_t *devices)
Register a fencing level for a specific node, node regex, or attribute.
Definition pcmk_fence.c:462
int pcmk__fence_action(stonith_t *st, const char *target, const char *action, const char *name, unsigned int timeout, unsigned int tolerance, int delay)
Perform a STONITH action.
Definition pcmk_fence.c:136
unsigned int timeout
Definition pcmk_fence.c:32
char * name
Definition pcmk_fence.c:31
int delay
Definition pcmk_fence.c:34
unsigned int tolerance
Definition pcmk_fence.c:33
int pcmk__fence_list_targets(pcmk__output_t *out, stonith_t *st, const char *device_id, unsigned int timeout)
List nodes that can be fenced.
Definition pcmk_fence.c:335
int pcmk__fence_installed(pcmk__output_t *out, stonith_t *st, unsigned int timeout)
List all installed STONITH agents.
Definition pcmk_fence.c:259
stonith_t * st
Definition pcmk_fence.c:28
stonith_history_t * pcmk__reduce_fence_history(stonith_history_t *history)
Reduce the STONITH history.
Definition pcmk_fence.c:523
int pcmk__fence_registered(pcmk__output_t *out, stonith_t *st, char *target, unsigned int timeout)
List registered fence devices.
Definition pcmk_fence.c:416
const char * action
Definition pcmk_fence.c:30
int pcmk__fence_unregister_level(stonith_t *st, char *target, int fence_level)
Unregister a fencing level for a specific node, node regex, or attribute.
Definition pcmk_fence.c:476
int pcmk__fence_history(pcmk__output_t *out, stonith_t *st, char *target, unsigned int timeout, int verbose, bool broadcast, bool cleanup)
List the fencing operations that have occurred for a specific node.
Definition pcmk_fence.c:173
int rc
Definition pcmk_fence.c:35
int pcmk__fence_last(pcmk__output_t *out, const char *target, bool as_nodeid)
When was a device last fenced?
Definition pcmk_fence.c:299
int pcmk__fence_metadata(pcmk__output_t *out, stonith_t *st, char *agent, unsigned int timeout)
Get metadata for a resource.
Definition pcmk_fence.c:380
const char * target
Definition pcmk_fence.c:29
int pcmk__out_prologue(pcmk__output_t **out, xmlNodePtr *xml)
void pcmk__out_epilogue(pcmk__output_t *out, xmlNodePtr *xml, int retval)
Function and executable result codes.
const char * pcmk_strerror(int rc)
Definition results.c:58
#define pcmk_err_generic
Definition results.h:70
@ pcmk_rc_ok
Definition results.h:142
#define pcmk_ok
Definition results.h:67
int pcmk_legacy2rc(int legacy_rc)
Definition results.c:450
Fencing aka. STONITH.
time_t stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
Definition st_client.c:2286
#define T_STONITH_NOTIFY_FENCE
Definition stonith-ng.h:36
void stonith_history_free(stonith_history_t *history)
Definition st_client.c:1158
@ st_opt_cleanup
Definition stonith-ng.h:65
@ st_opt_timeout_updates
Definition stonith-ng.h:61
@ st_opt_broadcast
Definition stonith-ng.h:67
@ st_opt_allow_suicide
Definition stonith-ng.h:50
@ st_opt_sync_call
Definition stonith-ng.h:58
int stonith_api_connect_retry(stonith_t *st, const char *name, int max_attempts)
Make a blocking connection attempt to the fencer.
Definition st_client.c:2175
void stonith_key_value_freeall(stonith_key_value_t *kvp, int keys, int values)
Definition st_client.c:2223
@ st_failed
Definition stonith-ng.h:77
@ st_done
Definition stonith-ng.h:75
@ pcmk__str_none
@ pcmk__str_casei
This structure contains everything that makes up a single output formatter.
void(*) void(*) void(* increment_list)(pcmk__output_t *out)
void(* end_list)(pcmk__output_t *out)
int(* message)(pcmk__output_t *out, const char *message_id,...)
bool(* is_quiet)(pcmk__output_t *out)
int(*) void(*) void(* output_xml)(pcmk__output_t *out, const char *name, const char *buf)
void(*) void(* list_item)(pcmk__output_t *out, const char *name, const char *format,...) G_GNUC_PRINTF(3
void(* begin_list)(pcmk__output_t *out, const char *singular_noun, const char *plural_noun, const char *format,...) G_GNUC_PRINTF(4
bool quiet
Should this formatter supress most output?
int(* info)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
int(* fence_with_delay)(stonith_t *st, int options, const char *node, const char *action, int timeout, int tolerance, int delay)
Issue a fencing action against a node with requested fencing delay.
Definition stonith-ng.h:418
int(* register_level_full)(stonith_t *st, int options, const char *node, const char *pattern, const char *attr, const char *value, int level, stonith_key_value_t *device_list)
Register fencing level for specific node, node regex or attribute.
Definition stonith-ng.h:373
int(* metadata)(stonith_t *st, int options, const char *device, const char *provider, char **output, int timeout)
Get the metadata documentation for a resource.
Definition stonith-ng.h:217
int(* register_notification)(stonith_t *st, const char *event, void(*notify)(stonith_t *st, stonith_event_t *e))
Definition stonith-ng.h:303
int(* register_callback)(stonith_t *st, int call_id, int timeout, int options, void *userdata, const char *callback_name, void(*callback)(stonith_t *st, stonith_callback_data_t *data))
Register a callback to receive the result of an asynchronous call.
Definition stonith-ng.h:325
int(* list_agents)(stonith_t *stonith, int call_options, const char *provider, stonith_key_value_t **devices, int timeout)
Retrieve a list of installed stonith agents.
Definition stonith-ng.h:230
int(* list)(stonith_t *st, int options, const char *id, char **list_output, int timeout)
Retrieve string listing hosts and port assignments from a local stonith device.
Definition stonith-ng.h:239
int(* query)(stonith_t *st, int options, const char *node, stonith_key_value_t **devices, int timeout)
Retrieve a list of registered stonith devices.
Definition stonith-ng.h:266
int(* validate)(stonith_t *st, int call_options, const char *rsc_id, const char *namespace_s, const char *agent, stonith_key_value_t *params, int timeout, char **output, char **error_output)
Validate an arbitrary stonith device configuration.
Definition stonith-ng.h:396
int(* remove_level_full)(stonith_t *st, int options, const char *node, const char *pattern, const char *attr, const char *value, int level)
Remove fencing level for specific node, node regex or attribute.
Definition stonith-ng.h:353
int(* history)(stonith_t *st, int options, const char *node, stonith_history_t **output, int timeout)
Retrieve a list of fencing operations that have occurred for a specific node.
Definition stonith-ng.h:301
struct stonith_history_s * next
Definition stonith-ng.h:112
struct stonith_key_value_s * next
Definition stonith-ng.h:101
stonith_api_operations_t * cmds
Definition stonith-ng.h:431