This source file includes following definitions.
- is_action_required
- get_action_delay_max
- get_action_delay_base
- get_action_timeout
- free_async_command
- create_async_command
- get_action_limit
- get_active_cmds
- stonith_device_execute
- stonith_device_dispatch
- start_delay_helper
- schedule_stonith_command
- free_device
- build_port_aliases
- parse_host_line
- parse_host_list
- get_agent_metadata
- is_nodeid_required
- add_action
- read_action_metadata
- map_action
- xml2device_params
- build_device_from_xml
- target_list_type
- schedule_internal_command
- string_in_list
- status_search_cb
- dynamic_list_search_cb
- device_params_diff
- device_has_duplicate
- stonith_device_register
- stonith_device_remove
- count_active_levels
- free_topology_entry
- stonith_level_key
- stonith_level_kind
- parse_device_list
- stonith_level_register
- stonith_level_remove
- stonith_device_action
- search_devices_record_result
- localhost_is_eligible
- can_fence_host_with_device
- search_devices
- get_capable_devices
- add_action_specific_attributes
- add_disallowed
- add_action_reply
- stonith_query_capable_device_cb
- stonith_query
- log_operation
- stonith_send_async_reply
- unfence_cb
- cancel_stonith_command
- st_child_done
- sort_device_priority
- stonith_fence_get_devices_cb
- stonith_fence
- stonith_construct_reply
- stonith_construct_async_reply
- fencing_peer_active
- check_alternate_host
- stonith_send_reply
- handle_request
- handle_reply
- stonith_command
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <crm_internal.h>
20
21 #include <sys/param.h>
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <sys/utsname.h>
28
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <ctype.h>
33
34 #include <crm/crm.h>
35 #include <crm/msg_xml.h>
36 #include <crm/common/ipc.h>
37 #include <crm/common/ipcs.h>
38 #include <crm/cluster/internal.h>
39 #include <crm/common/mainloop.h>
40
41 #include <crm/stonith-ng.h>
42 #include <crm/fencing/internal.h>
43 #include <crm/common/xml.h>
44
45 #if SUPPORT_CIBSECRETS
46 # include <crm/common/cib_secrets.h>
47 #endif
48
49 #include <internal.h>
50
51 GHashTable *device_list = NULL;
52 GHashTable *topology = NULL;
53 GList *cmd_list = NULL;
54
55 struct device_search_s {
56
57 char *host;
58
59 char *action;
60
61 int per_device_timeout;
62
63 int replies_needed;
64
65 int replies_received;
66
67 bool allow_suicide;
68
69
70 void *user_data;
71
72 void (*callback) (GList * devices, void *user_data);
73
74 GListPtr capable;
75 };
76
77 static gboolean stonith_device_dispatch(gpointer user_data);
78 static void st_child_done(GPid pid, int rc, const char *output, gpointer user_data);
79 static void stonith_send_reply(xmlNode * reply, int call_options, const char *remote_peer,
80 const char *client_id);
81
82 static void search_devices_record_result(struct device_search_s *search, const char *device,
83 gboolean can_fence);
84
85 typedef struct async_command_s {
86
87 int id;
88 int pid;
89 int fd_stdout;
90 int options;
91 int default_timeout;
92 int timeout;
93
94 int start_delay;
95 int delay_id;
96
97 char *op;
98 char *origin;
99 char *client;
100 char *client_name;
101 char *remote_op_id;
102
103 char *victim;
104 uint32_t victim_nodeid;
105 char *action;
106 char *device;
107 char *mode;
108
109 GListPtr device_list;
110 GListPtr device_next;
111
112 void *internal_user_data;
113 void (*done_cb) (GPid pid, int rc, const char *output, gpointer user_data);
114 guint timer_sigterm;
115 guint timer_sigkill;
116
117
118 int last_timeout_signo;
119
120 stonith_device_t *active_on;
121 } async_command_t;
122
123 static xmlNode *stonith_construct_async_reply(async_command_t * cmd, const char *output,
124 xmlNode * data, int rc);
125
126 static gboolean
127 is_action_required(const char *action, stonith_device_t *device)
128 {
129 return device && device->automatic_unfencing && safe_str_eq(action, "on");
130 }
131
132 static int
133 get_action_delay_max(stonith_device_t * device, const char * action)
134 {
135 const char *value = NULL;
136 int delay_max_ms = 0;
137
138 if (safe_str_neq(action, "off") && safe_str_neq(action, "reboot")) {
139 return 0;
140 }
141
142 value = g_hash_table_lookup(device->params, STONITH_ATTR_DELAY_MAX);
143 if (value) {
144 delay_max_ms = crm_get_msec(value);
145 }
146
147 return delay_max_ms;
148 }
149
150 static int
151 get_action_delay_base(stonith_device_t * device, const char * action)
152 {
153 const char *value = NULL;
154 int delay_base_ms = 0;
155
156 if (safe_str_neq(action, "off") && safe_str_neq(action, "reboot")) {
157 return 0;
158 }
159
160 value = g_hash_table_lookup(device->params, STONITH_ATTR_DELAY_BASE);
161 if (value) {
162 delay_base_ms = crm_get_msec(value);
163 }
164
165 return delay_base_ms;
166 }
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188 static int
189 get_action_timeout(stonith_device_t * device, const char *action, int default_timeout)
190 {
191 if (action && device && device->params) {
192 char buffer[64] = { 0, };
193 const char *value = NULL;
194
195
196
197
198 if (safe_str_eq(action, "reboot")
199 && is_not_set(device->flags, st_device_supports_reboot)) {
200 crm_trace("%s doesn't support reboot, using timeout for off instead",
201 device->id);
202 action = "off";
203 }
204
205
206 snprintf(buffer, sizeof(buffer), "pcmk_%s_timeout", action);
207 value = g_hash_table_lookup(device->params, buffer);
208 if (value) {
209 return atoi(value);
210 }
211 }
212 return default_timeout;
213 }
214
215 static void
216 free_async_command(async_command_t * cmd)
217 {
218 if (!cmd) {
219 return;
220 }
221
222 if (cmd->delay_id) {
223 g_source_remove(cmd->delay_id);
224 }
225
226 cmd_list = g_list_remove(cmd_list, cmd);
227
228 g_list_free_full(cmd->device_list, free);
229 free(cmd->device);
230 free(cmd->action);
231 free(cmd->victim);
232 free(cmd->remote_op_id);
233 free(cmd->client);
234 free(cmd->client_name);
235 free(cmd->origin);
236 free(cmd->mode);
237 free(cmd->op);
238 free(cmd);
239 }
240
241 static async_command_t *
242 create_async_command(xmlNode * msg)
243 {
244 async_command_t *cmd = NULL;
245 xmlNode *op = get_xpath_object("//@" F_STONITH_ACTION, msg, LOG_ERR);
246 const char *action = crm_element_value(op, F_STONITH_ACTION);
247
248 CRM_CHECK(action != NULL, crm_log_xml_warn(msg, "NoAction"); return NULL);
249
250 crm_log_xml_trace(msg, "Command");
251 cmd = calloc(1, sizeof(async_command_t));
252 crm_element_value_int(msg, F_STONITH_CALLID, &(cmd->id));
253 crm_element_value_int(msg, F_STONITH_CALLOPTS, &(cmd->options));
254 crm_element_value_int(msg, F_STONITH_TIMEOUT, &(cmd->default_timeout));
255 cmd->timeout = cmd->default_timeout;
256
257 cmd->origin = crm_element_value_copy(msg, F_ORIG);
258 cmd->remote_op_id = crm_element_value_copy(msg, F_STONITH_REMOTE_OP_ID);
259 cmd->client = crm_element_value_copy(msg, F_STONITH_CLIENTID);
260 cmd->client_name = crm_element_value_copy(msg, F_STONITH_CLIENTNAME);
261 cmd->op = crm_element_value_copy(msg, F_STONITH_OPERATION);
262 cmd->action = strdup(action);
263 cmd->victim = crm_element_value_copy(op, F_STONITH_TARGET);
264 cmd->mode = crm_element_value_copy(op, F_STONITH_MODE);
265 cmd->device = crm_element_value_copy(op, F_STONITH_DEVICE);
266
267 CRM_CHECK(cmd->op != NULL, crm_log_xml_warn(msg, "NoOp"); free_async_command(cmd); return NULL);
268 CRM_CHECK(cmd->client != NULL, crm_log_xml_warn(msg, "NoClient"));
269
270 cmd->done_cb = st_child_done;
271 cmd_list = g_list_append(cmd_list, cmd);
272 return cmd;
273 }
274
275 static int
276 get_action_limit(stonith_device_t * device)
277 {
278 const char *value = NULL;
279 int action_limit = 1;
280
281 value = g_hash_table_lookup(device->params, STONITH_ATTR_ACTION_LIMIT);
282 if (value) {
283 action_limit = crm_parse_int(value, "1");
284 if (action_limit == 0) {
285
286 action_limit = 1;
287 }
288 }
289
290 return action_limit;
291 }
292
293 static int
294 get_active_cmds(stonith_device_t * device)
295 {
296 int counter = 0;
297 GListPtr gIter = NULL;
298 GListPtr gIterNext = NULL;
299
300 CRM_CHECK(device != NULL, return 0);
301
302 for (gIter = cmd_list; gIter != NULL; gIter = gIterNext) {
303 async_command_t *cmd = gIter->data;
304
305 gIterNext = gIter->next;
306
307 if (cmd->active_on == device) {
308 counter++;
309 }
310 }
311
312 return counter;
313 }
314
315 static gboolean
316 stonith_device_execute(stonith_device_t * device)
317 {
318 int exec_rc = 0;
319 const char *action_str = NULL;
320 async_command_t *cmd = NULL;
321 stonith_action_t *action = NULL;
322 int active_cmds = 0;
323 int action_limit = 0;
324
325 CRM_CHECK(device != NULL, return FALSE);
326
327 active_cmds = get_active_cmds(device);
328 action_limit = get_action_limit(device);
329 if (action_limit > -1 && active_cmds >= action_limit) {
330 crm_trace("%s is over its action limit of %d (%u active action%s)",
331 device->id, action_limit, active_cmds, active_cmds > 1 ? "s" : "");
332 return TRUE;
333 }
334
335 if (device->pending_ops) {
336 GList *first = device->pending_ops;
337
338 cmd = first->data;
339 if (cmd && cmd->delay_id) {
340 crm_trace
341 ("Operation %s%s%s on %s was asked to run too early, waiting for start_delay timeout of %dms",
342 cmd->action, cmd->victim ? " for node " : "", cmd->victim ? cmd->victim : "",
343 device->id, cmd->start_delay);
344 return TRUE;
345 }
346
347 device->pending_ops = g_list_remove_link(device->pending_ops, first);
348 g_list_free_1(first);
349 }
350
351 if (cmd == NULL) {
352 crm_trace("Nothing further to do for %s", device->id);
353 return TRUE;
354 }
355
356 if(safe_str_eq(device->agent, STONITH_WATCHDOG_AGENT)) {
357 if(safe_str_eq(cmd->action, "reboot")) {
358 pcmk_panic(__FUNCTION__);
359 return TRUE;
360
361 } else if(safe_str_eq(cmd->action, "off")) {
362 pcmk_panic(__FUNCTION__);
363 return TRUE;
364
365 } else {
366 crm_info("Faking success for %s watchdog operation", cmd->action);
367 cmd->done_cb(0, 0, NULL, cmd);
368 return TRUE;
369 }
370 }
371
372 #if SUPPORT_CIBSECRETS
373 if (replace_secret_params(device->id, device->params) < 0) {
374
375 if (safe_str_eq(cmd->action,"stop")) {
376
377 crm_info("proceeding with the stop operation for %s", device->id);
378
379 } else {
380 crm_err("failed to get secrets for %s, "
381 "considering resource not configured", device->id);
382 exec_rc = PCMK_OCF_NOT_CONFIGURED;
383 cmd->done_cb(0, exec_rc, NULL, cmd);
384 return TRUE;
385 }
386 }
387 #endif
388
389 action_str = cmd->action;
390 if (safe_str_eq(cmd->action, "reboot") && is_not_set(device->flags, st_device_supports_reboot)) {
391 crm_warn("Agent '%s' does not advertise support for 'reboot', performing 'off' action instead", device->agent);
392 action_str = "off";
393 }
394
395 action = stonith_action_create(device->agent,
396 action_str,
397 cmd->victim,
398 cmd->victim_nodeid,
399 cmd->timeout, device->params, device->aliases);
400
401
402 exec_rc = stonith_action_execute_async(action, (void *)cmd, cmd->done_cb);
403
404 if (exec_rc > 0) {
405 crm_debug("Operation %s%s%s on %s now running with pid=%d, timeout=%ds",
406 cmd->action, cmd->victim ? " for node " : "", cmd->victim ? cmd->victim : "",
407 device->id, exec_rc, cmd->timeout);
408 cmd->active_on = device;
409
410 } else {
411 crm_warn("Operation %s%s%s on %s failed: %s (%d)",
412 cmd->action, cmd->victim ? " for node " : "", cmd->victim ? cmd->victim : "",
413 device->id, pcmk_strerror(exec_rc), exec_rc);
414 cmd->done_cb(0, exec_rc, NULL, cmd);
415 }
416 return TRUE;
417 }
418
419 static gboolean
420 stonith_device_dispatch(gpointer user_data)
421 {
422 return stonith_device_execute(user_data);
423 }
424
425 static gboolean
426 start_delay_helper(gpointer data)
427 {
428 async_command_t *cmd = data;
429 stonith_device_t *device = NULL;
430
431 cmd->delay_id = 0;
432 device = cmd->device ? g_hash_table_lookup(device_list, cmd->device) : NULL;
433
434 if (device) {
435 mainloop_set_trigger(device->work);
436 }
437
438 return FALSE;
439 }
440
441 static void
442 schedule_stonith_command(async_command_t * cmd, stonith_device_t * device)
443 {
444 int delay_max = 0;
445 int delay_base = 0;
446
447 CRM_CHECK(cmd != NULL, return);
448 CRM_CHECK(device != NULL, return);
449
450 if (cmd->device) {
451 free(cmd->device);
452 }
453
454 if (device->include_nodeid && cmd->victim) {
455 crm_node_t *node = crm_get_peer(0, cmd->victim);
456
457 cmd->victim_nodeid = node->id;
458 }
459
460 cmd->device = strdup(device->id);
461 cmd->timeout = get_action_timeout(device, cmd->action, cmd->default_timeout);
462
463 if (cmd->remote_op_id) {
464 crm_debug("Scheduling %s on %s for remote peer %s with op id (%s) (timeout=%ds)",
465 cmd->action, device->id, cmd->origin, cmd->remote_op_id, cmd->timeout);
466 } else {
467 crm_debug("Scheduling %s on %s for %s (timeout=%ds)",
468 cmd->action, device->id, cmd->client, cmd->timeout);
469 }
470
471 device->pending_ops = g_list_append(device->pending_ops, cmd);
472 mainloop_set_trigger(device->work);
473
474 delay_max = get_action_delay_max(device, cmd->action);
475 delay_base = get_action_delay_base(device, cmd->action);
476 if (delay_max == 0) {
477 delay_max = delay_base;
478 }
479 if (delay_max < delay_base) {
480 crm_warn("Base-delay (%dms) is larger than max-delay (%dms) "
481 "for %s on %s - limiting to max-delay",
482 delay_base, delay_max, cmd->action, device->id);
483 delay_base = delay_max;
484 }
485 if (delay_max > 0) {
486
487 cmd->start_delay =
488 ((delay_max != delay_base)?(rand() % (delay_max - delay_base)):0)
489 + delay_base;
490 crm_notice("Delaying %s on %s for %lldms (timeout=%ds, base=%dms, "
491 "max=%dms)",
492 cmd->action, device->id, cmd->start_delay, cmd->timeout,
493 delay_base, delay_max);
494 cmd->delay_id =
495 g_timeout_add(cmd->start_delay, start_delay_helper, cmd);
496 }
497 }
498
499 void
500 free_device(gpointer data)
501 {
502 GListPtr gIter = NULL;
503 stonith_device_t *device = data;
504
505 g_hash_table_destroy(device->params);
506 g_hash_table_destroy(device->aliases);
507
508 for (gIter = device->pending_ops; gIter != NULL; gIter = gIter->next) {
509 async_command_t *cmd = gIter->data;
510
511 crm_warn("Removal of device '%s' purged operation %s", device->id, cmd->action);
512 cmd->done_cb(0, -ENODEV, NULL, cmd);
513 }
514 g_list_free(device->pending_ops);
515
516 g_list_free_full(device->targets, free);
517
518 mainloop_destroy_trigger(device->work);
519
520 free_xml(device->agent_metadata);
521 free(device->namespace);
522 free(device->on_target_actions);
523 free(device->agent);
524 free(device->id);
525 free(device);
526 }
527
528 static GHashTable *
529 build_port_aliases(const char *hostmap, GListPtr * targets)
530 {
531 char *name = NULL;
532 int last = 0, lpc = 0, max = 0, added = 0;
533 GHashTable *aliases = crm_strcase_table_new();
534
535 if (hostmap == NULL) {
536 return aliases;
537 }
538
539 max = strlen(hostmap);
540 for (; lpc <= max; lpc++) {
541 switch (hostmap[lpc]) {
542
543 case '=':
544 case ':':
545 if (lpc > last) {
546 free(name);
547 name = calloc(1, 1 + lpc - last);
548 memcpy(name, hostmap + last, lpc - last);
549 }
550 last = lpc + 1;
551 break;
552
553
554
555 case 0:
556 case ';':
557 case ' ':
558 case '\t':
559 if (name) {
560 char *value = NULL;
561
562 value = calloc(1, 1 + lpc - last);
563 memcpy(value, hostmap + last, lpc - last);
564
565 crm_debug("Adding alias '%s'='%s'", name, value);
566 g_hash_table_replace(aliases, name, value);
567 if (targets) {
568 *targets = g_list_append(*targets, strdup(value));
569 }
570 value = NULL;
571 name = NULL;
572 added++;
573
574 } else if (lpc > last) {
575 crm_debug("Parse error at offset %d near '%s'", lpc - last, hostmap + last);
576 }
577
578 last = lpc + 1;
579 break;
580 }
581
582 if (hostmap[lpc] == 0) {
583 break;
584 }
585 }
586
587 if (added == 0) {
588 crm_info("No host mappings detected in '%s'", hostmap);
589 }
590
591 free(name);
592 return aliases;
593 }
594
595 static void
596 parse_host_line(const char *line, int max, GListPtr * output)
597 {
598 int lpc = 0;
599 int last = 0;
600
601 if (max <= 0) {
602 return;
603 }
604
605
606 if (strstr(line, "invalid") || strstr(line, "variable")) {
607 crm_debug("Skipping: %s", line);
608 return;
609 }
610
611 crm_trace("Processing %d bytes: [%s]", max, line);
612
613 for (lpc = 0; lpc <= max && isspace(line[lpc]); lpc++) {
614 last = lpc + 1;
615 }
616
617
618 for (lpc = 0; lpc <= max; lpc++) {
619 gboolean a_space = isspace(line[lpc]);
620
621 if (a_space && lpc < max && isspace(line[lpc + 1])) {
622
623
624 } else if (a_space || line[lpc] == ',' || line[lpc] == ';' || line[lpc] == 0) {
625 int rc = 1;
626 char *entry = NULL;
627
628 if (lpc != last) {
629 entry = calloc(1, 1 + lpc - last);
630 rc = sscanf(line + last, "%[a-zA-Z0-9_-.]", entry);
631 }
632
633 if (entry == NULL) {
634
635 } else if (rc != 1) {
636 crm_warn("Could not parse (%d %d): %s", last, lpc, line + last);
637 } else if (safe_str_neq(entry, "on") && safe_str_neq(entry, "off")) {
638 crm_trace("Adding '%s'", entry);
639 *output = g_list_append(*output, entry);
640 entry = NULL;
641 }
642
643 free(entry);
644 last = lpc + 1;
645 }
646 }
647 }
648
649 static GListPtr
650 parse_host_list(const char *hosts)
651 {
652 int lpc = 0;
653 int max = 0;
654 int last = 0;
655 GListPtr output = NULL;
656
657 if (hosts == NULL) {
658 return output;
659 }
660
661 max = strlen(hosts);
662 for (lpc = 0; lpc <= max; lpc++) {
663 if (hosts[lpc] == '\n' || hosts[lpc] == 0) {
664 char *line = NULL;
665 int len = lpc - last;
666
667 if(len > 1) {
668 line = malloc(1 + len);
669 }
670
671 if(line) {
672 snprintf(line, 1 + len, "%s", hosts + last);
673 line[len] = 0;
674 parse_host_line(line, len, &output);
675 free(line);
676 }
677
678 last = lpc + 1;
679 }
680 }
681
682 crm_trace("Parsed %d entries from '%s'", g_list_length(output), hosts);
683 return output;
684 }
685
686 GHashTable *metadata_cache = NULL;
687
688 static xmlNode *
689 get_agent_metadata(const char *agent)
690 {
691 xmlNode *xml = NULL;
692 char *buffer = NULL;
693
694 if(metadata_cache == NULL) {
695 metadata_cache = crm_str_table_new();
696 }
697
698 buffer = g_hash_table_lookup(metadata_cache, agent);
699 if(safe_str_eq(agent, STONITH_WATCHDOG_AGENT)) {
700 return NULL;
701
702 } else if(buffer == NULL) {
703 stonith_t *st = stonith_api_new();
704 int rc = st->cmds->metadata(st, st_opt_sync_call, agent, NULL, &buffer, 10);
705
706 stonith_api_delete(st);
707 if (rc || !buffer) {
708 crm_err("Could not retrieve metadata for fencing agent %s", agent);
709 return NULL;
710 }
711 g_hash_table_replace(metadata_cache, strdup(agent), buffer);
712 }
713
714 xml = string2xml(buffer);
715
716 return xml;
717 }
718
719 static gboolean
720 is_nodeid_required(xmlNode * xml)
721 {
722 xmlXPathObjectPtr xpath = NULL;
723
724 if (stand_alone) {
725 return FALSE;
726 }
727
728 if (!xml) {
729 return FALSE;
730 }
731
732 xpath = xpath_search(xml, "//parameter[@name='nodeid']");
733 if (numXpathResults(xpath) <= 0) {
734 freeXpathObject(xpath);
735 return FALSE;
736 }
737
738 freeXpathObject(xpath);
739 return TRUE;
740 }
741
742 #define MAX_ACTION_LEN 256
743
744 static char *
745 add_action(char *actions, const char *action)
746 {
747 int offset = 0;
748
749 if (actions == NULL) {
750 actions = calloc(1, MAX_ACTION_LEN);
751 } else {
752 offset = strlen(actions);
753 }
754
755 if (offset > 0) {
756 offset += snprintf(actions+offset, MAX_ACTION_LEN - offset, " ");
757 }
758 offset += snprintf(actions+offset, MAX_ACTION_LEN - offset, "%s", action);
759
760 return actions;
761 }
762
763 static void
764 read_action_metadata(stonith_device_t *device)
765 {
766 xmlXPathObjectPtr xpath = NULL;
767 int max = 0;
768 int lpc = 0;
769
770 if (device->agent_metadata == NULL) {
771 return;
772 }
773
774 xpath = xpath_search(device->agent_metadata, "//action");
775 max = numXpathResults(xpath);
776
777 if (max <= 0) {
778 freeXpathObject(xpath);
779 return;
780 }
781
782 for (lpc = 0; lpc < max; lpc++) {
783 const char *on_target = NULL;
784 const char *action = NULL;
785 xmlNode *match = getXpathResult(xpath, lpc);
786
787 CRM_LOG_ASSERT(match != NULL);
788 if(match == NULL) { continue; };
789
790 on_target = crm_element_value(match, "on_target");
791 action = crm_element_value(match, "name");
792
793 if(safe_str_eq(action, "list")) {
794 set_bit(device->flags, st_device_supports_list);
795 } else if(safe_str_eq(action, "status")) {
796 set_bit(device->flags, st_device_supports_status);
797 } else if(safe_str_eq(action, "reboot")) {
798 set_bit(device->flags, st_device_supports_reboot);
799 } else if (safe_str_eq(action, "on")) {
800
801 const char *automatic = crm_element_value(match, "automatic");
802
803
804 const char *required = crm_element_value(match, "required");
805
806 if (crm_is_true(automatic) || crm_is_true(required)) {
807 device->automatic_unfencing = TRUE;
808 }
809 }
810
811 if (action && crm_is_true(on_target)) {
812 device->on_target_actions = add_action(device->on_target_actions, action);
813 }
814 }
815
816 freeXpathObject(xpath);
817 }
818
819
820
821
822
823
824
825
826
827 static void
828 map_action(GHashTable *params, const char *action, const char *value)
829 {
830 char *key = crm_strdup_printf("pcmk_%s_action", action);
831
832 if (g_hash_table_lookup(params, key)) {
833 crm_warn("Ignoring %s='%s', see %s instead",
834 STONITH_ATTR_ACTION_OP, value, key);
835 free(key);
836 } else {
837 crm_warn("Mapping %s='%s' to %s='%s'",
838 STONITH_ATTR_ACTION_OP, value, key, value);
839 g_hash_table_insert(params, key, strdup(value));
840 }
841 }
842
843
844
845
846
847
848
849
850 static GHashTable *
851 xml2device_params(const char *name, xmlNode *dev)
852 {
853 GHashTable *params = xml2list(dev);
854 const char *value;
855
856
857
858
859
860 value = g_hash_table_lookup(params, STONITH_ATTR_ACTION_OP);
861 if (value != NULL) {
862 crm_warn("%s has '%s' parameter, which should never be specified in configuration",
863 name, STONITH_ATTR_ACTION_OP);
864
865 if (*value == '\0') {
866 crm_warn("Ignoring empty '%s' parameter", STONITH_ATTR_ACTION_OP);
867
868 } else if (strcmp(value, "reboot") == 0) {
869 crm_warn("Ignoring %s='reboot' (see stonith-action cluster property instead)",
870 STONITH_ATTR_ACTION_OP);
871
872 } else if (strcmp(value, "off") == 0) {
873 map_action(params, "reboot", value);
874
875 } else {
876 map_action(params, "off", value);
877 map_action(params, "reboot", value);
878 }
879
880 g_hash_table_remove(params, STONITH_ATTR_ACTION_OP);
881 }
882
883 return params;
884 }
885
886 static stonith_device_t *
887 build_device_from_xml(xmlNode * msg)
888 {
889 const char *value = NULL;
890 xmlNode *dev = get_xpath_object("//" F_STONITH_DEVICE, msg, LOG_ERR);
891 stonith_device_t *device = NULL;
892
893 device = calloc(1, sizeof(stonith_device_t));
894 device->id = crm_element_value_copy(dev, XML_ATTR_ID);
895 device->agent = crm_element_value_copy(dev, "agent");
896 device->namespace = crm_element_value_copy(dev, "namespace");
897 device->params = xml2device_params(device->id, dev);
898
899 value = g_hash_table_lookup(device->params, STONITH_ATTR_HOSTLIST);
900 if (value) {
901 device->targets = parse_host_list(value);
902 }
903
904 value = g_hash_table_lookup(device->params, STONITH_ATTR_HOSTMAP);
905 device->aliases = build_port_aliases(value, &(device->targets));
906
907 device->agent_metadata = get_agent_metadata(device->agent);
908 read_action_metadata(device);
909
910 value = g_hash_table_lookup(device->params, "nodeid");
911 if (!value) {
912 device->include_nodeid = is_nodeid_required(device->agent_metadata);
913 }
914
915 value = crm_element_value(dev, "rsc_provides");
916 if (safe_str_eq(value, "unfencing")) {
917 device->automatic_unfencing = TRUE;
918 }
919
920 if (is_action_required("on", device)) {
921 crm_info("The fencing device '%s' requires unfencing", device->id);
922 }
923
924 if (device->on_target_actions) {
925 crm_info("The fencing device '%s' requires actions (%s) to be executed on the target node",
926 device->id, device->on_target_actions);
927 }
928
929 device->work = mainloop_add_trigger(G_PRIORITY_HIGH, stonith_device_dispatch, device);
930
931
932 return device;
933 }
934
935 static const char *
936 target_list_type(stonith_device_t * dev)
937 {
938 const char *check_type = NULL;
939
940 check_type = g_hash_table_lookup(dev->params, STONITH_ATTR_HOSTCHECK);
941
942 if (check_type == NULL) {
943
944 if (g_hash_table_lookup(dev->params, STONITH_ATTR_HOSTLIST)) {
945 check_type = "static-list";
946 } else if (g_hash_table_lookup(dev->params, STONITH_ATTR_HOSTMAP)) {
947 check_type = "static-list";
948 } else if(is_set(dev->flags, st_device_supports_list)){
949 check_type = "dynamic-list";
950 } else if(is_set(dev->flags, st_device_supports_status)){
951 check_type = "status";
952 } else {
953 check_type = "none";
954 }
955 }
956
957 return check_type;
958 }
959
960 void
961 schedule_internal_command(const char *origin,
962 stonith_device_t * device,
963 const char *action,
964 const char *victim,
965 int timeout,
966 void *internal_user_data,
967 void (*done_cb) (GPid pid, int rc, const char *output,
968 gpointer user_data))
969 {
970 async_command_t *cmd = NULL;
971
972 cmd = calloc(1, sizeof(async_command_t));
973
974 cmd->id = -1;
975 cmd->default_timeout = timeout ? timeout : 60;
976 cmd->timeout = cmd->default_timeout;
977 cmd->action = strdup(action);
978 cmd->victim = victim ? strdup(victim) : NULL;
979 cmd->device = strdup(device->id);
980 cmd->origin = strdup(origin);
981 cmd->client = strdup(crm_system_name);
982 cmd->client_name = strdup(crm_system_name);
983
984 cmd->internal_user_data = internal_user_data;
985 cmd->done_cb = done_cb;
986
987 schedule_stonith_command(cmd, device);
988 }
989
990 gboolean
991 string_in_list(GListPtr list, const char *item)
992 {
993 int lpc = 0;
994 int max = g_list_length(list);
995
996 for (lpc = 0; lpc < max; lpc++) {
997 const char *value = g_list_nth_data(list, lpc);
998
999 if (safe_str_eq(item, value)) {
1000 return TRUE;
1001 } else {
1002 crm_trace("%d: '%s' != '%s'", lpc, item, value);
1003 }
1004 }
1005 return FALSE;
1006 }
1007
1008 static void
1009 status_search_cb(GPid pid, int rc, const char *output, gpointer user_data)
1010 {
1011 async_command_t *cmd = user_data;
1012 struct device_search_s *search = cmd->internal_user_data;
1013 stonith_device_t *dev = cmd->device ? g_hash_table_lookup(device_list, cmd->device) : NULL;
1014 gboolean can = FALSE;
1015
1016 free_async_command(cmd);
1017
1018 if (!dev) {
1019 search_devices_record_result(search, NULL, FALSE);
1020 return;
1021 }
1022
1023 mainloop_set_trigger(dev->work);
1024
1025 if (rc == 1 ) {
1026 crm_trace("Host %s is not known by %s", search->host, dev->id);
1027
1028 } else if (rc == 0 || rc == 2 ) {
1029 crm_trace("Host %s is known by %s", search->host, dev->id);
1030 can = TRUE;
1031
1032 } else {
1033 crm_notice("Unknown result when testing if %s can fence %s: rc=%d", dev->id, search->host,
1034 rc);
1035 }
1036 search_devices_record_result(search, dev->id, can);
1037 }
1038
1039 static void
1040 dynamic_list_search_cb(GPid pid, int rc, const char *output, gpointer user_data)
1041 {
1042 async_command_t *cmd = user_data;
1043 struct device_search_s *search = cmd->internal_user_data;
1044 stonith_device_t *dev = cmd->device ? g_hash_table_lookup(device_list, cmd->device) : NULL;
1045 gboolean can_fence = FALSE;
1046
1047 free_async_command(cmd);
1048
1049
1050
1051
1052
1053
1054 if (!dev) {
1055 search_devices_record_result(search, NULL, FALSE);
1056 return;
1057 }
1058
1059 mainloop_set_trigger(dev->work);
1060
1061
1062 if (rc != 0 && !dev->targets) {
1063 crm_notice("Disabling port list queries for %s (%d): %s", dev->id, rc, output);
1064
1065 g_hash_table_replace(dev->params, strdup(STONITH_ATTR_HOSTCHECK), strdup("status"));
1066
1067 g_list_free_full(dev->targets, free);
1068 dev->targets = NULL;
1069 } else if (!rc) {
1070 crm_info("Refreshing port list for %s", dev->id);
1071 g_list_free_full(dev->targets, free);
1072 dev->targets = parse_host_list(output);
1073 dev->targets_age = time(NULL);
1074 }
1075
1076 if (dev->targets) {
1077 const char *alias = g_hash_table_lookup(dev->aliases, search->host);
1078
1079 if (!alias) {
1080 alias = search->host;
1081 }
1082 if (string_in_list(dev->targets, alias)) {
1083 can_fence = TRUE;
1084 }
1085 }
1086 search_devices_record_result(search, dev->id, can_fence);
1087 }
1088
1089
1090
1091
1092
1093 static int
1094 device_params_diff(GHashTable *first, GHashTable *second) {
1095 char *key = NULL;
1096 char *value = NULL;
1097 GHashTableIter gIter;
1098
1099 g_hash_table_iter_init(&gIter, first);
1100 while (g_hash_table_iter_next(&gIter, (void **)&key, (void **)&value)) {
1101
1102 if(strstr(key, "CRM_meta") == key) {
1103 continue;
1104 } else if(strcmp(key, "crm_feature_set") == 0) {
1105 continue;
1106 } else {
1107 char *other_value = g_hash_table_lookup(second, key);
1108
1109 if (!other_value || safe_str_neq(other_value, value)) {
1110 crm_trace("Different value for %s: %s != %s", key, other_value, value);
1111 return 1;
1112 }
1113 }
1114 }
1115
1116 return 0;
1117 }
1118
1119
1120
1121
1122
1123 static stonith_device_t *
1124 device_has_duplicate(stonith_device_t * device)
1125 {
1126 stonith_device_t *dup = g_hash_table_lookup(device_list, device->id);
1127
1128 if (!dup) {
1129 crm_trace("No match for %s", device->id);
1130 return NULL;
1131
1132 } else if (safe_str_neq(dup->agent, device->agent)) {
1133 crm_trace("Different agent: %s != %s", dup->agent, device->agent);
1134 return NULL;
1135 }
1136
1137
1138 if (device_params_diff(device->params, dup->params) ||
1139 device_params_diff(dup->params, device->params)) {
1140 return NULL;
1141 }
1142
1143 crm_trace("Match");
1144 return dup;
1145 }
1146
1147 int
1148 stonith_device_register(xmlNode * msg, const char **desc, gboolean from_cib)
1149 {
1150 stonith_device_t *dup = NULL;
1151 stonith_device_t *device = build_device_from_xml(msg);
1152
1153 dup = device_has_duplicate(device);
1154 if (dup) {
1155 crm_debug("Device '%s' already existed in device list (%d active devices)", device->id,
1156 g_hash_table_size(device_list));
1157 free_device(device);
1158 device = dup;
1159
1160 } else {
1161 stonith_device_t *old = g_hash_table_lookup(device_list, device->id);
1162
1163 if (from_cib && old && old->api_registered) {
1164
1165
1166
1167
1168 crm_info("Overwriting an existing entry for %s from the cib", device->id);
1169 device->pending_ops = old->pending_ops;
1170 device->api_registered = TRUE;
1171 old->pending_ops = NULL;
1172 if (device->pending_ops) {
1173 mainloop_set_trigger(device->work);
1174 }
1175 }
1176 g_hash_table_replace(device_list, device->id, device);
1177
1178 crm_notice("Added '%s' to the device list (%d active devices)", device->id,
1179 g_hash_table_size(device_list));
1180 }
1181 if (desc) {
1182 *desc = device->id;
1183 }
1184
1185 if (from_cib) {
1186 device->cib_registered = TRUE;
1187 } else {
1188 device->api_registered = TRUE;
1189 }
1190
1191 return pcmk_ok;
1192 }
1193
1194 int
1195 stonith_device_remove(const char *id, gboolean from_cib)
1196 {
1197 stonith_device_t *device = g_hash_table_lookup(device_list, id);
1198
1199 if (!device) {
1200 crm_info("Device '%s' not found (%d active devices)", id, g_hash_table_size(device_list));
1201 return pcmk_ok;
1202 }
1203
1204 if (from_cib) {
1205 device->cib_registered = FALSE;
1206 } else {
1207 device->verified = FALSE;
1208 device->api_registered = FALSE;
1209 }
1210
1211 if (!device->cib_registered && !device->api_registered) {
1212 g_hash_table_remove(device_list, id);
1213 crm_info("Removed '%s' from the device list (%d active devices)",
1214 id, g_hash_table_size(device_list));
1215 } else {
1216 crm_trace("Not removing '%s' from the device list (%d active devices) "
1217 "- still %s%s_registered", id, g_hash_table_size(device_list),
1218 device->cib_registered?"cib":"", device->api_registered?"api":"");
1219 }
1220 return pcmk_ok;
1221 }
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232 static int
1233 count_active_levels(stonith_topology_t * tp)
1234 {
1235 int lpc = 0;
1236 int count = 0;
1237
1238 for (lpc = 0; lpc < ST_LEVEL_MAX; lpc++) {
1239 if (tp->levels[lpc] != NULL) {
1240 count++;
1241 }
1242 }
1243 return count;
1244 }
1245
1246 void
1247 free_topology_entry(gpointer data)
1248 {
1249 stonith_topology_t *tp = data;
1250
1251 int lpc = 0;
1252
1253 for (lpc = 0; lpc < ST_LEVEL_MAX; lpc++) {
1254 if (tp->levels[lpc] != NULL) {
1255 g_list_free_full(tp->levels[lpc], free);
1256 }
1257 }
1258 free(tp->target);
1259 free(tp->target_value);
1260 free(tp->target_pattern);
1261 free(tp->target_attribute);
1262 free(tp);
1263 }
1264
1265 char *stonith_level_key(xmlNode *level, int mode)
1266 {
1267 if(mode == -1) {
1268 mode = stonith_level_kind(level);
1269 }
1270
1271 switch(mode) {
1272 case 0:
1273 return crm_element_value_copy(level, XML_ATTR_STONITH_TARGET);
1274 case 1:
1275 return crm_element_value_copy(level, XML_ATTR_STONITH_TARGET_PATTERN);
1276 case 2:
1277 {
1278 const char *name = crm_element_value(level, XML_ATTR_STONITH_TARGET_ATTRIBUTE);
1279 const char *value = crm_element_value(level, XML_ATTR_STONITH_TARGET_VALUE);
1280
1281 if(name && value) {
1282 return crm_strdup_printf("%s=%s", name, value);
1283 }
1284 }
1285 default:
1286 return crm_strdup_printf("Unknown-%d-%s", mode, ID(level));
1287 }
1288 }
1289
1290 int stonith_level_kind(xmlNode * level)
1291 {
1292 int mode = 0;
1293 const char *target = crm_element_value(level, XML_ATTR_STONITH_TARGET);
1294
1295 if(target == NULL) {
1296 mode++;
1297 target = crm_element_value(level, XML_ATTR_STONITH_TARGET_PATTERN);
1298 }
1299
1300 if(stand_alone == FALSE && target == NULL) {
1301
1302 mode++;
1303
1304 if(crm_element_value(level, XML_ATTR_STONITH_TARGET_ATTRIBUTE) == NULL) {
1305 mode++;
1306
1307 } else if(crm_element_value(level, XML_ATTR_STONITH_TARGET_VALUE) == NULL) {
1308 mode++;
1309 }
1310 }
1311
1312 return mode;
1313 }
1314
1315 static stonith_key_value_t *
1316 parse_device_list(const char *devices)
1317 {
1318 int lpc = 0;
1319 int max = 0;
1320 int last = 0;
1321 stonith_key_value_t *output = NULL;
1322
1323 if (devices == NULL) {
1324 return output;
1325 }
1326
1327 max = strlen(devices);
1328 for (lpc = 0; lpc <= max; lpc++) {
1329 if (devices[lpc] == ',' || devices[lpc] == 0) {
1330 char *line = NULL;
1331
1332 line = calloc(1, 2 + lpc - last);
1333 snprintf(line, 1 + lpc - last, "%s", devices + last);
1334 output = stonith_key_value_add(output, NULL, line);
1335 free(line);
1336
1337 last = lpc + 1;
1338 }
1339 }
1340
1341 return output;
1342 }
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358 int
1359 stonith_level_register(xmlNode *msg, char **desc)
1360 {
1361 int id = 0;
1362 xmlNode *level;
1363 int mode;
1364 char *target;
1365
1366 stonith_topology_t *tp;
1367 stonith_key_value_t *dIter = NULL;
1368 stonith_key_value_t *devices = NULL;
1369
1370
1371
1372
1373
1374 if (safe_str_eq(TYPE(msg), XML_TAG_FENCING_LEVEL)) {
1375 level = msg;
1376 } else {
1377 level = get_xpath_object("//" XML_TAG_FENCING_LEVEL, msg, LOG_ERR);
1378 }
1379 CRM_CHECK(level != NULL, return -EINVAL);
1380
1381 mode = stonith_level_kind(level);
1382 target = stonith_level_key(level, mode);
1383 crm_element_value_int(level, XML_ATTR_STONITH_INDEX, &id);
1384
1385 if (desc) {
1386 *desc = crm_strdup_printf("%s[%d]", target, id);
1387 }
1388
1389
1390 if (mode >= 3 || (id <= 0) || (id >= ST_LEVEL_MAX)) {
1391 crm_trace("Could not add %s[%d] (%d) to the topology (%d active entries)", target, id, mode, g_hash_table_size(topology));
1392 free(target);
1393 crm_log_xml_err(level, "Bad topology");
1394 return -EINVAL;
1395 }
1396
1397
1398 tp = g_hash_table_lookup(topology, target);
1399 if (tp == NULL) {
1400 tp = calloc(1, sizeof(stonith_topology_t));
1401 tp->kind = mode;
1402 tp->target = target;
1403 tp->target_value = crm_element_value_copy(level, XML_ATTR_STONITH_TARGET_VALUE);
1404 tp->target_pattern = crm_element_value_copy(level, XML_ATTR_STONITH_TARGET_PATTERN);
1405 tp->target_attribute = crm_element_value_copy(level, XML_ATTR_STONITH_TARGET_ATTRIBUTE);
1406
1407 g_hash_table_replace(topology, tp->target, tp);
1408 crm_trace("Added %s (%d) to the topology (%d active entries)",
1409 target, mode, g_hash_table_size(topology));
1410 } else {
1411 free(target);
1412 }
1413
1414 if (tp->levels[id] != NULL) {
1415 crm_info("Adding to the existing %s[%d] topology entry",
1416 tp->target, id);
1417 }
1418
1419 devices = parse_device_list(crm_element_value(level, XML_ATTR_STONITH_DEVICES));
1420 for (dIter = devices; dIter; dIter = dIter->next) {
1421 const char *device = dIter->value;
1422
1423 crm_trace("Adding device '%s' for %s[%d]", device, tp->target, id);
1424 tp->levels[id] = g_list_append(tp->levels[id], strdup(device));
1425 }
1426 stonith_key_value_freeall(devices, 1, 1);
1427
1428 crm_info("Target %s has %d active fencing levels",
1429 tp->target, count_active_levels(tp));
1430 return pcmk_ok;
1431 }
1432
1433 int
1434 stonith_level_remove(xmlNode *msg, char **desc)
1435 {
1436 int id = 0;
1437 stonith_topology_t *tp;
1438 char *target;
1439
1440
1441 xmlNode *level = get_xpath_object("//" XML_TAG_FENCING_LEVEL, msg, LOG_ERR);
1442
1443 CRM_CHECK(level != NULL, return -EINVAL);
1444
1445 target = stonith_level_key(level, -1);
1446 crm_element_value_int(level, XML_ATTR_STONITH_INDEX, &id);
1447 if (desc) {
1448 *desc = crm_strdup_printf("%s[%d]", target, id);
1449 }
1450
1451
1452 if (id >= ST_LEVEL_MAX) {
1453 free(target);
1454 return -EINVAL;
1455 }
1456
1457 tp = g_hash_table_lookup(topology, target);
1458 if (tp == NULL) {
1459 crm_info("Topology for %s not found (%d active entries)",
1460 target, g_hash_table_size(topology));
1461
1462 } else if (id == 0 && g_hash_table_remove(topology, target)) {
1463 crm_info("Removed all %s related entries from the topology (%d active entries)",
1464 target, g_hash_table_size(topology));
1465
1466 } else if (id > 0 && tp->levels[id] != NULL) {
1467 g_list_free_full(tp->levels[id], free);
1468 tp->levels[id] = NULL;
1469
1470 crm_info("Removed level '%d' from topology for %s (%d active levels remaining)",
1471 id, target, count_active_levels(tp));
1472 }
1473
1474 free(target);
1475 return pcmk_ok;
1476 }
1477
1478 static int
1479 stonith_device_action(xmlNode * msg, char **output)
1480 {
1481 int rc = pcmk_ok;
1482 xmlNode *dev = get_xpath_object("//" F_STONITH_DEVICE, msg, LOG_ERR);
1483 const char *id = crm_element_value(dev, F_STONITH_DEVICE);
1484
1485 async_command_t *cmd = NULL;
1486 stonith_device_t *device = NULL;
1487
1488 if (id) {
1489 crm_trace("Looking for '%s'", id);
1490 device = g_hash_table_lookup(device_list, id);
1491 }
1492
1493 if (device && device->api_registered == FALSE) {
1494 rc = -ENODEV;
1495
1496 } else if (device) {
1497 cmd = create_async_command(msg);
1498 if (cmd == NULL) {
1499 return -EPROTO;
1500 }
1501
1502 schedule_stonith_command(cmd, device);
1503 rc = -EINPROGRESS;
1504
1505 } else {
1506 crm_info("Device %s not found", id ? id : "<none>");
1507 rc = -ENODEV;
1508 }
1509 return rc;
1510 }
1511
1512 static void
1513 search_devices_record_result(struct device_search_s *search, const char *device, gboolean can_fence)
1514 {
1515 search->replies_received++;
1516
1517 if (can_fence && device) {
1518 search->capable = g_list_append(search->capable, strdup(device));
1519 }
1520
1521 if (search->replies_needed == search->replies_received) {
1522
1523 crm_debug("Finished Search. %d devices can perform action (%s) on node %s",
1524 g_list_length(search->capable),
1525 search->action ? search->action : "<unknown>",
1526 search->host ? search->host : "<anyone>");
1527
1528 search->callback(search->capable, search->user_data);
1529 free(search->host);
1530 free(search->action);
1531 free(search);
1532 }
1533 }
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546 static gboolean
1547 localhost_is_eligible(const stonith_device_t *device, const char *action,
1548 const char *target, gboolean allow_suicide)
1549 {
1550 gboolean localhost_is_target = safe_str_eq(target, stonith_our_uname);
1551
1552 if (device && action && device->on_target_actions
1553 && strstr(device->on_target_actions, action)) {
1554 if (!localhost_is_target) {
1555 crm_trace("%s operation with %s can only be executed for localhost not %s",
1556 action, device->id, target);
1557 return FALSE;
1558 }
1559
1560 } else if (localhost_is_target && !allow_suicide) {
1561 crm_trace("%s operation does not support self-fencing", action);
1562 return FALSE;
1563 }
1564 return TRUE;
1565 }
1566
1567 static void
1568 can_fence_host_with_device(stonith_device_t * dev, struct device_search_s *search)
1569 {
1570 gboolean can = FALSE;
1571 const char *check_type = NULL;
1572 const char *host = search->host;
1573 const char *alias = NULL;
1574
1575 CRM_LOG_ASSERT(dev != NULL);
1576
1577 if (dev == NULL) {
1578 goto search_report_results;
1579 } else if (host == NULL) {
1580 can = TRUE;
1581 goto search_report_results;
1582 }
1583
1584
1585 if (safe_str_eq(search->action, "reboot")) {
1586
1587
1588
1589
1590
1591 if (!localhost_is_eligible(dev, "reboot", host, search->allow_suicide)
1592 && !localhost_is_eligible(dev, "off", host, search->allow_suicide)
1593 && !localhost_is_eligible(dev, "on", host, FALSE)) {
1594 goto search_report_results;
1595 }
1596 } else if (!localhost_is_eligible(dev, search->action, host,
1597 search->allow_suicide)) {
1598 goto search_report_results;
1599 }
1600
1601 alias = g_hash_table_lookup(dev->aliases, host);
1602 if (alias == NULL) {
1603 alias = host;
1604 }
1605
1606 check_type = target_list_type(dev);
1607
1608 if (safe_str_eq(check_type, "none")) {
1609 can = TRUE;
1610
1611 } else if (safe_str_eq(check_type, "static-list")) {
1612
1613
1614
1615
1616
1617 if (string_in_list(dev->targets, host)) {
1618 can = TRUE;
1619 } else if (g_hash_table_lookup(dev->params, STONITH_ATTR_HOSTMAP)
1620 && g_hash_table_lookup(dev->aliases, host)) {
1621 can = TRUE;
1622 }
1623
1624 } else if (safe_str_eq(check_type, "dynamic-list")) {
1625 time_t now = time(NULL);
1626
1627 if (dev->targets == NULL || dev->targets_age + 60 < now) {
1628 crm_trace("Running %s command to see if %s can fence %s (%s)",
1629 check_type, dev?dev->id:"N/A", search->host, search->action);
1630
1631 schedule_internal_command(__FUNCTION__, dev, "list", NULL,
1632 search->per_device_timeout, search, dynamic_list_search_cb);
1633
1634
1635 return;
1636 }
1637
1638 if (string_in_list(dev->targets, alias)) {
1639 can = TRUE;
1640 }
1641
1642 } else if (safe_str_eq(check_type, "status")) {
1643 crm_trace("Running %s command to see if %s can fence %s (%s)",
1644 check_type, dev?dev->id:"N/A", search->host, search->action);
1645 schedule_internal_command(__FUNCTION__, dev, "status", search->host,
1646 search->per_device_timeout, search, status_search_cb);
1647
1648 return;
1649 } else {
1650 crm_err("Unknown check type: %s", check_type);
1651 }
1652
1653 if (safe_str_eq(host, alias)) {
1654 crm_notice("%s can%s fence (%s) %s: %s", dev->id, can ? "" : " not", search->action, host, check_type);
1655 } else {
1656 crm_notice("%s can%s fence (%s) %s (aka. '%s'): %s", dev->id, can ? "" : " not", search->action, host, alias,
1657 check_type);
1658 }
1659
1660 search_report_results:
1661 search_devices_record_result(search, dev ? dev->id : NULL, can);
1662 }
1663
1664 static void
1665 search_devices(gpointer key, gpointer value, gpointer user_data)
1666 {
1667 stonith_device_t *dev = value;
1668 struct device_search_s *search = user_data;
1669
1670 can_fence_host_with_device(dev, search);
1671 }
1672
1673 #define DEFAULT_QUERY_TIMEOUT 20
1674 static void
1675 get_capable_devices(const char *host, const char *action, int timeout, bool suicide, void *user_data,
1676 void (*callback) (GList * devices, void *user_data))
1677 {
1678 struct device_search_s *search;
1679 int per_device_timeout = DEFAULT_QUERY_TIMEOUT;
1680 int devices_needing_async_query = 0;
1681 char *key = NULL;
1682 const char *check_type = NULL;
1683 GHashTableIter gIter;
1684 stonith_device_t *device = NULL;
1685
1686 if (!g_hash_table_size(device_list)) {
1687 callback(NULL, user_data);
1688 return;
1689 }
1690
1691 search = calloc(1, sizeof(struct device_search_s));
1692 if (!search) {
1693 callback(NULL, user_data);
1694 return;
1695 }
1696
1697 g_hash_table_iter_init(&gIter, device_list);
1698 while (g_hash_table_iter_next(&gIter, (void **)&key, (void **)&device)) {
1699 check_type = target_list_type(device);
1700 if (safe_str_eq(check_type, "status") || safe_str_eq(check_type, "dynamic-list")) {
1701 devices_needing_async_query++;
1702 }
1703 }
1704
1705
1706
1707
1708 if (devices_needing_async_query) {
1709 per_device_timeout = timeout / devices_needing_async_query;
1710 if (!per_device_timeout) {
1711 crm_err("STONITH timeout %ds is too low; using %ds, but consider raising to at least %ds",
1712 timeout, DEFAULT_QUERY_TIMEOUT,
1713 DEFAULT_QUERY_TIMEOUT * devices_needing_async_query);
1714 per_device_timeout = DEFAULT_QUERY_TIMEOUT;
1715 } else if (per_device_timeout < DEFAULT_QUERY_TIMEOUT) {
1716 crm_notice("STONITH timeout %ds is low for the current configuration;"
1717 " consider raising to at least %ds",
1718 timeout, DEFAULT_QUERY_TIMEOUT * devices_needing_async_query);
1719 }
1720 }
1721
1722 search->host = host ? strdup(host) : NULL;
1723 search->action = action ? strdup(action) : NULL;
1724 search->per_device_timeout = per_device_timeout;
1725
1726
1727
1728 search->replies_needed = g_hash_table_size(device_list);
1729 search->allow_suicide = suicide;
1730 search->callback = callback;
1731 search->user_data = user_data;
1732
1733
1734 crm_debug("Searching through %d devices to see what is capable of action (%s) for target %s",
1735 search->replies_needed,
1736 search->action ? search->action : "<unknown>",
1737 search->host ? search->host : "<anyone>");
1738 g_hash_table_foreach(device_list, search_devices, search);
1739 }
1740
1741 struct st_query_data {
1742 xmlNode *reply;
1743 char *remote_peer;
1744 char *client_id;
1745 char *target;
1746 char *action;
1747 int call_options;
1748 };
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758 static void
1759 add_action_specific_attributes(xmlNode *xml, const char *action,
1760 stonith_device_t *device)
1761 {
1762 int action_specific_timeout;
1763 int delay_max;
1764 int delay_base;
1765
1766 CRM_CHECK(xml && action && device, return);
1767
1768 if (is_action_required(action, device)) {
1769 crm_trace("Action %s is required on %s", action, device->id);
1770 crm_xml_add_int(xml, F_STONITH_DEVICE_REQUIRED, 1);
1771 }
1772
1773 action_specific_timeout = get_action_timeout(device, action, 0);
1774 if (action_specific_timeout) {
1775 crm_trace("Action %s has timeout %dms on %s",
1776 action, action_specific_timeout, device->id);
1777 crm_xml_add_int(xml, F_STONITH_ACTION_TIMEOUT, action_specific_timeout);
1778 }
1779
1780 delay_max = get_action_delay_max(device, action);
1781 if (delay_max > 0) {
1782 crm_trace("Action %s has maximum random delay %dms on %s",
1783 action, delay_max, device->id);
1784 crm_xml_add_int(xml, F_STONITH_DELAY_MAX, delay_max / 1000);
1785 }
1786
1787 delay_base = get_action_delay_base(device, action);
1788 if (delay_base > 0) {
1789 crm_xml_add_int(xml, F_STONITH_DELAY_BASE, delay_base / 1000);
1790 }
1791
1792 if ((delay_max > 0) && (delay_base == 0)) {
1793 crm_trace("Action %s has maximum random delay %dms on %s",
1794 action, delay_max, device->id);
1795 } else if ((delay_max == 0) && (delay_base > 0)) {
1796 crm_trace("Action %s has a static delay of %dms on %s",
1797 action, delay_base, device->id);
1798 } else if ((delay_max > 0) && (delay_base > 0)) {
1799 crm_trace("Action %s has a minimum delay of %dms and a randomly chosen "
1800 "maximum delay of %dms on %s",
1801 action, delay_base, delay_max, device->id);
1802 }
1803 }
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815 static void
1816 add_disallowed(xmlNode *xml, const char *action, stonith_device_t *device,
1817 const char *target, gboolean allow_suicide)
1818 {
1819 if (!localhost_is_eligible(device, action, target, allow_suicide)) {
1820 crm_trace("Action %s on %s is disallowed for local host",
1821 action, device->id);
1822 crm_xml_add(xml, F_STONITH_ACTION_DISALLOWED, XML_BOOLEAN_TRUE);
1823 }
1824 }
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836 static void
1837 add_action_reply(xmlNode *xml, const char *action, stonith_device_t *device,
1838 const char *target, gboolean allow_suicide)
1839 {
1840 xmlNode *child = create_xml_node(xml, F_STONITH_ACTION);
1841
1842 crm_xml_add(child, XML_ATTR_ID, action);
1843 add_action_specific_attributes(child, action, device);
1844 add_disallowed(child, action, device, target, allow_suicide);
1845 }
1846
1847 static void
1848 stonith_query_capable_device_cb(GList * devices, void *user_data)
1849 {
1850 struct st_query_data *query = user_data;
1851 int available_devices = 0;
1852 xmlNode *dev = NULL;
1853 xmlNode *list = NULL;
1854 GListPtr lpc = NULL;
1855
1856
1857 list = create_xml_node(NULL, __FUNCTION__);
1858 crm_xml_add(list, F_STONITH_TARGET, query->target);
1859 for (lpc = devices; lpc != NULL; lpc = lpc->next) {
1860 stonith_device_t *device = g_hash_table_lookup(device_list, lpc->data);
1861 const char *action = query->action;
1862
1863 if (!device) {
1864
1865
1866 continue;
1867 }
1868
1869 available_devices++;
1870
1871 dev = create_xml_node(list, F_STONITH_DEVICE);
1872 crm_xml_add(dev, XML_ATTR_ID, device->id);
1873 crm_xml_add(dev, "namespace", device->namespace);
1874 crm_xml_add(dev, "agent", device->agent);
1875 crm_xml_add_int(dev, F_STONITH_DEVICE_VERIFIED, device->verified);
1876
1877
1878
1879
1880 if (is_not_set(device->flags, st_device_supports_reboot)
1881 && safe_str_eq(query->action, "reboot")) {
1882 crm_trace("%s doesn't support reboot, using values for off instead",
1883 device->id);
1884 action = "off";
1885 }
1886
1887
1888 add_action_specific_attributes(dev, action, device);
1889 if (safe_str_eq(query->action, "reboot")) {
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901 add_disallowed(dev, action, device, query->target,
1902 is_set(query->call_options, st_opt_allow_suicide));
1903 add_action_reply(dev, "off", device, query->target,
1904 is_set(query->call_options, st_opt_allow_suicide));
1905 add_action_reply(dev, "on", device, query->target, FALSE);
1906 }
1907
1908
1909 if (query->target == NULL) {
1910 xmlNode *attrs = create_xml_node(dev, XML_TAG_ATTRS);
1911
1912 g_hash_table_foreach(device->params, hash2field, attrs);
1913 }
1914 }
1915
1916 crm_xml_add_int(list, F_STONITH_AVAILABLE_DEVICES, available_devices);
1917 if (query->target) {
1918 crm_debug("Found %d matching devices for '%s'", available_devices, query->target);
1919 } else {
1920 crm_debug("%d devices installed", available_devices);
1921 }
1922
1923 if (list != NULL) {
1924 crm_log_xml_trace(list, "Add query results");
1925 add_message_xml(query->reply, F_STONITH_CALLDATA, list);
1926 }
1927 stonith_send_reply(query->reply, query->call_options, query->remote_peer, query->client_id);
1928
1929 free_xml(query->reply);
1930 free(query->remote_peer);
1931 free(query->client_id);
1932 free(query->target);
1933 free(query->action);
1934 free(query);
1935 free_xml(list);
1936 g_list_free_full(devices, free);
1937 }
1938
1939 static void
1940 stonith_query(xmlNode * msg, const char *remote_peer, const char *client_id, int call_options)
1941 {
1942 struct st_query_data *query = NULL;
1943 const char *action = NULL;
1944 const char *target = NULL;
1945 int timeout = 0;
1946 xmlNode *dev = get_xpath_object("//@" F_STONITH_ACTION, msg, LOG_DEBUG_3);
1947
1948 crm_element_value_int(msg, F_STONITH_TIMEOUT, &timeout);
1949 if (dev) {
1950 const char *device = crm_element_value(dev, F_STONITH_DEVICE);
1951
1952 target = crm_element_value(dev, F_STONITH_TARGET);
1953 action = crm_element_value(dev, F_STONITH_ACTION);
1954 if (device && safe_str_eq(device, "manual_ack")) {
1955
1956 return;
1957 }
1958 }
1959
1960 crm_log_xml_debug(msg, "Query");
1961 query = calloc(1, sizeof(struct st_query_data));
1962
1963 query->reply = stonith_construct_reply(msg, NULL, NULL, pcmk_ok);
1964 query->remote_peer = remote_peer ? strdup(remote_peer) : NULL;
1965 query->client_id = client_id ? strdup(client_id) : NULL;
1966 query->target = target ? strdup(target) : NULL;
1967 query->action = action ? strdup(action) : NULL;
1968 query->call_options = call_options;
1969
1970 get_capable_devices(target, action, timeout,
1971 is_set(call_options, st_opt_allow_suicide),
1972 query, stonith_query_capable_device_cb);
1973 }
1974
1975 #define ST_LOG_OUTPUT_MAX 512
1976 static void
1977 log_operation(async_command_t * cmd, int rc, int pid, const char *next, const char *output)
1978 {
1979 if (rc == 0) {
1980 next = NULL;
1981 }
1982
1983 if (cmd->victim != NULL) {
1984 do_crm_log(rc == 0 ? LOG_NOTICE : LOG_ERR,
1985 "Operation '%s' [%d] (call %d from %s) for host '%s' with device '%s' returned: %d (%s)%s%s",
1986 cmd->action, pid, cmd->id, cmd->client_name, cmd->victim, cmd->device, rc,
1987 pcmk_strerror(rc), next ? ". Trying: " : "", next ? next : "");
1988 } else {
1989 do_crm_log_unlikely(rc == 0 ? LOG_DEBUG : LOG_NOTICE,
1990 "Operation '%s' [%d] for device '%s' returned: %d (%s)%s%s",
1991 cmd->action, pid, cmd->device, rc, pcmk_strerror(rc),
1992 next ? ". Trying: " : "", next ? next : "");
1993 }
1994
1995 if (output) {
1996
1997 char *prefix = crm_strdup_printf("%s:%d", cmd->device, pid);
1998
1999 crm_log_output(rc == 0 ? LOG_DEBUG : LOG_WARNING, prefix, output);
2000 free(prefix);
2001 }
2002 }
2003
2004 static void
2005 stonith_send_async_reply(async_command_t * cmd, const char *output, int rc, GPid pid)
2006 {
2007 xmlNode *reply = NULL;
2008 gboolean bcast = FALSE;
2009
2010 reply = stonith_construct_async_reply(cmd, output, NULL, rc);
2011
2012 if (safe_str_eq(cmd->action, "metadata")) {
2013
2014 crm_trace("Metadata query for %s", cmd->device);
2015 output = NULL;
2016
2017 } else if (crm_str_eq(cmd->action, "monitor", TRUE) ||
2018 crm_str_eq(cmd->action, "list", TRUE) || crm_str_eq(cmd->action, "status", TRUE)) {
2019 crm_trace("Never broadcast %s replies", cmd->action);
2020
2021 } else if (!stand_alone && safe_str_eq(cmd->origin, cmd->victim) && safe_str_neq(cmd->action, "on")) {
2022 crm_trace("Broadcast %s reply for %s", cmd->action, cmd->victim);
2023 crm_xml_add(reply, F_SUBTYPE, "broadcast");
2024 bcast = TRUE;
2025 }
2026
2027 log_operation(cmd, rc, pid, NULL, output);
2028 crm_log_xml_trace(reply, "Reply");
2029
2030 if (bcast) {
2031 crm_xml_add(reply, F_STONITH_OPERATION, T_STONITH_NOTIFY);
2032 send_cluster_message(NULL, crm_msg_stonith_ng, reply, FALSE);
2033
2034 } else if (cmd->origin) {
2035 crm_trace("Directed reply to %s", cmd->origin);
2036 send_cluster_message(crm_get_peer(0, cmd->origin), crm_msg_stonith_ng, reply, FALSE);
2037
2038 } else {
2039 crm_trace("Directed local %ssync reply to %s",
2040 (cmd->options & st_opt_sync_call) ? "" : "a-", cmd->client_name);
2041 do_local_reply(reply, cmd->client, cmd->options & st_opt_sync_call, FALSE);
2042 }
2043
2044 if (stand_alone) {
2045
2046 xmlNode *notify_data = create_xml_node(NULL, T_STONITH_NOTIFY_FENCE);
2047
2048 crm_xml_add_int(notify_data, F_STONITH_RC, rc);
2049 crm_xml_add(notify_data, F_STONITH_TARGET, cmd->victim);
2050 crm_xml_add(notify_data, F_STONITH_OPERATION, cmd->op);
2051 crm_xml_add(notify_data, F_STONITH_DELEGATE, "localhost");
2052 crm_xml_add(notify_data, F_STONITH_DEVICE, cmd->device);
2053 crm_xml_add(notify_data, F_STONITH_REMOTE_OP_ID, cmd->remote_op_id);
2054 crm_xml_add(notify_data, F_STONITH_ORIGIN, cmd->client);
2055
2056 do_stonith_notify(0, T_STONITH_NOTIFY_FENCE, rc, notify_data);
2057 }
2058
2059 free_xml(reply);
2060 }
2061
2062 void
2063 unfence_cb(GPid pid, int rc, const char *output, gpointer user_data)
2064 {
2065 async_command_t * cmd = user_data;
2066 stonith_device_t *dev = g_hash_table_lookup(device_list, cmd->device);
2067
2068 log_operation(cmd, rc, pid, NULL, output);
2069
2070 cmd->active_on = NULL;
2071
2072 if(dev) {
2073 mainloop_set_trigger(dev->work);
2074 } else {
2075 crm_trace("Device %s does not exist", cmd->device);
2076 }
2077
2078 if(rc != 0) {
2079 crm_exit(DAEMON_RESPAWN_STOP);
2080 }
2081 }
2082
2083 static void
2084 cancel_stonith_command(async_command_t * cmd)
2085 {
2086 stonith_device_t *device;
2087
2088 CRM_CHECK(cmd != NULL, return);
2089
2090 if (!cmd->device) {
2091 return;
2092 }
2093
2094 device = g_hash_table_lookup(device_list, cmd->device);
2095
2096 if (device) {
2097 crm_trace("Cancel scheduled %s on %s", cmd->action, device->id);
2098 device->pending_ops = g_list_remove(device->pending_ops, cmd);
2099 }
2100 }
2101
2102 static void
2103 st_child_done(GPid pid, int rc, const char *output, gpointer user_data)
2104 {
2105 stonith_device_t *device = NULL;
2106 stonith_device_t *next_device = NULL;
2107 async_command_t *cmd = user_data;
2108
2109 GListPtr gIter = NULL;
2110 GListPtr gIterNext = NULL;
2111
2112 CRM_CHECK(cmd != NULL, return);
2113
2114 cmd->active_on = NULL;
2115
2116
2117 device = g_hash_table_lookup(device_list, cmd->device);
2118 if (device) {
2119 if (rc == pcmk_ok &&
2120 (safe_str_eq(cmd->action, "list") ||
2121 safe_str_eq(cmd->action, "monitor") || safe_str_eq(cmd->action, "status"))) {
2122
2123 device->verified = TRUE;
2124 }
2125
2126 mainloop_set_trigger(device->work);
2127 }
2128
2129 crm_debug("Operation '%s' on '%s' completed with rc=%d (%d remaining)",
2130 cmd->action, cmd->device, rc, g_list_length(cmd->device_next));
2131
2132 if (rc == 0) {
2133 GListPtr iter;
2134
2135 for (iter = cmd->device_next; iter != NULL; iter = iter->next) {
2136 next_device = g_hash_table_lookup(device_list, iter->data);
2137
2138 if (next_device != NULL && is_action_required(cmd->action, next_device)) {
2139 cmd->device_next = iter->next;
2140 break;
2141 }
2142 next_device = NULL;
2143 }
2144
2145 } else if (rc != 0 && cmd->device_next && (is_action_required(cmd->action, device) == FALSE)) {
2146
2147
2148 next_device = g_hash_table_lookup(device_list, cmd->device_next->data);
2149 cmd->device_next = cmd->device_next->next;
2150 }
2151
2152
2153 if (next_device) {
2154 log_operation(cmd, rc, pid, cmd->device, output);
2155
2156 schedule_stonith_command(cmd, next_device);
2157
2158 cmd = NULL;
2159 goto done;
2160 }
2161
2162 stonith_send_async_reply(cmd, output, rc, pid);
2163
2164 if (rc != 0) {
2165 goto done;
2166 }
2167
2168
2169
2170
2171
2172 for (gIter = cmd_list; gIter != NULL; gIter = gIterNext) {
2173 async_command_t *cmd_other = gIter->data;
2174
2175 gIterNext = gIter->next;
2176
2177 if (cmd == cmd_other) {
2178 continue;
2179 }
2180
2181
2182
2183
2184
2185
2186
2187 if (safe_str_eq(cmd->client, cmd_other->client) ||
2188 safe_str_neq(cmd->victim, cmd_other->victim) ||
2189 safe_str_neq(cmd->action, cmd_other->action) ||
2190 safe_str_neq(cmd->device, cmd_other->device)) {
2191
2192 continue;
2193 }
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203 crm_notice
2204 ("Merging stonith action %s for node %s originating from client %s with identical stonith request from client %s",
2205 cmd_other->action, cmd_other->victim, cmd_other->client_name, cmd->client_name);
2206
2207 cmd_list = g_list_remove_link(cmd_list, gIter);
2208
2209 stonith_send_async_reply(cmd_other, output, rc, pid);
2210 cancel_stonith_command(cmd_other);
2211
2212 free_async_command(cmd_other);
2213 g_list_free_1(gIter);
2214 }
2215
2216 done:
2217 free_async_command(cmd);
2218 }
2219
2220 static gint
2221 sort_device_priority(gconstpointer a, gconstpointer b)
2222 {
2223 const stonith_device_t *dev_a = a;
2224 const stonith_device_t *dev_b = b;
2225
2226 if (dev_a->priority > dev_b->priority) {
2227 return -1;
2228 } else if (dev_a->priority < dev_b->priority) {
2229 return 1;
2230 }
2231 return 0;
2232 }
2233
2234 static void
2235 stonith_fence_get_devices_cb(GList * devices, void *user_data)
2236 {
2237 async_command_t *cmd = user_data;
2238 stonith_device_t *device = NULL;
2239
2240 crm_info("Found %d matching devices for '%s'", g_list_length(devices), cmd->victim);
2241
2242 if (g_list_length(devices) > 0) {
2243
2244 devices = g_list_sort(devices, sort_device_priority);
2245 device = g_hash_table_lookup(device_list, devices->data);
2246
2247 if (device) {
2248 cmd->device_list = devices;
2249 cmd->device_next = devices->next;
2250 devices = NULL;
2251 }
2252 }
2253
2254
2255 if (device) {
2256 schedule_stonith_command(cmd, device);
2257
2258 return;
2259 }
2260
2261
2262 stonith_send_async_reply(cmd, NULL, -ENODEV, 0);
2263
2264 free_async_command(cmd);
2265 g_list_free_full(devices, free);
2266 }
2267
2268 static int
2269 stonith_fence(xmlNode * msg)
2270 {
2271 const char *device_id = NULL;
2272 stonith_device_t *device = NULL;
2273 async_command_t *cmd = create_async_command(msg);
2274 xmlNode *dev = get_xpath_object("//@" F_STONITH_TARGET, msg, LOG_ERR);
2275
2276 if (cmd == NULL) {
2277 return -EPROTO;
2278 }
2279
2280 device_id = crm_element_value(dev, F_STONITH_DEVICE);
2281 if (device_id) {
2282 device = g_hash_table_lookup(device_list, device_id);
2283 if (device == NULL) {
2284 crm_err("Requested device '%s' is not available", device_id);
2285 return -ENODEV;
2286 }
2287 schedule_stonith_command(cmd, device);
2288
2289 } else {
2290 const char *host = crm_element_value(dev, F_STONITH_TARGET);
2291 char *nodename = NULL;
2292
2293 if (cmd->options & st_opt_cs_nodeid) {
2294 int nodeid = crm_atoi(host, NULL);
2295
2296 nodename = stonith_get_peer_name(nodeid);
2297 if (nodename) {
2298 host = nodename;
2299 }
2300 }
2301
2302
2303 get_capable_devices(host, cmd->action, cmd->default_timeout,
2304 TRUE, cmd, stonith_fence_get_devices_cb);
2305
2306 free(nodename);
2307 }
2308
2309 return -EINPROGRESS;
2310 }
2311
2312 xmlNode *
2313 stonith_construct_reply(xmlNode * request, const char *output, xmlNode * data, int rc)
2314 {
2315 int lpc = 0;
2316 xmlNode *reply = NULL;
2317
2318 const char *name = NULL;
2319 const char *value = NULL;
2320
2321 const char *names[] = {
2322 F_STONITH_OPERATION,
2323 F_STONITH_CALLID,
2324 F_STONITH_CLIENTID,
2325 F_STONITH_CLIENTNAME,
2326 F_STONITH_REMOTE_OP_ID,
2327 F_STONITH_CALLOPTS
2328 };
2329
2330 crm_trace("Creating a basic reply");
2331 reply = create_xml_node(NULL, T_STONITH_REPLY);
2332
2333 crm_xml_add(reply, "st_origin", __FUNCTION__);
2334 crm_xml_add(reply, F_TYPE, T_STONITH_NG);
2335 crm_xml_add(reply, "st_output", output);
2336 crm_xml_add_int(reply, F_STONITH_RC, rc);
2337
2338 CRM_CHECK(request != NULL, crm_warn("Can't create a sane reply"); return reply);
2339 for (lpc = 0; lpc < DIMOF(names); lpc++) {
2340 name = names[lpc];
2341 value = crm_element_value(request, name);
2342 crm_xml_add(reply, name, value);
2343 }
2344
2345 if (data != NULL) {
2346 crm_trace("Attaching reply output");
2347 add_message_xml(reply, F_STONITH_CALLDATA, data);
2348 }
2349 return reply;
2350 }
2351
2352 static xmlNode *
2353 stonith_construct_async_reply(async_command_t * cmd, const char *output, xmlNode * data, int rc)
2354 {
2355 xmlNode *reply = NULL;
2356
2357 crm_trace("Creating a basic reply");
2358 reply = create_xml_node(NULL, T_STONITH_REPLY);
2359
2360 crm_xml_add(reply, "st_origin", __FUNCTION__);
2361 crm_xml_add(reply, F_TYPE, T_STONITH_NG);
2362
2363 crm_xml_add(reply, F_STONITH_OPERATION, cmd->op);
2364 crm_xml_add(reply, F_STONITH_DEVICE, cmd->device);
2365 crm_xml_add(reply, F_STONITH_REMOTE_OP_ID, cmd->remote_op_id);
2366 crm_xml_add(reply, F_STONITH_CLIENTID, cmd->client);
2367 crm_xml_add(reply, F_STONITH_CLIENTNAME, cmd->client_name);
2368 crm_xml_add(reply, F_STONITH_TARGET, cmd->victim);
2369 crm_xml_add(reply, F_STONITH_ACTION, cmd->op);
2370 crm_xml_add(reply, F_STONITH_ORIGIN, cmd->origin);
2371 crm_xml_add_int(reply, F_STONITH_CALLID, cmd->id);
2372 crm_xml_add_int(reply, F_STONITH_CALLOPTS, cmd->options);
2373
2374 crm_xml_add_int(reply, F_STONITH_RC, rc);
2375
2376 crm_xml_add(reply, "st_output", output);
2377
2378 if (data != NULL) {
2379 crm_info("Attaching reply output");
2380 add_message_xml(reply, F_STONITH_CALLDATA, data);
2381 }
2382 return reply;
2383 }
2384
2385 bool fencing_peer_active(crm_node_t *peer)
2386 {
2387 if (peer == NULL) {
2388 return FALSE;
2389 } else if (peer->uname == NULL) {
2390 return FALSE;
2391 } else if (is_set(peer->processes, crm_get_cluster_proc())) {
2392 return TRUE;
2393 }
2394 return FALSE;
2395 }
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405 static const char *
2406 check_alternate_host(const char *target)
2407 {
2408 const char *alternate_host = NULL;
2409
2410 crm_trace("Checking if we (%s) can fence %s", stonith_our_uname, target);
2411 if (find_topology_for_host(target) && safe_str_eq(target, stonith_our_uname)) {
2412 GHashTableIter gIter;
2413 crm_node_t *entry = NULL;
2414
2415 g_hash_table_iter_init(&gIter, crm_peer_cache);
2416 while (g_hash_table_iter_next(&gIter, NULL, (void **)&entry)) {
2417 crm_trace("Checking for %s.%d != %s", entry->uname, entry->id, target);
2418 if (fencing_peer_active(entry)
2419 && safe_str_neq(entry->uname, target)) {
2420 alternate_host = entry->uname;
2421 break;
2422 }
2423 }
2424 if (alternate_host == NULL) {
2425 crm_err("No alternate host available to handle complex self fencing request");
2426 g_hash_table_iter_init(&gIter, crm_peer_cache);
2427 while (g_hash_table_iter_next(&gIter, NULL, (void **)&entry)) {
2428 crm_notice("Peer[%d] %s", entry->id, entry->uname);
2429 }
2430 }
2431 }
2432
2433 return alternate_host;
2434 }
2435
2436 static void
2437 stonith_send_reply(xmlNode * reply, int call_options, const char *remote_peer,
2438 const char *client_id)
2439 {
2440 if (remote_peer) {
2441 send_cluster_message(crm_get_peer(0, remote_peer), crm_msg_stonith_ng, reply, FALSE);
2442 } else {
2443 do_local_reply(reply, client_id, is_set(call_options, st_opt_sync_call), remote_peer != NULL);
2444 }
2445 }
2446
2447 static int
2448 handle_request(crm_client_t * client, uint32_t id, uint32_t flags, xmlNode * request,
2449 const char *remote_peer)
2450 {
2451 int call_options = 0;
2452 int rc = -EOPNOTSUPP;
2453
2454 xmlNode *data = NULL;
2455 xmlNode *reply = NULL;
2456
2457 char *output = NULL;
2458 const char *op = crm_element_value(request, F_STONITH_OPERATION);
2459 const char *client_id = crm_element_value(request, F_STONITH_CLIENTID);
2460
2461 crm_element_value_int(request, F_STONITH_CALLOPTS, &call_options);
2462
2463 if (is_set(call_options, st_opt_sync_call)) {
2464 CRM_ASSERT(client == NULL || client->request_id == id);
2465 }
2466
2467 if (crm_str_eq(op, CRM_OP_REGISTER, TRUE)) {
2468 xmlNode *reply = create_xml_node(NULL, "reply");
2469
2470 CRM_ASSERT(client);
2471 crm_xml_add(reply, F_STONITH_OPERATION, CRM_OP_REGISTER);
2472 crm_xml_add(reply, F_STONITH_CLIENTID, client->id);
2473 crm_ipcs_send(client, id, reply, flags);
2474 client->request_id = 0;
2475 free_xml(reply);
2476 return 0;
2477
2478 } else if (crm_str_eq(op, STONITH_OP_EXEC, TRUE)) {
2479 rc = stonith_device_action(request, &output);
2480
2481 } else if (crm_str_eq(op, STONITH_OP_TIMEOUT_UPDATE, TRUE)) {
2482 const char *call_id = crm_element_value(request, F_STONITH_CALLID);
2483 const char *client_id = crm_element_value(request, F_STONITH_CLIENTID);
2484 int op_timeout = 0;
2485
2486 crm_element_value_int(request, F_STONITH_TIMEOUT, &op_timeout);
2487 do_stonith_async_timeout_update(client_id, call_id, op_timeout);
2488 return 0;
2489
2490 } else if (crm_str_eq(op, STONITH_OP_QUERY, TRUE)) {
2491 if (remote_peer) {
2492 create_remote_stonith_op(client_id, request, TRUE);
2493 }
2494 stonith_query(request, remote_peer, client_id, call_options);
2495 return 0;
2496
2497 } else if (crm_str_eq(op, T_STONITH_NOTIFY, TRUE)) {
2498 const char *flag_name = NULL;
2499
2500 CRM_ASSERT(client);
2501 flag_name = crm_element_value(request, F_STONITH_NOTIFY_ACTIVATE);
2502 if (flag_name) {
2503 crm_debug("Setting %s callbacks for %s (%s): ON", flag_name, client->name, client->id);
2504 client->options |= get_stonith_flag(flag_name);
2505 }
2506
2507 flag_name = crm_element_value(request, F_STONITH_NOTIFY_DEACTIVATE);
2508 if (flag_name) {
2509 crm_debug("Setting %s callbacks for %s (%s): off", flag_name, client->name, client->id);
2510 client->options |= get_stonith_flag(flag_name);
2511 }
2512
2513 if (flags & crm_ipc_client_response) {
2514 crm_ipcs_send_ack(client, id, flags, "ack", __FUNCTION__, __LINE__);
2515 }
2516 return 0;
2517
2518 } else if (crm_str_eq(op, STONITH_OP_RELAY, TRUE)) {
2519 xmlNode *dev = get_xpath_object("//@" F_STONITH_TARGET, request, LOG_TRACE);
2520
2521 crm_notice("Peer %s has received a forwarded fencing request from %s to fence (%s) peer %s",
2522 stonith_our_uname,
2523 client ? client->name : remote_peer,
2524 crm_element_value(dev, F_STONITH_ACTION),
2525 crm_element_value(dev, F_STONITH_TARGET));
2526
2527 if (initiate_remote_stonith_op(NULL, request, FALSE) != NULL) {
2528 rc = -EINPROGRESS;
2529 }
2530
2531 } else if (crm_str_eq(op, STONITH_OP_FENCE, TRUE)) {
2532
2533 if (remote_peer || stand_alone) {
2534 rc = stonith_fence(request);
2535
2536 } else if (call_options & st_opt_manual_ack) {
2537 remote_fencing_op_t *rop = NULL;
2538 xmlNode *dev = get_xpath_object("//@" F_STONITH_TARGET, request, LOG_TRACE);
2539 const char *target = crm_element_value(dev, F_STONITH_TARGET);
2540
2541 crm_notice("Received manual confirmation that %s is fenced", target);
2542 rop = initiate_remote_stonith_op(client, request, TRUE);
2543 rc = stonith_manual_ack(request, rop);
2544
2545 } else {
2546 const char *alternate_host = NULL;
2547 xmlNode *dev = get_xpath_object("//@" F_STONITH_TARGET, request, LOG_TRACE);
2548 const char *target = crm_element_value(dev, F_STONITH_TARGET);
2549 const char *action = crm_element_value(dev, F_STONITH_ACTION);
2550 const char *device = crm_element_value(dev, F_STONITH_DEVICE);
2551
2552 if (client) {
2553 int tolerance = 0;
2554
2555 crm_notice("Client %s.%.8s wants to fence (%s) '%s' with device '%s'",
2556 client->name, client->id, action, target, device ? device : "(any)");
2557
2558 crm_element_value_int(dev, F_STONITH_TOLERANCE, &tolerance);
2559
2560 if (stonith_check_fence_tolerance(tolerance, target, action)) {
2561 rc = 0;
2562 goto done;
2563 }
2564
2565 } else {
2566 crm_notice("Peer %s wants to fence (%s) '%s' with device '%s'",
2567 remote_peer, action, target, device ? device : "(any)");
2568 }
2569
2570 alternate_host = check_alternate_host(target);
2571
2572 if (alternate_host && client) {
2573 const char *client_id = NULL;
2574
2575 crm_notice("Forwarding complex self fencing request to peer %s", alternate_host);
2576
2577 if (client->id) {
2578 client_id = client->id;
2579 } else {
2580 client_id = crm_element_value(request, F_STONITH_CLIENTID);
2581 }
2582
2583
2584 create_remote_stonith_op(client_id, request, FALSE);
2585
2586 crm_xml_add(request, F_STONITH_OPERATION, STONITH_OP_RELAY);
2587 crm_xml_add(request, F_STONITH_CLIENTID, client->id);
2588 send_cluster_message(crm_get_peer(0, alternate_host), crm_msg_stonith_ng, request,
2589 FALSE);
2590 rc = -EINPROGRESS;
2591
2592 } else if (initiate_remote_stonith_op(client, request, FALSE) != NULL) {
2593 rc = -EINPROGRESS;
2594 }
2595 }
2596
2597 } else if (crm_str_eq(op, STONITH_OP_FENCE_HISTORY, TRUE)) {
2598 rc = stonith_fence_history(request, &data);
2599
2600 } else if (crm_str_eq(op, STONITH_OP_DEVICE_ADD, TRUE)) {
2601 const char *device_id = NULL;
2602
2603 rc = stonith_device_register(request, &device_id, FALSE);
2604 do_stonith_notify_device(call_options, op, rc, device_id);
2605
2606 } else if (crm_str_eq(op, STONITH_OP_DEVICE_DEL, TRUE)) {
2607 xmlNode *dev = get_xpath_object("//" F_STONITH_DEVICE, request, LOG_ERR);
2608 const char *device_id = crm_element_value(dev, XML_ATTR_ID);
2609
2610 rc = stonith_device_remove(device_id, FALSE);
2611 do_stonith_notify_device(call_options, op, rc, device_id);
2612
2613 } else if (crm_str_eq(op, STONITH_OP_LEVEL_ADD, TRUE)) {
2614 char *device_id = NULL;
2615
2616 rc = stonith_level_register(request, &device_id);
2617 do_stonith_notify_level(call_options, op, rc, device_id);
2618 free(device_id);
2619
2620 } else if (crm_str_eq(op, STONITH_OP_LEVEL_DEL, TRUE)) {
2621 char *device_id = NULL;
2622
2623 rc = stonith_level_remove(request, &device_id);
2624 do_stonith_notify_level(call_options, op, rc, device_id);
2625
2626 } else if (crm_str_eq(op, STONITH_OP_CONFIRM, TRUE)) {
2627 async_command_t *cmd = create_async_command(request);
2628 xmlNode *reply = stonith_construct_async_reply(cmd, NULL, NULL, 0);
2629
2630 crm_xml_add(reply, F_STONITH_OPERATION, T_STONITH_NOTIFY);
2631 crm_notice("Broadcasting manual fencing confirmation for node %s", cmd->victim);
2632 send_cluster_message(NULL, crm_msg_stonith_ng, reply, FALSE);
2633
2634 free_async_command(cmd);
2635 free_xml(reply);
2636
2637 } else if(safe_str_eq(op, CRM_OP_RM_NODE_CACHE)) {
2638 int node_id = 0;
2639 const char *name = NULL;
2640
2641 crm_element_value_int(request, XML_ATTR_ID, &node_id);
2642 name = crm_element_value(request, XML_ATTR_UNAME);
2643 reap_crm_member(node_id, name);
2644
2645 return pcmk_ok;
2646
2647 } else {
2648 crm_err("Unknown %s from %s", op, client ? client->name : remote_peer);
2649 crm_log_xml_warn(request, "UnknownOp");
2650 }
2651
2652 done:
2653
2654
2655
2656
2657 if (rc != -EINPROGRESS) {
2658 crm_trace("Reply handling: %p %u %u %d %d %s", client, client?client->request_id:0,
2659 id, is_set(call_options, st_opt_sync_call), call_options,
2660 crm_element_value(request, F_STONITH_CALLOPTS));
2661
2662 if (is_set(call_options, st_opt_sync_call)) {
2663 CRM_ASSERT(client == NULL || client->request_id == id);
2664 }
2665 reply = stonith_construct_reply(request, output, data, rc);
2666 stonith_send_reply(reply, call_options, remote_peer, client_id);
2667 }
2668
2669 free(output);
2670 free_xml(data);
2671 free_xml(reply);
2672
2673 return rc;
2674 }
2675
2676 static void
2677 handle_reply(crm_client_t * client, xmlNode * request, const char *remote_peer)
2678 {
2679 const char *op = crm_element_value(request, F_STONITH_OPERATION);
2680
2681 if (crm_str_eq(op, STONITH_OP_QUERY, TRUE)) {
2682 process_remote_stonith_query(request);
2683 } else if (crm_str_eq(op, T_STONITH_NOTIFY, TRUE)) {
2684 process_remote_stonith_exec(request);
2685 } else if (crm_str_eq(op, STONITH_OP_FENCE, TRUE)) {
2686
2687 process_remote_stonith_exec(request);
2688 } else {
2689 crm_err("Unknown %s reply from %s", op, client ? client->name : remote_peer);
2690 crm_log_xml_warn(request, "UnknownOp");
2691 }
2692 }
2693
2694 void
2695 stonith_command(crm_client_t * client, uint32_t id, uint32_t flags, xmlNode * request,
2696 const char *remote_peer)
2697 {
2698 int call_options = 0;
2699 int rc = 0;
2700 gboolean is_reply = FALSE;
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711 char *op = crm_element_value_copy(request, F_STONITH_OPERATION);
2712
2713 if (get_xpath_object("//" T_STONITH_REPLY, request, LOG_DEBUG_3)) {
2714 is_reply = TRUE;
2715 }
2716
2717 crm_element_value_int(request, F_STONITH_CALLOPTS, &call_options);
2718 crm_debug("Processing %s%s %u from %s (%16x)", op, is_reply ? " reply" : "",
2719 id, client ? client->name : remote_peer, call_options);
2720
2721 if (is_set(call_options, st_opt_sync_call)) {
2722 CRM_ASSERT(client == NULL || client->request_id == id);
2723 }
2724
2725 if (is_reply) {
2726 handle_reply(client, request, remote_peer);
2727 } else {
2728 rc = handle_request(client, id, flags, request, remote_peer);
2729 }
2730
2731 crm_debug("Processed %s%s from %s: %s (%d)", op,
2732 is_reply ? " reply" : "", client ? client->name : remote_peer,
2733 rc > 0 ? "" : pcmk_strerror(rc), rc);
2734
2735 free(op);
2736 }