pacemaker 2.1.4-dc6eb4362e
Scalable High-Availability cluster resource manager
st_client.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2022 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 Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <stdbool.h>
15#include <string.h>
16#include <ctype.h>
17#include <inttypes.h>
18#include <sys/types.h>
19#include <glib.h>
20
21#include <crm/crm.h>
22#include <crm/stonith-ng.h>
24#include <crm/msg_xml.h>
25
26#include <crm/common/mainloop.h>
27
28#include "fencing_private.h"
29
31
32// Used as stonith_t:st_private
33typedef struct stonith_private_s {
34 char *token;
35 crm_ipc_t *ipc;
36 mainloop_io_t *source;
37 GHashTable *stonith_op_callback_table;
38 GList *notify_list;
39 int notify_refcnt;
40 bool notify_deletes;
41
42 void (*op_callback) (stonith_t * st, stonith_callback_data_t * data);
43
45
46// Used as stonith_event_t:opaque
47struct event_private {
49};
50
51typedef struct stonith_notify_client_s {
52 const char *event;
53 const char *obj_id; /* implement one day */
54 const char *obj_type; /* implement one day */
55 void (*notify) (stonith_t * st, stonith_event_t * e);
56 bool delete;
57
59
60typedef struct stonith_callback_client_s {
61 void (*callback) (stonith_t * st, stonith_callback_data_t * data);
62 const char *id;
63 void *user_data;
64 gboolean only_success;
65 gboolean allow_timeout_updates;
66 struct timer_rec_s *timer;
67
69
70struct notify_blob_s {
71 stonith_t *stonith;
72 xmlNode *xml;
73};
74
75struct timer_rec_s {
76 int call_id;
77 int timeout;
78 guint ref;
80};
81
82typedef int (*stonith_op_t) (const char *, int, const char *, xmlNode *,
83 xmlNode *, xmlNode *, xmlNode **, xmlNode **);
84
86xmlNode *stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data,
87 int call_options);
88static int stonith_send_command(stonith_t *stonith, const char *op,
89 xmlNode *data, xmlNode **output_data,
90 int call_options, int timeout);
91
92static void stonith_connection_destroy(gpointer user_data);
93static void stonith_send_notification(gpointer data, gpointer user_data);
94static int stonith_api_del_notification(stonith_t *stonith,
95 const char *event);
104stonith_text2namespace(const char *namespace_s)
105{
106 if (pcmk__str_eq(namespace_s, "any", pcmk__str_null_matches)) {
107 return st_namespace_any;
108
109 } else if (!strcmp(namespace_s, "redhat")
110 || !strcmp(namespace_s, "stonith-ng")) {
111 return st_namespace_rhcs;
112
113 } else if (!strcmp(namespace_s, "internal")) {
115
116 } else if (!strcmp(namespace_s, "heartbeat")) {
117 return st_namespace_lha;
118 }
120}
121
129const char *
131{
132 switch (st_namespace) {
133 case st_namespace_any: return "any";
134 case st_namespace_rhcs: return "stonith-ng";
135 case st_namespace_internal: return "internal";
136 case st_namespace_lha: return "heartbeat";
137 default: break;
138 }
139 return "unsupported";
140}
141
151stonith_get_namespace(const char *agent, const char *namespace_s)
152{
153 if (pcmk__str_eq(namespace_s, "internal", pcmk__str_casei)) {
155 }
156
157 if (stonith__agent_is_rhcs(agent)) {
158 return st_namespace_rhcs;
159 }
160
161#if HAVE_STONITH_STONITH_H
162 if (stonith__agent_is_lha(agent)) {
163 return st_namespace_lha;
164 }
165#endif
166
167 crm_err("Unknown fence agent: %s", agent);
169}
170
171gboolean
173{
174 gboolean rv = FALSE;
175 stonith_t *stonith_api = st?st:stonith_api_new();
176 char *list = NULL;
177
178 if(stonith_api) {
179 if (stonith_api->state == stonith_disconnected) {
180 int rc = stonith_api->cmds->connect(stonith_api, "stonith-api", NULL);
181
182 if (rc != pcmk_ok) {
183 crm_err("Failed connecting to Stonith-API for watchdog-fencing-query.");
184 }
185 }
186
187 if (stonith_api->state != stonith_disconnected) {
188 /* caveat!!!
189 * this might fail when when stonithd is just updating the device-list
190 * probably something we should fix as well for other api-calls */
191 int rc = stonith_api->cmds->list(stonith_api, st_opt_sync_call, STONITH_WATCHDOG_ID, &list, 0);
192 if ((rc != pcmk_ok) || (list == NULL)) {
193 /* due to the race described above it can happen that
194 * we drop in here - so as not to make remote nodes
195 * panic on that answer
196 */
197 if (rc == -ENODEV) {
198 crm_notice("Cluster does not have watchdog fencing device");
199 } else {
200 crm_warn("Could not check for watchdog fencing device: %s",
201 pcmk_strerror(rc));
202 }
203 } else if (list[0] == '\0') {
204 rv = TRUE;
205 } else {
206 GList *targets = stonith__parse_targets(list);
207 rv = pcmk__str_in_list(node, targets, pcmk__str_casei);
208 g_list_free_full(targets, free);
209 }
210 free(list);
211 if (!st) {
212 /* if we're provided the api we still might have done the
213 * connection - but let's assume the caller won't bother
214 */
215 stonith_api->cmds->disconnect(stonith_api);
216 }
217 }
218
219 if (!st) {
220 stonith_api_delete(stonith_api);
221 }
222 } else {
223 crm_err("Stonith-API for watchdog-fencing-query couldn't be created.");
224 }
225 crm_trace("Pacemaker assumes node %s %sto do watchdog-fencing.",
226 node, rv?"":"not ");
227 return rv;
228}
229
230gboolean
232{
234}
235
236/* when cycling through the list we don't want to delete items
237 so just mark them and when we know nobody is using the list
238 loop over it to remove the marked items
239 */
240static void
241foreach_notify_entry (stonith_private_t *private,
242 GFunc func,
243 gpointer user_data)
244{
245 private->notify_refcnt++;
246 g_list_foreach(private->notify_list, func, user_data);
247 private->notify_refcnt--;
248 if ((private->notify_refcnt == 0) &&
249 private->notify_deletes) {
250 GList *list_item = private->notify_list;
251
252 private->notify_deletes = FALSE;
253 while (list_item != NULL)
254 {
255 stonith_notify_client_t *list_client = list_item->data;
256 GList *next = g_list_next(list_item);
257
258 if (list_client->delete) {
259 free(list_client);
260 private->notify_list =
261 g_list_delete_link(private->notify_list, list_item);
262 }
263 list_item = next;
264 }
265 }
266}
267
268static void
269stonith_connection_destroy(gpointer user_data)
270{
271 stonith_t *stonith = user_data;
272 stonith_private_t *native = NULL;
273 struct notify_blob_s blob;
274
275 crm_trace("Sending destroyed notification");
276 blob.stonith = stonith;
277 blob.xml = create_xml_node(NULL, "notify");
278
279 native = stonith->st_private;
280 native->ipc = NULL;
281 native->source = NULL;
282
283 free(native->token); native->token = NULL;
284 stonith->state = stonith_disconnected;
287
288 foreach_notify_entry(native, stonith_send_notification, &blob);
289 free_xml(blob.xml);
290}
291
292xmlNode *
294 const char *agent, stonith_key_value_t *params,
295 const char *rsc_provides)
296{
297 xmlNode *data = create_xml_node(NULL, F_STONITH_DEVICE);
298 xmlNode *args = create_xml_node(data, XML_TAG_ATTRS);
299
300#if HAVE_STONITH_STONITH_H
301 if (namespace == st_namespace_any) {
302 namespace = stonith_get_namespace(agent, NULL);
303 }
304 if (namespace == st_namespace_lha) {
305 hash2field((gpointer) "plugin", (gpointer) agent, args);
306 agent = "fence_legacy";
307 }
308#endif
309
312 crm_xml_add(data, "agent", agent);
313 if ((namespace != st_namespace_any) && (namespace != st_namespace_invalid)) {
314 crm_xml_add(data, "namespace", stonith_namespace2text(namespace));
315 }
316 if (rsc_provides) {
317 crm_xml_add(data, "rsc_provides", rsc_provides);
318 }
319
320 for (; params; params = params->next) {
321 hash2field((gpointer) params->key, (gpointer) params->value, args);
322 }
323
324 return data;
325}
326
327static int
328stonith_api_register_device(stonith_t * st, int call_options,
329 const char *id, const char *namespace, const char *agent,
330 stonith_key_value_t * params)
331{
332 int rc = 0;
333 xmlNode *data = NULL;
334
336 agent, params, NULL);
337
338 rc = stonith_send_command(st, STONITH_OP_DEVICE_ADD, data, NULL, call_options, 0);
339 free_xml(data);
340
341 return rc;
342}
343
344static int
345stonith_api_remove_device(stonith_t * st, int call_options, const char *name)
346{
347 int rc = 0;
348 xmlNode *data = NULL;
349
353 rc = stonith_send_command(st, STONITH_OP_DEVICE_DEL, data, NULL, call_options, 0);
354 free_xml(data);
355
356 return rc;
357}
358
359static int
360stonith_api_remove_level_full(stonith_t *st, int options,
361 const char *node, const char *pattern,
362 const char *attr, const char *value, int level)
363{
364 int rc = 0;
365 xmlNode *data = NULL;
366
367 CRM_CHECK(node || pattern || (attr && value), return -EINVAL);
368
371
372 if (node) {
374
375 } else if (pattern) {
377
378 } else {
381 }
382
384 rc = stonith_send_command(st, STONITH_OP_LEVEL_DEL, data, NULL, options, 0);
385 free_xml(data);
386
387 return rc;
388}
389
390static int
391stonith_api_remove_level(stonith_t * st, int options, const char *node, int level)
392{
393 return stonith_api_remove_level_full(st, options, node,
394 NULL, NULL, NULL, level);
395}
396
412xmlNode *
413create_level_registration_xml(const char *node, const char *pattern,
414 const char *attr, const char *value,
415 int level, stonith_key_value_t *device_list)
416{
417 size_t len = 0;
418 char *list = NULL;
419 xmlNode *data;
420
421 CRM_CHECK(node || pattern || (attr && value), return NULL);
422
424 CRM_CHECK(data, return NULL);
425
429
430 if (node) {
432
433 } else if (pattern) {
435
436 } else {
439 }
440
441 // cppcheck seems not to understand the abort logic behind pcmk__realloc
442 // cppcheck-suppress memleak
443 for (; device_list; device_list = device_list->next) {
444 pcmk__add_separated_word(&list, &len, device_list->value, ",");
445 }
446
448
449 free(list);
450 return data;
451}
452
453static int
454stonith_api_register_level_full(stonith_t * st, int options, const char *node,
455 const char *pattern,
456 const char *attr, const char *value,
457 int level, stonith_key_value_t *device_list)
458{
459 int rc = 0;
460 xmlNode *data = create_level_registration_xml(node, pattern, attr, value,
461 level, device_list);
462 CRM_CHECK(data != NULL, return -EINVAL);
463
464 rc = stonith_send_command(st, STONITH_OP_LEVEL_ADD, data, NULL, options, 0);
465 free_xml(data);
466
467 return rc;
468}
469
470static int
471stonith_api_register_level(stonith_t * st, int options, const char *node, int level,
472 stonith_key_value_t * device_list)
473{
474 return stonith_api_register_level_full(st, options, node, NULL, NULL, NULL,
475 level, device_list);
476}
477
478static int
479stonith_api_device_list(stonith_t * stonith, int call_options, const char *namespace,
480 stonith_key_value_t ** devices, int timeout)
481{
482 int count = 0;
483 enum stonith_namespace ns = stonith_text2namespace(namespace);
484
485 if (devices == NULL) {
486 crm_err("Parameter error: stonith_api_device_list");
487 return -EFAULT;
488 }
489
490#if HAVE_STONITH_STONITH_H
491 // Include Linux-HA agents if requested
492 if ((ns == st_namespace_any) || (ns == st_namespace_lha)) {
493 count += stonith__list_lha_agents(devices);
494 }
495#endif
496
497 // Include Red Hat agents if requested
498 if ((ns == st_namespace_any) || (ns == st_namespace_rhcs)) {
499 count += stonith__list_rhcs_agents(devices);
500 }
501
502 return count;
503}
504
505static int
506stonith_api_device_metadata(stonith_t * stonith, int call_options, const char *agent,
507 const char *namespace, char **output, int timeout)
508{
509 /* By executing meta-data directly, we can get it from stonith_admin when
510 * the cluster is not running, which is important for higher-level tools.
511 */
512
513 enum stonith_namespace ns = stonith_get_namespace(agent, namespace);
514
515 crm_trace("Looking up metadata for %s agent %s",
516 stonith_namespace2text(ns), agent);
517
518 switch (ns) {
520 return stonith__rhcs_metadata(agent, timeout, output);
521
522#if HAVE_STONITH_STONITH_H
523 case st_namespace_lha:
524 return stonith__lha_metadata(agent, timeout, output);
525#endif
526
527 default:
528 crm_err("Can't get fence agent '%s' meta-data: No such agent",
529 agent);
530 break;
531 }
532 return -ENODEV;
533}
534
535static int
536stonith_api_query(stonith_t * stonith, int call_options, const char *target,
537 stonith_key_value_t ** devices, int timeout)
538{
539 int rc = 0, lpc = 0, max = 0;
540
541 xmlNode *data = NULL;
542 xmlNode *output = NULL;
543 xmlXPathObjectPtr xpathObj = NULL;
544
545 CRM_CHECK(devices != NULL, return -EINVAL);
546
551 rc = stonith_send_command(stonith, STONITH_OP_QUERY, data, &output, call_options, timeout);
552
553 if (rc < 0) {
554 return rc;
555 }
556
557 xpathObj = xpath_search(output, "//@agent");
558 if (xpathObj) {
559 max = numXpathResults(xpathObj);
560
561 for (lpc = 0; lpc < max; lpc++) {
562 xmlNode *match = getXpathResult(xpathObj, lpc);
563
564 CRM_LOG_ASSERT(match != NULL);
565 if(match != NULL) {
566 xmlChar *match_path = xmlGetNodePath(match);
567
568 crm_info("%s[%d] = %s", "//@agent", lpc, match_path);
569 free(match_path);
570 *devices = stonith_key_value_add(*devices, NULL, crm_element_value(match, XML_ATTR_ID));
571 }
572 }
573
574 freeXpathObject(xpathObj);
575 }
576
577 free_xml(output);
578 free_xml(data);
579 return max;
580}
581
582static int
583stonith_api_call(stonith_t * stonith,
584 int call_options,
585 const char *id,
586 const char *action, const char *victim, int timeout, xmlNode ** output)
587{
588 int rc = 0;
589 xmlNode *data = NULL;
590
596
597 rc = stonith_send_command(stonith, STONITH_OP_EXEC, data, output, call_options, timeout);
598 free_xml(data);
599
600 return rc;
601}
602
603static int
604stonith_api_list(stonith_t * stonith, int call_options, const char *id, char **list_info,
605 int timeout)
606{
607 int rc;
608 xmlNode *output = NULL;
609
610 rc = stonith_api_call(stonith, call_options, id, "list", NULL, timeout, &output);
611
612 if (output && list_info) {
613 const char *list_str;
614
615 list_str = crm_element_value(output, F_STONITH_OUTPUT);
616
617 if (list_str) {
618 *list_info = strdup(list_str);
619 }
620 }
621
622 if (output) {
623 free_xml(output);
624 }
625
626 return rc;
627}
628
629static int
630stonith_api_monitor(stonith_t * stonith, int call_options, const char *id, int timeout)
631{
632 return stonith_api_call(stonith, call_options, id, "monitor", NULL, timeout, NULL);
633}
634
635static int
636stonith_api_status(stonith_t * stonith, int call_options, const char *id, const char *port,
637 int timeout)
638{
639 return stonith_api_call(stonith, call_options, id, "status", port, timeout, NULL);
640}
641
642static int
643stonith_api_fence_with_delay(stonith_t * stonith, int call_options, const char *node,
644 const char *action, int timeout, int tolerance, int delay)
645{
646 int rc = 0;
647 xmlNode *data = NULL;
648
649 data = create_xml_node(NULL, __func__);
655
656 rc = stonith_send_command(stonith, STONITH_OP_FENCE, data, NULL, call_options, timeout);
657 free_xml(data);
658
659 return rc;
660}
661
662static int
663stonith_api_fence(stonith_t * stonith, int call_options, const char *node, const char *action,
664 int timeout, int tolerance)
665{
666 return stonith_api_fence_with_delay(stonith, call_options, node, action,
667 timeout, tolerance, 0);
668}
669
670static int
671stonith_api_confirm(stonith_t * stonith, int call_options, const char *target)
672{
674 return stonith_api_fence(stonith, call_options, target, "off", 0, 0);
675}
676
677static int
678stonith_api_history(stonith_t * stonith, int call_options, const char *node,
679 stonith_history_t ** history, int timeout)
680{
681 int rc = 0;
682 xmlNode *data = NULL;
683 xmlNode *output = NULL;
684 stonith_history_t *last = NULL;
685
686 *history = NULL;
687
688 if (node) {
689 data = create_xml_node(NULL, __func__);
691 }
692
693 stonith__set_call_options(call_options, node, st_opt_sync_call);
694 rc = stonith_send_command(stonith, STONITH_OP_FENCE_HISTORY, data, &output,
695 call_options, timeout);
696 free_xml(data);
697
698 if (rc == 0) {
699 xmlNode *op = NULL;
700 xmlNode *reply = get_xpath_object("//" F_STONITH_HISTORY_LIST, output,
701 LOG_NEVER);
702
703 for (op = pcmk__xml_first_child(reply); op != NULL;
704 op = pcmk__xml_next(op)) {
706 long long completed;
707 long long completed_nsec = 0L;
708
709 kvp = calloc(1, sizeof(stonith_history_t));
715 crm_element_value_ll(op, F_STONITH_DATE, &completed);
716 kvp->completed = (time_t) completed;
717 crm_element_value_ll(op, F_STONITH_DATE_NSEC, &completed_nsec);
718 kvp->completed_nsec = completed_nsec;
722
723 if (last) {
724 last->next = kvp;
725 } else {
726 *history = kvp;
727 }
728 last = kvp;
729 }
730 }
731
732 free_xml(output);
733
734 return rc;
735}
736
738{
739 stonith_history_t *hp, *hp_old;
740
741 for (hp = history; hp; hp_old = hp, hp = hp->next, free(hp_old)) {
742 free(hp->target);
743 free(hp->action);
744 free(hp->origin);
745 free(hp->delegate);
746 free(hp->client);
747 free(hp->exit_reason);
748 }
749}
750
751static gint
752stonithlib_GCompareFunc(gconstpointer a, gconstpointer b)
753{
754 int rc = 0;
755 const stonith_notify_client_t *a_client = a;
756 const stonith_notify_client_t *b_client = b;
757
758 if (a_client->delete || b_client->delete) {
759 /* make entries marked for deletion not findable */
760 return -1;
761 }
762 CRM_CHECK(a_client->event != NULL && b_client->event != NULL, return 0);
763 rc = strcmp(a_client->event, b_client->event);
764 if (rc == 0) {
765 if (a_client->notify == NULL || b_client->notify == NULL) {
766 return 0;
767
768 } else if (a_client->notify == b_client->notify) {
769 return 0;
770
771 } else if (((long)a_client->notify) < ((long)b_client->notify)) {
772 crm_err("callbacks for %s are not equal: %p vs. %p",
773 a_client->event, a_client->notify, b_client->notify);
774 return -1;
775 }
776 crm_err("callbacks for %s are not equal: %p vs. %p",
777 a_client->event, a_client->notify, b_client->notify);
778 return 1;
779 }
780 return rc;
781}
782
783xmlNode *
784stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data, int call_options)
785{
786 xmlNode *op_msg = create_xml_node(NULL, "stonith_command");
787
788 CRM_CHECK(op_msg != NULL, return NULL);
789 CRM_CHECK(token != NULL, return NULL);
790
791 crm_xml_add(op_msg, F_XML_TAGNAME, "stonith_command");
792
795 crm_xml_add(op_msg, F_STONITH_OPERATION, op);
796 crm_xml_add_int(op_msg, F_STONITH_CALLID, call_id);
797 crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
798 crm_xml_add_int(op_msg, F_STONITH_CALLOPTS, call_options);
799
800 if (data != NULL) {
802 }
803
804 return op_msg;
805}
806
807static void
808stonith_destroy_op_callback(gpointer data)
809{
811
812 if (blob->timer && blob->timer->ref > 0) {
813 g_source_remove(blob->timer->ref);
814 }
815 free(blob->timer);
816 free(blob);
817}
818
819static int
820stonith_api_signoff(stonith_t * stonith)
821{
822 stonith_private_t *native = stonith->st_private;
823
824 crm_debug("Disconnecting from the fencer");
825
826 if (native->source != NULL) {
827 /* Attached to mainloop */
828 mainloop_del_ipc_client(native->source);
829 native->source = NULL;
830 native->ipc = NULL;
831
832 } else if (native->ipc) {
833 /* Not attached to mainloop */
834 crm_ipc_t *ipc = native->ipc;
835
836 native->ipc = NULL;
837 crm_ipc_close(ipc);
838 crm_ipc_destroy(ipc);
839 }
840
841 free(native->token); native->token = NULL;
842 stonith->state = stonith_disconnected;
843 return pcmk_ok;
844}
845
846static int
847stonith_api_del_callback(stonith_t * stonith, int call_id, bool all_callbacks)
848{
849 stonith_private_t *private = stonith->st_private;
850
851 if (all_callbacks) {
852 private->op_callback = NULL;
853 g_hash_table_destroy(private->stonith_op_callback_table);
854 private->stonith_op_callback_table = pcmk__intkey_table(stonith_destroy_op_callback);
855
856 } else if (call_id == 0) {
857 private->op_callback = NULL;
858
859 } else {
860 pcmk__intkey_table_remove(private->stonith_op_callback_table, call_id);
861 }
862 return pcmk_ok;
863}
864
876static void
877invoke_fence_action_callback(stonith_t *st, int call_id,
879 void *userdata,
880 void (*callback) (stonith_t *st,
882{
884
885 data.call_id = call_id;
887 data.userdata = userdata;
888 data.opaque = (void *) result;
889
890 callback(st, &data);
891}
892
904static void
905invoke_registered_callbacks(stonith_t *stonith, xmlNode *msg, int call_id)
906{
907 stonith_private_t *private = NULL;
908 stonith_callback_client_t *cb_info = NULL;
910
911 CRM_CHECK(stonith != NULL, return);
912 CRM_CHECK(stonith->st_private != NULL, return);
913
914 private = stonith->st_private;
915
916 if (msg == NULL) {
917 // Fencer didn't reply in time
919 "Fencer accepted request but did not reply in time");
920 CRM_LOG_ASSERT(call_id > 0);
921
922 } else {
923 // We have the fencer reply
924 if ((crm_element_value_int(msg, F_STONITH_CALLID, &call_id) != 0)
925 || (call_id <= 0)) {
926 crm_log_xml_warn(msg, "Bad fencer reply");
927 }
929 }
930
931 if (call_id > 0) {
932 cb_info = pcmk__intkey_table_lookup(private->stonith_op_callback_table,
933 call_id);
934 }
935
936 if ((cb_info != NULL) && (cb_info->callback != NULL)
937 && (pcmk__result_ok(&result) || !(cb_info->only_success))) {
938 crm_trace("Invoking callback %s for call %d",
939 crm_str(cb_info->id), call_id);
940 invoke_fence_action_callback(stonith, call_id, &result,
941 cb_info->user_data, cb_info->callback);
942
943 } else if ((private->op_callback == NULL) && !pcmk__result_ok(&result)) {
944 crm_warn("Fencing action without registered callback failed: %d (%s%s%s)",
946 pcmk_exec_status_str(result.execution_status),
947 ((result.exit_reason == NULL)? "" : ": "),
948 ((result.exit_reason == NULL)? "" : result.exit_reason));
949 crm_log_xml_debug(msg, "Failed fence update");
950 }
951
952 if (private->op_callback != NULL) {
953 crm_trace("Invoking global callback for call %d", call_id);
954 invoke_fence_action_callback(stonith, call_id, &result, NULL,
955 private->op_callback);
956 }
957
958 if (cb_info != NULL) {
959 stonith_api_del_callback(stonith, call_id, FALSE);
960 }
962}
963
964static gboolean
965stonith_async_timeout_handler(gpointer data)
966{
967 struct timer_rec_s *timer = data;
968
969 crm_err("Async call %d timed out after %dms", timer->call_id, timer->timeout);
970 invoke_registered_callbacks(timer->stonith, NULL, timer->call_id);
971
972 /* Always return TRUE, never remove the handler
973 * We do that in stonith_del_callback()
974 */
975 return TRUE;
976}
977
978static void
979set_callback_timeout(stonith_callback_client_t * callback, stonith_t * stonith, int call_id,
980 int timeout)
981{
982 struct timer_rec_s *async_timer = callback->timer;
983
984 if (timeout <= 0) {
985 return;
986 }
987
988 if (!async_timer) {
989 async_timer = calloc(1, sizeof(struct timer_rec_s));
990 callback->timer = async_timer;
991 }
992
993 async_timer->stonith = stonith;
994 async_timer->call_id = call_id;
995 /* Allow a fair bit of grace to allow the server to tell us of a timeout
996 * This is only a fallback
997 */
998 async_timer->timeout = (timeout + 60) * 1000;
999 if (async_timer->ref) {
1000 g_source_remove(async_timer->ref);
1001 }
1002 async_timer->ref =
1003 g_timeout_add(async_timer->timeout, stonith_async_timeout_handler, async_timer);
1004}
1005
1006static void
1007update_callback_timeout(int call_id, int timeout, stonith_t * st)
1008{
1009 stonith_callback_client_t *callback = NULL;
1010 stonith_private_t *private = st->st_private;
1011
1012 callback = pcmk__intkey_table_lookup(private->stonith_op_callback_table,
1013 call_id);
1014 if (!callback || !callback->allow_timeout_updates) {
1015 return;
1016 }
1017
1018 set_callback_timeout(callback, st, call_id, timeout);
1019}
1020
1021static int
1022stonith_dispatch_internal(const char *buffer, ssize_t length, gpointer userdata)
1023{
1024 const char *type = NULL;
1025 struct notify_blob_s blob;
1026
1027 stonith_t *st = userdata;
1028 stonith_private_t *private = NULL;
1029
1030 CRM_ASSERT(st != NULL);
1031 private = st->st_private;
1032
1033 blob.stonith = st;
1034 blob.xml = string2xml(buffer);
1035 if (blob.xml == NULL) {
1036 crm_warn("Received malformed message from fencer: %s", buffer);
1037 return 0;
1038 }
1039
1040 /* do callbacks */
1041 type = crm_element_value(blob.xml, F_TYPE);
1042 crm_trace("Activating %s callbacks...", type);
1043
1044 if (pcmk__str_eq(type, T_STONITH_NG, pcmk__str_casei)) {
1045 invoke_registered_callbacks(st, blob.xml, 0);
1046
1047 } else if (pcmk__str_eq(type, T_STONITH_NOTIFY, pcmk__str_casei)) {
1048 foreach_notify_entry(private, stonith_send_notification, &blob);
1049 } else if (pcmk__str_eq(type, T_STONITH_TIMEOUT_VALUE, pcmk__str_casei)) {
1050 int call_id = 0;
1051 int timeout = 0;
1052
1054 crm_element_value_int(blob.xml, F_STONITH_CALLID, &call_id);
1055
1056 update_callback_timeout(call_id, timeout, st);
1057 } else {
1058 crm_err("Unknown message type: %s", type);
1059 crm_log_xml_warn(blob.xml, "BadReply");
1060 }
1061
1062 free_xml(blob.xml);
1063 return 1;
1064}
1065
1066static int
1067stonith_api_signon(stonith_t * stonith, const char *name, int *stonith_fd)
1068{
1069 int rc = pcmk_ok;
1070 stonith_private_t *native = NULL;
1071 const char *display_name = name? name : "client";
1072
1073 struct ipc_client_callbacks st_callbacks = {
1074 .dispatch = stonith_dispatch_internal,
1075 .destroy = stonith_connection_destroy
1076 };
1077
1078 CRM_CHECK(stonith != NULL, return -EINVAL);
1079
1080 native = stonith->st_private;
1081 CRM_ASSERT(native != NULL);
1082
1083 crm_debug("Attempting fencer connection by %s with%s mainloop",
1084 display_name, (stonith_fd? "out" : ""));
1085
1087 if (stonith_fd) {
1088 /* No mainloop */
1089 native->ipc = crm_ipc_new("stonith-ng", 0);
1090
1091 if (native->ipc && crm_ipc_connect(native->ipc)) {
1092 *stonith_fd = crm_ipc_get_fd(native->ipc);
1093 } else if (native->ipc) {
1094 crm_ipc_close(native->ipc);
1095 crm_ipc_destroy(native->ipc);
1096 native->ipc = NULL;
1097 }
1098
1099 } else {
1100 /* With mainloop */
1101 native->source =
1102 mainloop_add_ipc_client("stonith-ng", G_PRIORITY_MEDIUM, 0, stonith, &st_callbacks);
1103 native->ipc = mainloop_get_ipc_client(native->source);
1104 }
1105
1106 if (native->ipc == NULL) {
1107 rc = -ENOTCONN;
1108 } else {
1109 xmlNode *reply = NULL;
1110 xmlNode *hello = create_xml_node(NULL, "stonith_command");
1111
1115 rc = crm_ipc_send(native->ipc, hello, crm_ipc_client_response, -1, &reply);
1116
1117 if (rc < 0) {
1118 crm_debug("Couldn't register with the fencer: %s "
1119 CRM_XS " rc=%d", pcmk_strerror(rc), rc);
1120 rc = -ECOMM;
1121
1122 } else if (reply == NULL) {
1123 crm_debug("Couldn't register with the fencer: no reply");
1124 rc = -EPROTO;
1125
1126 } else {
1127 const char *msg_type = crm_element_value(reply, F_STONITH_OPERATION);
1128
1129 native->token = crm_element_value_copy(reply, F_STONITH_CLIENTID);
1130 if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_casei)) {
1131 crm_debug("Couldn't register with the fencer: invalid reply type '%s'",
1132 (msg_type? msg_type : "(missing)"));
1133 crm_log_xml_debug(reply, "Invalid fencer reply");
1134 rc = -EPROTO;
1135
1136 } else if (native->token == NULL) {
1137 crm_debug("Couldn't register with the fencer: no token in reply");
1138 crm_log_xml_debug(reply, "Invalid fencer reply");
1139 rc = -EPROTO;
1140
1141 } else {
1142 crm_debug("Connection to fencer by %s succeeded (registration token: %s)",
1143 display_name, native->token);
1144 rc = pcmk_ok;
1145 }
1146 }
1147
1148 free_xml(reply);
1149 free_xml(hello);
1150 }
1151
1152 if (rc != pcmk_ok) {
1153 crm_debug("Connection attempt to fencer by %s failed: %s "
1154 CRM_XS " rc=%d", display_name, pcmk_strerror(rc), rc);
1155 stonith->cmds->disconnect(stonith);
1156 }
1157 return rc;
1158}
1159
1160static int
1161stonith_set_notification(stonith_t * stonith, const char *callback, int enabled)
1162{
1163 int rc = pcmk_ok;
1164 xmlNode *notify_msg = create_xml_node(NULL, __func__);
1165 stonith_private_t *native = stonith->st_private;
1166
1167 if (stonith->state != stonith_disconnected) {
1168
1170 if (enabled) {
1171 crm_xml_add(notify_msg, F_STONITH_NOTIFY_ACTIVATE, callback);
1172 } else {
1173 crm_xml_add(notify_msg, F_STONITH_NOTIFY_DEACTIVATE, callback);
1174 }
1175
1176 rc = crm_ipc_send(native->ipc, notify_msg, crm_ipc_client_response, -1, NULL);
1177 if (rc < 0) {
1178 crm_perror(LOG_DEBUG, "Couldn't register for fencing notifications: %d", rc);
1179 rc = -ECOMM;
1180 } else {
1181 rc = pcmk_ok;
1182 }
1183 }
1184
1185 free_xml(notify_msg);
1186 return rc;
1187}
1188
1189static int
1190stonith_api_add_notification(stonith_t * stonith, const char *event,
1191 void (*callback) (stonith_t * stonith, stonith_event_t * e))
1192{
1193 GList *list_item = NULL;
1194 stonith_notify_client_t *new_client = NULL;
1195 stonith_private_t *private = NULL;
1196
1197 private = stonith->st_private;
1198 crm_trace("Adding callback for %s events (%d)", event, g_list_length(private->notify_list));
1199
1200 new_client = calloc(1, sizeof(stonith_notify_client_t));
1201 new_client->event = event;
1202 new_client->notify = callback;
1203
1204 list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1205
1206 if (list_item != NULL) {
1207 crm_warn("Callback already present");
1208 free(new_client);
1209 return -ENOTUNIQ;
1210
1211 } else {
1212 private->notify_list = g_list_append(private->notify_list, new_client);
1213
1214 stonith_set_notification(stonith, event, 1);
1215
1216 crm_trace("Callback added (%d)", g_list_length(private->notify_list));
1217 }
1218 return pcmk_ok;
1219}
1220
1221static void
1222del_notify_entry(gpointer data, gpointer user_data)
1223{
1225 stonith_t * stonith = user_data;
1226
1227 if (!entry->delete) {
1228 crm_debug("Removing callback for %s events", entry->event);
1229 stonith_api_del_notification(stonith, entry->event);
1230 }
1231}
1232
1233static int
1234stonith_api_del_notification(stonith_t * stonith, const char *event)
1235{
1236 GList *list_item = NULL;
1237 stonith_notify_client_t *new_client = NULL;
1238 stonith_private_t *private = stonith->st_private;
1239
1240 if (event == NULL) {
1241 foreach_notify_entry(private, del_notify_entry, stonith);
1242 crm_trace("Removed callback");
1243
1244 return pcmk_ok;
1245 }
1246
1247 crm_debug("Removing callback for %s events", event);
1248
1249 new_client = calloc(1, sizeof(stonith_notify_client_t));
1250 new_client->event = event;
1251 new_client->notify = NULL;
1252
1253 list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1254
1255 stonith_set_notification(stonith, event, 0);
1256
1257 if (list_item != NULL) {
1258 stonith_notify_client_t *list_client = list_item->data;
1259
1260 if (private->notify_refcnt) {
1261 list_client->delete = TRUE;
1262 private->notify_deletes = TRUE;
1263 } else {
1264 private->notify_list = g_list_remove(private->notify_list, list_client);
1265 free(list_client);
1266 }
1267
1268 crm_trace("Removed callback");
1269
1270 } else {
1271 crm_trace("Callback not present");
1272 }
1273 free(new_client);
1274 return pcmk_ok;
1275}
1276
1277static int
1278stonith_api_add_callback(stonith_t * stonith, int call_id, int timeout, int options,
1279 void *user_data, const char *callback_name,
1280 void (*callback) (stonith_t * st, stonith_callback_data_t * data))
1281{
1282 stonith_callback_client_t *blob = NULL;
1283 stonith_private_t *private = NULL;
1284
1285 CRM_CHECK(stonith != NULL, return -EINVAL);
1286 CRM_CHECK(stonith->st_private != NULL, return -EINVAL);
1287 private = stonith->st_private;
1288
1289 if (call_id == 0) { // Add global callback
1290 private->op_callback = callback;
1291
1292 } else if (call_id < 0) { // Call failed immediately, so call callback now
1293 if (!(options & st_opt_report_only_success)) {
1295
1296 crm_trace("Call failed, calling %s: %s", callback_name, pcmk_strerror(call_id));
1298 stonith__legacy2status(call_id), NULL);
1299 invoke_fence_action_callback(stonith, call_id, &result,
1300 user_data, callback);
1301 } else {
1302 crm_warn("Fencer call failed: %s", pcmk_strerror(call_id));
1303 }
1304 return FALSE;
1305 }
1306
1307 blob = calloc(1, sizeof(stonith_callback_client_t));
1308 blob->id = callback_name;
1309 blob->only_success = (options & st_opt_report_only_success) ? TRUE : FALSE;
1310 blob->user_data = user_data;
1311 blob->callback = callback;
1312 blob->allow_timeout_updates = (options & st_opt_timeout_updates) ? TRUE : FALSE;
1313
1314 if (timeout > 0) {
1315 set_callback_timeout(blob, stonith, call_id, timeout);
1316 }
1317
1318 pcmk__intkey_table_insert(private->stonith_op_callback_table, call_id,
1319 blob);
1320 crm_trace("Added callback to %s for call %d", callback_name, call_id);
1321
1322 return TRUE;
1323}
1324
1325static void
1326stonith_dump_pending_op(gpointer key, gpointer value, gpointer user_data)
1327{
1328 int call = GPOINTER_TO_INT(key);
1329 stonith_callback_client_t *blob = value;
1330
1331 crm_debug("Call %d (%s): pending", call, crm_str(blob->id));
1332}
1333
1334void
1336{
1337 stonith_private_t *private = stonith->st_private;
1338
1339 if (private->stonith_op_callback_table == NULL) {
1340 return;
1341 }
1342 return g_hash_table_foreach(private->stonith_op_callback_table, stonith_dump_pending_op, NULL);
1343}
1344
1352static xmlNode *
1353get_event_data_xml(xmlNode *msg, const char *ntype)
1354{
1355 char *data_addr = crm_strdup_printf("//%s", ntype);
1356 xmlNode *data = get_xpath_object(data_addr, msg, LOG_DEBUG);
1357
1358 free(data_addr);
1359 return data;
1360}
1361
1362/*
1363 <notify t="st_notify" subt="st_device_register" st_op="st_device_register" st_rc="0" >
1364 <st_calldata >
1365 <stonith_command t="stonith-ng" st_async_id="088fb640-431a-48b9-b2fc-c4ff78d0a2d9" st_op="st_device_register" st_callid="2" st_callopt="4096" st_timeout="0" st_clientid="088fb640-431a-48b9-b2fc-c4ff78d0a2d9" st_clientname="cts-fence-helper" >
1366 <st_calldata >
1367 <st_device_id id="test-id" origin="create_device_registration_xml" agent="fence_virsh" namespace="stonith-ng" >
1368 <attributes ipaddr="localhost" pcmk-portmal="some-host=pcmk-1 pcmk-3=3,4" login="root" identity_file="/root/.ssh/id_dsa" />
1369 </st_device_id>
1370 </st_calldata>
1371 </stonith_command>
1372 </st_calldata>
1373 </notify>
1374
1375 <notify t="st_notify" subt="st_notify_fence" st_op="st_notify_fence" st_rc="0" >
1376 <st_calldata >
1377 <st_notify_fence st_rc="0" st_target="some-host" st_op="st_fence" st_delegate="test-id" st_origin="61dd7759-e229-4be7-b1f8-ef49dd14d9f0" />
1378 </st_calldata>
1379 </notify>
1380*/
1381static stonith_event_t *
1382xml_to_event(xmlNode *msg)
1383{
1384 stonith_event_t *event = calloc(1, sizeof(stonith_event_t));
1385 const char *ntype = crm_element_value(msg, F_SUBTYPE);
1386 struct event_private *event_private = NULL;
1387
1388 CRM_ASSERT(event != NULL);
1389
1390 event->opaque = calloc(1, sizeof(struct event_private));
1391 CRM_ASSERT(event->opaque != NULL);
1392 event_private = (struct event_private *) event->opaque;
1393
1394 crm_log_xml_trace(msg, "stonith_notify");
1395
1396 // All notification types have the operation result
1397 stonith__xe_get_result(msg, &event_private->result);
1398
1399 // @COMPAT The API originally provided the result as a legacy return code
1400 event->result = pcmk_rc2legacy(stonith__result2rc(&event_private->result));
1401
1402 // Fence notifications have additional information
1403 if (pcmk__str_eq(ntype, T_STONITH_NOTIFY_FENCE, pcmk__str_casei)) {
1404 xmlNode *data = get_event_data_xml(msg, ntype);
1405
1406 if (data == NULL) {
1407 crm_err("No data for %s event", ntype);
1408 crm_log_xml_notice(msg, "BadEvent");
1409 } else {
1413 event->executioner = crm_element_value_copy(data, F_STONITH_DELEGATE);
1415 event->client_origin = crm_element_value_copy(data, F_STONITH_CLIENTNAME);
1417 }
1418 event->operation = crm_element_value_copy(msg, F_STONITH_OPERATION);
1419 }
1420
1421 return event;
1422}
1423
1424static void
1425event_free(stonith_event_t * event)
1426{
1427 struct event_private *event_private = event->opaque;
1428
1429 free(event->id);
1430 free(event->type);
1431 free(event->message);
1432 free(event->operation);
1433 free(event->origin);
1434 free(event->action);
1435 free(event->target);
1436 free(event->executioner);
1437 free(event->device);
1438 free(event->client_origin);
1439 pcmk__reset_result(&event_private->result);
1440 free(event->opaque);
1441 free(event);
1442}
1443
1444static void
1445stonith_send_notification(gpointer data, gpointer user_data)
1446{
1447 struct notify_blob_s *blob = user_data;
1449 stonith_event_t *st_event = NULL;
1450 const char *event = NULL;
1451
1452 if (blob->xml == NULL) {
1453 crm_warn("Skipping callback - NULL message");
1454 return;
1455 }
1456
1457 event = crm_element_value(blob->xml, F_SUBTYPE);
1458
1459 if (entry == NULL) {
1460 crm_warn("Skipping callback - NULL callback client");
1461 return;
1462
1463 } else if (entry->delete) {
1464 crm_trace("Skipping callback - marked for deletion");
1465 return;
1466
1467 } else if (entry->notify == NULL) {
1468 crm_warn("Skipping callback - NULL callback");
1469 return;
1470
1471 } else if (!pcmk__str_eq(entry->event, event, pcmk__str_casei)) {
1472 crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
1473 return;
1474 }
1475
1476 st_event = xml_to_event(blob->xml);
1477
1478 crm_trace("Invoking callback for %p/%s event...", entry, event);
1479 entry->notify(blob->stonith, st_event);
1480 crm_trace("Callback invoked...");
1481
1482 event_free(st_event);
1483}
1484
1499static int
1500stonith_send_command(stonith_t * stonith, const char *op, xmlNode * data, xmlNode ** output_data,
1501 int call_options, int timeout)
1502{
1503 int rc = 0;
1504 int reply_id = -1;
1505
1506 xmlNode *op_msg = NULL;
1507 xmlNode *op_reply = NULL;
1508 stonith_private_t *native = NULL;
1509
1510 CRM_ASSERT(stonith && stonith->st_private && op);
1511 native = stonith->st_private;
1512
1513 if (output_data != NULL) {
1514 *output_data = NULL;
1515 }
1516
1517 if ((stonith->state == stonith_disconnected) || (native->token == NULL)) {
1518 return -ENOTCONN;
1519 }
1520
1521 /* Increment the call ID, which must be positive to avoid conflicting with
1522 * error codes. This shouldn't be a problem unless the client mucked with
1523 * it or the counter wrapped around.
1524 */
1525 stonith->call_id++;
1526 if (stonith->call_id < 1) {
1527 stonith->call_id = 1;
1528 }
1529
1530 op_msg = stonith_create_op(stonith->call_id, native->token, op, data, call_options);
1531 if (op_msg == NULL) {
1532 return -EINVAL;
1533 }
1534
1536 crm_trace("Sending %s message to fencer with timeout %ds", op, timeout);
1537
1538 if (data) {
1539 const char *delay_s = crm_element_value(data, F_STONITH_DELAY);
1540
1541 if (delay_s) {
1542 crm_xml_add(op_msg, F_STONITH_DELAY, delay_s);
1543 }
1544 }
1545
1546 {
1547 enum crm_ipc_flags ipc_flags = crm_ipc_flags_none;
1548
1549 if (call_options & st_opt_sync_call) {
1550 pcmk__set_ipc_flags(ipc_flags, "stonith command",
1552 }
1553 rc = crm_ipc_send(native->ipc, op_msg, ipc_flags,
1554 1000 * (timeout + 60), &op_reply);
1555 }
1556 free_xml(op_msg);
1557
1558 if (rc < 0) {
1559 crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%ds): %d", op, timeout, rc);
1560 rc = -ECOMM;
1561 goto done;
1562 }
1563
1564 crm_log_xml_trace(op_reply, "Reply");
1565
1566 if (!(call_options & st_opt_sync_call)) {
1567 crm_trace("Async call %d, returning", stonith->call_id);
1568 free_xml(op_reply);
1569 return stonith->call_id;
1570 }
1571
1572 rc = pcmk_ok;
1573 crm_element_value_int(op_reply, F_STONITH_CALLID, &reply_id);
1574
1575 if (reply_id == stonith->call_id) {
1577
1578 crm_trace("Synchronous reply %d received", reply_id);
1579
1580 stonith__xe_get_result(op_reply, &result);
1583
1584 if ((call_options & st_opt_discard_reply) || output_data == NULL) {
1585 crm_trace("Discarding reply");
1586
1587 } else {
1588 *output_data = op_reply;
1589 op_reply = NULL; /* Prevent subsequent free */
1590 }
1591
1592 } else if (reply_id <= 0) {
1593 crm_err("Received bad reply: No id set");
1594 crm_log_xml_err(op_reply, "Bad reply");
1595 free_xml(op_reply);
1596 rc = -ENOMSG;
1597
1598 } else {
1599 crm_err("Received bad reply: %d (wanted %d)", reply_id, stonith->call_id);
1600 crm_log_xml_err(op_reply, "Old reply");
1601 free_xml(op_reply);
1602 rc = -ENOMSG;
1603 }
1604
1605 done:
1606 if (crm_ipc_connected(native->ipc) == FALSE) {
1607 crm_err("Fencer disconnected");
1608 free(native->token); native->token = NULL;
1609 stonith->state = stonith_disconnected;
1610 }
1611
1612 free_xml(op_reply);
1613 return rc;
1614}
1615
1616/* Not used with mainloop */
1617bool
1619{
1620 gboolean stay_connected = TRUE;
1621 stonith_private_t *private = NULL;
1622
1623 CRM_ASSERT(st != NULL);
1624 private = st->st_private;
1625
1626 while (crm_ipc_ready(private->ipc)) {
1627
1628 if (crm_ipc_read(private->ipc) > 0) {
1629 const char *msg = crm_ipc_buffer(private->ipc);
1630
1631 stonith_dispatch_internal(msg, strlen(msg), st);
1632 }
1633
1634 if (crm_ipc_connected(private->ipc) == FALSE) {
1635 crm_err("Connection closed");
1636 stay_connected = FALSE;
1637 }
1638 }
1639
1640 return stay_connected;
1641}
1642
1643static int
1644stonith_api_free(stonith_t * stonith)
1645{
1646 int rc = pcmk_ok;
1647
1648 crm_trace("Destroying %p", stonith);
1649
1650 if (stonith->state != stonith_disconnected) {
1651 crm_trace("Disconnecting %p first", stonith);
1652 rc = stonith->cmds->disconnect(stonith);
1653 }
1654
1655 if (stonith->state == stonith_disconnected) {
1656 stonith_private_t *private = stonith->st_private;
1657
1658 crm_trace("Removing %d callbacks", g_hash_table_size(private->stonith_op_callback_table));
1659 g_hash_table_destroy(private->stonith_op_callback_table);
1660
1661 crm_trace("Destroying %d notification clients", g_list_length(private->notify_list));
1662 g_list_free_full(private->notify_list, free);
1663
1664 free(stonith->st_private);
1665 free(stonith->cmds);
1666 free(stonith);
1667
1668 } else {
1669 crm_err("Not free'ing active connection: %s (%d)", pcmk_strerror(rc), rc);
1670 }
1671
1672 return rc;
1673}
1674
1675void
1677{
1678 crm_trace("Destroying %p", stonith);
1679 if(stonith) {
1680 stonith->cmds->free(stonith);
1681 }
1682}
1683
1684static int
1685stonith_api_validate(stonith_t *st, int call_options, const char *rsc_id,
1686 const char *namespace_s, const char *agent,
1687 stonith_key_value_t *params, int timeout, char **output,
1688 char **error_output)
1689{
1690 /* Validation should be done directly via the agent, so we can get it from
1691 * stonith_admin when the cluster is not running, which is important for
1692 * higher-level tools.
1693 */
1694
1695 int rc = pcmk_ok;
1696
1697 /* Use a dummy node name in case the agent requires a target. We assume the
1698 * actual target doesn't matter for validation purposes (if in practice,
1699 * that is incorrect, we will need to allow the caller to pass the target).
1700 */
1701 const char *target = "node1";
1702 const char *host_arg = NULL;
1703
1704 GHashTable *params_table = pcmk__strkey_table(free, free);
1705
1706 // Convert parameter list to a hash table
1707 for (; params; params = params->next) {
1708 if (pcmk__str_eq(params->key, PCMK_STONITH_HOST_ARGUMENT,
1709 pcmk__str_casei)) {
1710 host_arg = params->value;
1711 }
1712 if (!pcmk_stonith_param(params->key)) {
1713 g_hash_table_insert(params_table, strdup(params->key),
1714 strdup(params->value));
1715 }
1716 }
1717
1718#if SUPPORT_CIBSECRETS
1719 rc = pcmk__substitute_secrets(rsc_id, params_table);
1720 if (rc != pcmk_rc_ok) {
1721 crm_warn("Could not replace secret parameters for validation of %s: %s",
1722 agent, pcmk_rc_str(rc));
1723 // rc is standard return value, don't return it in this function
1724 }
1725#endif
1726
1727 if (output) {
1728 *output = NULL;
1729 }
1730 if (error_output) {
1731 *error_output = NULL;
1732 }
1733
1734 switch (stonith_get_namespace(agent, namespace_s)) {
1735 case st_namespace_rhcs:
1736 rc = stonith__rhcs_validate(st, call_options, target, agent,
1737 params_table, host_arg, timeout,
1738 output, error_output);
1739 break;
1740
1741#if HAVE_STONITH_STONITH_H
1742 case st_namespace_lha:
1743 rc = stonith__lha_validate(st, call_options, target, agent,
1744 params_table, timeout, output,
1745 error_output);
1746 break;
1747#endif
1748
1749 default:
1750 rc = -EINVAL;
1751 errno = EINVAL;
1752 crm_perror(LOG_ERR,
1753 "Agent %s not found or does not support validation",
1754 agent);
1755 break;
1756 }
1757 g_hash_table_destroy(params_table);
1758 return rc;
1759}
1760
1761stonith_t *
1763{
1764 stonith_t *new_stonith = NULL;
1765 stonith_private_t *private = NULL;
1766
1767 new_stonith = calloc(1, sizeof(stonith_t));
1768 if (new_stonith == NULL) {
1769 return NULL;
1770 }
1771
1772 private = calloc(1, sizeof(stonith_private_t));
1773 if (private == NULL) {
1774 free(new_stonith);
1775 return NULL;
1776 }
1777 new_stonith->st_private = private;
1778
1779 private->stonith_op_callback_table = pcmk__intkey_table(stonith_destroy_op_callback);
1780 private->notify_list = NULL;
1781 private->notify_refcnt = 0;
1782 private->notify_deletes = FALSE;
1783
1784 new_stonith->call_id = 1;
1785 new_stonith->state = stonith_disconnected;
1786
1787 new_stonith->cmds = calloc(1, sizeof(stonith_api_operations_t));
1788 if (new_stonith->cmds == NULL) {
1789 free(new_stonith->st_private);
1790 free(new_stonith);
1791 return NULL;
1792 }
1793
1794/* *INDENT-OFF* */
1795 new_stonith->cmds->free = stonith_api_free;
1796 new_stonith->cmds->connect = stonith_api_signon;
1797 new_stonith->cmds->disconnect = stonith_api_signoff;
1798
1799 new_stonith->cmds->list = stonith_api_list;
1800 new_stonith->cmds->monitor = stonith_api_monitor;
1801 new_stonith->cmds->status = stonith_api_status;
1802 new_stonith->cmds->fence = stonith_api_fence;
1803 new_stonith->cmds->fence_with_delay = stonith_api_fence_with_delay;
1804 new_stonith->cmds->confirm = stonith_api_confirm;
1805 new_stonith->cmds->history = stonith_api_history;
1806
1807 new_stonith->cmds->list_agents = stonith_api_device_list;
1808 new_stonith->cmds->metadata = stonith_api_device_metadata;
1809
1810 new_stonith->cmds->query = stonith_api_query;
1811 new_stonith->cmds->remove_device = stonith_api_remove_device;
1812 new_stonith->cmds->register_device = stonith_api_register_device;
1813
1814 new_stonith->cmds->remove_level = stonith_api_remove_level;
1815 new_stonith->cmds->remove_level_full = stonith_api_remove_level_full;
1816 new_stonith->cmds->register_level = stonith_api_register_level;
1817 new_stonith->cmds->register_level_full = stonith_api_register_level_full;
1818
1819 new_stonith->cmds->remove_callback = stonith_api_del_callback;
1820 new_stonith->cmds->register_callback = stonith_api_add_callback;
1821 new_stonith->cmds->remove_notification = stonith_api_del_notification;
1822 new_stonith->cmds->register_notification = stonith_api_add_notification;
1823
1824 new_stonith->cmds->validate = stonith_api_validate;
1825/* *INDENT-ON* */
1826
1827 return new_stonith;
1828}
1829
1839int
1840stonith_api_connect_retry(stonith_t *st, const char *name, int max_attempts)
1841{
1842 int rc = -EINVAL; // if max_attempts is not positive
1843
1844 for (int attempt = 1; attempt <= max_attempts; attempt++) {
1845 rc = st->cmds->connect(st, name, NULL);
1846 if (rc == pcmk_ok) {
1847 return pcmk_ok;
1848 } else if (attempt < max_attempts) {
1849 crm_notice("Fencer connection attempt %d of %d failed (retrying in 2s): %s "
1850 CRM_XS " rc=%d",
1851 attempt, max_attempts, pcmk_strerror(rc), rc);
1852 sleep(2);
1853 }
1854 }
1855 crm_notice("Could not connect to fencer: %s " CRM_XS " rc=%d",
1856 pcmk_strerror(rc), rc);
1857 return rc;
1858}
1859
1861stonith_key_value_add(stonith_key_value_t * head, const char *key, const char *value)
1862{
1863 stonith_key_value_t *p, *end;
1864
1865 p = calloc(1, sizeof(stonith_key_value_t));
1866 pcmk__str_update(&p->key, key);
1867 pcmk__str_update(&p->value, value);
1868
1869 end = head;
1870 while (end && end->next) {
1871 end = end->next;
1872 }
1873
1874 if (end) {
1875 end->next = p;
1876 } else {
1877 head = p;
1878 }
1879
1880 return head;
1881}
1882
1883void
1885{
1887
1888 while (head) {
1889 p = head->next;
1890 if (keys) {
1891 free(head->key);
1892 }
1893 if (values) {
1894 free(head->value);
1895 }
1896 free(head);
1897 head = p;
1898 }
1899}
1900
1901#define api_log_open() openlog("stonith-api", LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON)
1902#define api_log(level, fmt, args...) syslog(level, "%s: "fmt, __func__, args)
1903
1904int
1905stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
1906{
1907 int rc = pcmk_ok;
1909 const char *action = off? "off" : "reboot";
1910
1911 api_log_open();
1912 if (st == NULL) {
1913 api_log(LOG_ERR, "API initialization failed, could not kick (%s) node %u/%s",
1914 action, nodeid, uname);
1915 return -EPROTO;
1916 }
1917
1918 rc = st->cmds->connect(st, "stonith-api", NULL);
1919 if (rc != pcmk_ok) {
1920 api_log(LOG_ERR, "Connection failed, could not kick (%s) node %u/%s : %s (%d)",
1921 action, nodeid, uname, pcmk_strerror(rc), rc);
1922 } else {
1923 char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
1924 int opts = 0;
1925
1928 if ((uname == NULL) && (nodeid > 0)) {
1930 }
1931 rc = st->cmds->fence(st, opts, name, action, timeout, 0);
1932 free(name);
1933
1934 if (rc != pcmk_ok) {
1935 api_log(LOG_ERR, "Could not kick (%s) node %u/%s : %s (%d)",
1936 action, nodeid, uname, pcmk_strerror(rc), rc);
1937 } else {
1938 api_log(LOG_NOTICE, "Node %u/%s kicked: %s", nodeid, uname, action);
1939 }
1940 }
1941
1943 return rc;
1944}
1945
1946time_t
1947stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
1948{
1949 int rc = pcmk_ok;
1950 time_t when = 0;
1952 stonith_history_t *history = NULL, *hp = NULL;
1953
1954 if (st == NULL) {
1955 api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: "
1956 "API initialization failed", nodeid, uname);
1957 return when;
1958 }
1959
1960 rc = st->cmds->connect(st, "stonith-api", NULL);
1961 if (rc != pcmk_ok) {
1962 api_log(LOG_NOTICE, "Connection failed: %s (%d)", pcmk_strerror(rc), rc);
1963 } else {
1964 int entries = 0;
1965 int progress = 0;
1966 int completed = 0;
1967 int opts = 0;
1968 char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
1969
1971 if ((uname == NULL) && (nodeid > 0)) {
1973 }
1974 rc = st->cmds->history(st, opts, name, &history, 120);
1975 free(name);
1976
1977 for (hp = history; hp; hp = hp->next) {
1978 entries++;
1979 if (in_progress) {
1980 progress++;
1981 if (hp->state != st_done && hp->state != st_failed) {
1982 when = time(NULL);
1983 }
1984
1985 } else if (hp->state == st_done) {
1986 completed++;
1987 if (hp->completed > when) {
1988 when = hp->completed;
1989 }
1990 }
1991 }
1992
1993 stonith_history_free(history);
1994
1995 if(rc == pcmk_ok) {
1996 api_log(LOG_INFO, "Found %d entries for %u/%s: %d in progress, %d completed", entries, nodeid, uname, progress, completed);
1997 } else {
1998 api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: %s (%d)", nodeid, uname, pcmk_strerror(rc), rc);
1999 }
2000 }
2001
2003
2004 if(when) {
2005 api_log(LOG_INFO, "Node %u/%s last kicked at: %ld", nodeid, uname, (long int)when);
2006 }
2007 return when;
2008}
2009
2010bool
2011stonith_agent_exists(const char *agent, int timeout)
2012{
2013 stonith_t *st = NULL;
2014 stonith_key_value_t *devices = NULL;
2015 stonith_key_value_t *dIter = NULL;
2016 bool rc = FALSE;
2017
2018 if (agent == NULL) {
2019 return rc;
2020 }
2021
2022 st = stonith_api_new();
2023 if (st == NULL) {
2024 crm_err("Could not list fence agents: API memory allocation failed");
2025 return FALSE;
2026 }
2027 st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, timeout == 0 ? 120 : timeout);
2028
2029 for (dIter = devices; dIter != NULL; dIter = dIter->next) {
2030 if (pcmk__str_eq(dIter->value, agent, pcmk__str_none)) {
2031 rc = TRUE;
2032 break;
2033 }
2034 }
2035
2036 stonith_key_value_freeall(devices, 1, 1);
2038 return rc;
2039}
2040
2041const char *
2043{
2044 if (action == NULL) {
2045 return "fencing";
2046 } else if (!strcmp(action, "on")) {
2047 return "unfencing";
2048 } else if (!strcmp(action, "off")) {
2049 return "turning off";
2050 } else {
2051 return action;
2052 }
2053}
2054
2063static void
2064parse_list_line(const char *line, int len, GList **output)
2065{
2066 size_t i = 0;
2067 size_t entry_start = 0;
2068
2069 /* Skip complaints about additional parameters device doesn't understand
2070 *
2071 * @TODO Document or eliminate the implied restriction of target names
2072 */
2073 if (strstr(line, "invalid") || strstr(line, "variable")) {
2074 crm_debug("Skipping list output line: %s", line);
2075 return;
2076 }
2077
2078 // Process line content, character by character
2079 for (i = 0; i <= len; i++) {
2080
2081 if (isspace(line[i]) || (line[i] == ',') || (line[i] == ';')
2082 || (line[i] == '\0')) {
2083 // We've found a separator (i.e. the end of an entry)
2084
2085 int rc = 0;
2086 char *entry = NULL;
2087
2088 if (i == entry_start) {
2089 // Skip leading and sequential separators
2090 entry_start = i + 1;
2091 continue;
2092 }
2093
2094 entry = calloc(i - entry_start + 1, sizeof(char));
2095 CRM_ASSERT(entry != NULL);
2096
2097 /* Read entry, stopping at first separator
2098 *
2099 * @TODO Document or eliminate these character restrictions
2100 */
2101 rc = sscanf(line + entry_start, "%[a-zA-Z0-9_-.]", entry);
2102 if (rc != 1) {
2103 crm_warn("Could not parse list output entry: %s "
2104 CRM_XS " entry_start=%d position=%d",
2105 line + entry_start, entry_start, i);
2106 free(entry);
2107
2108 } else if (pcmk__strcase_any_of(entry, "on", "off", NULL)) {
2109 /* Some agents print the target status in the list output,
2110 * though none are known now (the separate list-status command
2111 * is used for this, but it can also print "UNKNOWN"). To handle
2112 * this possibility, skip such entries.
2113 *
2114 * @TODO Document or eliminate the implied restriction of target
2115 * names.
2116 */
2117 free(entry);
2118
2119 } else {
2120 // We have a valid entry
2121 *output = g_list_append(*output, entry);
2122 }
2123 entry_start = i + 1;
2124 }
2125 }
2126}
2127
2149GList *
2150stonith__parse_targets(const char *target_spec)
2151{
2152 GList *targets = NULL;
2153
2154 if (target_spec != NULL) {
2155 size_t out_len = strlen(target_spec);
2156 size_t line_start = 0; // Starting index of line being processed
2157
2158 for (size_t i = 0; i <= out_len; ++i) {
2159 if ((target_spec[i] == '\n') || (target_spec[i] == '\0')
2160 || ((target_spec[i] == '\\') && (target_spec[i + 1] == 'n'))) {
2161 // We've reached the end of one line of output
2162
2163 int len = i - line_start;
2164
2165 if (len > 0) {
2166 char *line = strndup(target_spec + line_start, len);
2167
2168 line[len] = '\0'; // Because it might be a newline
2169 parse_list_line(line, len, &targets);
2170 free(line);
2171 }
2172 if (target_spec[i] == '\\') {
2173 ++i; // backslash-n takes up two positions
2174 }
2175 line_start = i + 1;
2176 }
2177 }
2178 }
2179 return targets;
2180}
2181
2189gboolean
2191{
2192 gboolean ret = FALSE;
2193
2194 for (stonith_history_t *prev_hp = top_history; prev_hp; prev_hp = prev_hp->next) {
2195 if (prev_hp == event) {
2196 break;
2197 }
2198
2199 if ((prev_hp->state == st_done) &&
2200 pcmk__str_eq(event->target, prev_hp->target, pcmk__str_casei) &&
2201 pcmk__str_eq(event->action, prev_hp->action, pcmk__str_casei) &&
2202 ((event->completed < prev_hp->completed) ||
2203 ((event->completed == prev_hp->completed) && (event->completed_nsec < prev_hp->completed_nsec)))) {
2204 ret = TRUE;
2205 break;
2206 }
2207 }
2208 return ret;
2209}
2210
2222{
2223 stonith_history_t *new = NULL, *pending = NULL, *hp, *np, *tmp;
2224
2225 for (hp = history; hp; ) {
2226 tmp = hp->next;
2227 if ((hp->state == st_done) || (hp->state == st_failed)) {
2228 /* sort into new */
2229 if ((!new) || (hp->completed > new->completed) ||
2230 ((hp->completed == new->completed) && (hp->completed_nsec > new->completed_nsec))) {
2231 hp->next = new;
2232 new = hp;
2233 } else {
2234 np = new;
2235 do {
2236 if ((!np->next) || (hp->completed > np->next->completed) ||
2237 ((hp->completed == np->next->completed) && (hp->completed_nsec > np->next->completed_nsec))) {
2238 hp->next = np->next;
2239 np->next = hp;
2240 break;
2241 }
2242 np = np->next;
2243 } while (1);
2244 }
2245 } else {
2246 /* put into pending */
2247 hp->next = pending;
2248 pending = hp;
2249 }
2250 hp = tmp;
2251 }
2252
2253 /* pending actions don't have a completed-stamp so make them go front */
2254 if (pending) {
2255 stonith_history_t *last_pending = pending;
2256
2257 while (last_pending->next) {
2258 last_pending = last_pending->next;
2259 }
2260
2261 last_pending->next = new;
2262 new = pending;
2263 }
2264 return new;
2265}
2266
2274const char *
2276{
2277 switch (state) {
2278 case st_query: return "querying";
2279 case st_exec: return "executing";
2280 case st_done: return "completed";
2281 case st_duplicate: return "duplicate";
2282 case st_failed: return "failed";
2283 }
2284 return "unknown";
2285}
2286
2289 bool (*matching_fn)(stonith_history_t *, void *),
2290 void *user_data)
2291{
2292 for (stonith_history_t *hp = history; hp; hp = hp->next) {
2293 if (matching_fn(hp, user_data)) {
2294 return hp;
2295 }
2296 }
2297
2298 return NULL;
2299}
2300
2301bool
2303{
2304 return history->state != st_failed && history->state != st_done;
2305}
2306
2307bool
2309{
2310 return history->state == GPOINTER_TO_INT(user_data);
2311}
2312
2313bool
2315{
2316 return history->state != GPOINTER_TO_INT(user_data);
2317}
2318
2319void
2320stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name,
2321 xmlNode *metadata)
2322{
2323 xmlXPathObjectPtr xpath = NULL;
2324 int max = 0;
2325 int lpc = 0;
2326
2327 CRM_CHECK((device_flags != NULL) && (metadata != NULL), return);
2328
2329 xpath = xpath_search(metadata, "//parameter");
2330 max = numXpathResults(xpath);
2331
2332 if (max <= 0) {
2333 freeXpathObject(xpath);
2334 return;
2335 }
2336
2337 for (lpc = 0; lpc < max; lpc++) {
2338 const char *parameter = NULL;
2339 xmlNode *match = getXpathResult(xpath, lpc);
2340
2341 CRM_LOG_ASSERT(match != NULL);
2342 if (match == NULL) {
2343 continue;
2344 }
2345
2346 parameter = crm_element_value(match, "name");
2347
2348 if (pcmk__str_eq(parameter, "plug", pcmk__str_casei)) {
2349 stonith__set_device_flags(*device_flags, device_name,
2351
2352 } else if (pcmk__str_eq(parameter, "port", pcmk__str_casei)) {
2353 stonith__set_device_flags(*device_flags, device_name,
2355 }
2356 }
2357
2358 freeXpathObject(xpath);
2359}
2360
2369int
2371{
2372 if ((data == NULL) || (data->opaque == NULL)) {
2373 return CRM_EX_ERROR;
2374 }
2375 return ((pcmk__action_result_t *) data->opaque)->exit_status;
2376}
2377
2386int
2388{
2389 if ((data == NULL) || (data->opaque == NULL)) {
2390 return PCMK_EXEC_UNKNOWN;
2391 }
2392 return ((pcmk__action_result_t *) data->opaque)->execution_status;
2393}
2394
2403const char *
2405{
2406 if ((data == NULL) || (data->opaque == NULL)) {
2407 return NULL;
2408 }
2409 return ((pcmk__action_result_t *) data->opaque)->exit_reason;
2410}
2411
2420int
2422{
2423 if ((event == NULL) || (event->opaque == NULL)) {
2424 return CRM_EX_ERROR;
2425 } else {
2426 struct event_private *event_private = event->opaque;
2427
2428 return event_private->result.exit_status;
2429 }
2430}
2431
2440int
2442{
2443 if ((event == NULL) || (event->opaque == NULL)) {
2444 return PCMK_EXEC_UNKNOWN;
2445 } else {
2446 struct event_private *event_private = event->opaque;
2447
2448 return event_private->result.execution_status;
2449 }
2450}
2451
2460const char *
2462{
2463 if ((event == NULL) || (event->opaque == NULL)) {
2464 return NULL;
2465 } else {
2466 struct event_private *event_private = event->opaque;
2467
2468 return event_private->result.exit_reason;
2469 }
2470}
2471
2484char *
2486{
2487 const char *origin = event->client_origin;
2488 const char *executioner = event->executioner;
2489 const char *reason = stonith__event_exit_reason(event);
2490 const char *status;
2491
2492 if (origin == NULL) {
2493 origin = "a client";
2494 }
2495 if (executioner == NULL) {
2496 executioner = "the cluster";
2497 }
2498
2500 status = pcmk_exec_status_str(stonith__event_execution_status(event));
2501 } else if (stonith__event_exit_status(event) != CRM_EX_OK) {
2502 status = pcmk_exec_status_str(PCMK_EXEC_ERROR);
2503 } else {
2504 status = crm_exit_str(CRM_EX_OK);
2505 }
2506
2507 return crm_strdup_printf("Operation %s of %s by %s for %s@%s: %s%s%s%s (ref=%s)",
2508 event->action, event->target, executioner, origin,
2509 event->origin, status,
2510 ((reason == NULL)? "" : " ("),
2511 ((reason == NULL)? "" : reason),
2512 ((reason == NULL)? "" : ")"),
2513 event->id);
2514}
2515
2516
2517// Deprecated functions kept only for backward API compatibility
2518// LCOV_EXCL_START
2519
2520const char *get_stonith_provider(const char *agent, const char *provider);
2521
2522const char *
2523get_stonith_provider(const char *agent, const char *provider)
2524{
2525 return stonith_namespace2text(stonith_get_namespace(agent, provider));
2526}
2527
2528// LCOV_EXCL_STOP
2529// End deprecated API
#define PCMK_STONITH_HOST_ARGUMENT
Definition: agents.h:32
bool pcmk_stonith_param(const char *param)
Check whether a given stonith parameter is handled by Pacemaker.
Definition: agents.c:170
const char * name
Definition: cib.c:24
int pcmk__substitute_secrets(const char *rsc_id, GHashTable *params)
Definition: cib_secrets.c:96
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
enum crm_ais_msg_types type
Definition: cpg.c:3
char uname[MAX_NAME]
Definition: cpg.c:5
char data[0]
Definition: cpg.c:10
uint32_t id
Definition: cpg.c:0
A dumping ground.
#define CRM_OP_REGISTER
Definition: crm.h:146
#define F_STONITH_DATE_NSEC
Definition: internal.h:141
int stonith__legacy2status(int rc)
Definition: st_actions.c:379
#define F_STONITH_HISTORY_LIST
Definition: internal.h:139
#define F_STONITH_ORIGIN
Definition: internal.h:138
#define T_STONITH_TIMEOUT_VALUE
Definition: internal.h:155
@ st_device_supports_parameter_port
Definition: internal.h:25
@ st_device_supports_parameter_plug
Definition: internal.h:24
#define STONITH_OP_QUERY
Definition: internal.h:162
#define STONITH_OP_FENCE
Definition: internal.h:163
#define F_STONITH_DELAY
Definition: internal.h:112
#define F_STONITH_CLIENTID
Definition: internal.h:99
#define F_STONITH_REMOTE_OP_ID
Definition: internal.h:105
#define STONITH_OP_DEVICE_ADD
Definition: internal.h:165
#define F_STONITH_DEVICE
Definition: internal.h:146
#define F_STONITH_DATE
Definition: internal.h:140
#define F_STONITH_TOLERANCE
Definition: internal.h:111
#define STONITH_OP_EXEC
Definition: internal.h:160
#define F_STONITH_TARGET
Definition: internal.h:104
#define stonith__set_device_flags(device_flags, device_id, flags_to_set)
Definition: internal.h:28
#define F_STONITH_NOTIFY_ACTIVATE
Definition: internal.h:131
#define F_STONITH_NOTIFY_DEACTIVATE
Definition: internal.h:132
#define F_STONITH_STATE
Definition: internal.h:142
#define F_STONITH_CALLDATA
Definition: internal.h:102
#define T_STONITH_NG
Definition: internal.h:150
#define STONITH_WATCHDOG_ID
Definition: internal.h:174
#define F_STONITH_CLIENTNAME
Definition: internal.h:129
#define F_STONITH_DELEGATE
Definition: internal.h:133
#define F_STONITH_ACTION
Definition: internal.h:147
void stonith__xe_get_result(xmlNode *xml, pcmk__action_result_t *result)
Definition: st_actions.c:469
#define STONITH_OP_LEVEL_ADD
Definition: internal.h:168
#define T_STONITH_NOTIFY
Definition: internal.h:156
#define STONITH_OP_FENCE_HISTORY
Definition: internal.h:167
#define stonith__set_call_options(st_call_opts, call_for, flags_to_set)
Definition: internal.h:35
#define F_STONITH_OUTPUT
Definition: internal.h:108
#define STONITH_OP_LEVEL_DEL
Definition: internal.h:169
int stonith__result2rc(const pcmk__action_result_t *result)
Definition: st_actions.c:305
#define F_STONITH_OPERATION
Definition: internal.h:103
#define F_STONITH_CALLBACK_TOKEN
Definition: internal.h:128
#define F_STONITH_CALLOPTS
Definition: internal.h:100
#define STONITH_OP_DEVICE_DEL
Definition: internal.h:166
#define F_STONITH_CALLID
Definition: internal.h:101
#define F_STONITH_TIMEOUT
Definition: internal.h:110
G_GNUC_INTERNAL bool stonith__agent_is_rhcs(const char *agent)
Definition: st_rhcs.c:245
G_GNUC_INTERNAL int stonith__rhcs_validate(stonith_t *st, int call_options, const char *target, const char *agent, GHashTable *params, const char *host_arg, int timeout, char **output, char **error_output)
Definition: st_rhcs.c:256
G_GNUC_INTERNAL int stonith__list_rhcs_agents(stonith_key_value_t **devices)
Definition: st_rhcs.c:35
G_GNUC_INTERNAL int stonith__rhcs_metadata(const char *agent, int timeout, char **output)
Execute RHCS-compatible agent's meta-data action.
Definition: st_rhcs.c:219
void crm_ipc_destroy(crm_ipc_t *client)
Definition: ipc_client.c:930
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
Definition: ipc_client.c:1209
long crm_ipc_read(crm_ipc_t *client)
Definition: ipc_client.c:1066
int crm_ipc_get_fd(crm_ipc_t *client)
Definition: ipc_client.c:956
crm_ipc_flags
Definition: ipc.h:145
@ crm_ipc_flags_none
Definition: ipc.h:146
@ crm_ipc_client_response
Definition: ipc.h:151
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
Definition: ipc_client.c:1002
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc_client.c:970
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition: ipc_client.c:847
void crm_ipc_close(crm_ipc_t *client)
Definition: ipc_client.c:917
const char * crm_ipc_buffer(crm_ipc_t *client)
Definition: ipc_client.c:1115
struct crm_ipc_s crm_ipc_t
Definition: ipc.h:163
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Create a new (legacy) object for using Pacemaker daemon IPC.
Definition: ipc_client.c:800
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
Definition: ipc_internal.h:176
#define crm_str(x)
Definition: logging.h:384
#define crm_info(fmt, args...)
Definition: logging.h:361
#define crm_warn(fmt, args...)
Definition: logging.h:359
#define CRM_XS
Definition: logging.h:55
#define crm_log_xml_debug(xml, text)
Definition: logging.h:371
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:210
#define crm_log_xml_err(xml, text)
Definition: logging.h:367
#define crm_notice(fmt, args...)
Definition: logging.h:360
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:309
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:226
#define crm_debug(fmt, args...)
Definition: logging.h:363
#define crm_err(fmt, args...)
Definition: logging.h:358
#define LOG_NEVER
Definition: logging.h:47
#define crm_log_xml_trace(xml, text)
Definition: logging.h:372
#define crm_log_xml_warn(xml, text)
Definition: logging.h:368
#define crm_trace(fmt, args...)
Definition: logging.h:364
#define crm_log_xml_notice(xml, text)
Definition: logging.h:369
Wrappers for and extensions to glib mainloop.
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:967
mainloop_io_t * mainloop_add_ipc_client(const char *name, int priority, size_t max_size, void *userdata, struct ipc_client_callbacks *callbacks)
Definition: mainloop.c:936
struct mainloop_io_s mainloop_io_t
Definition: mainloop.h:33
#define G_PRIORITY_MEDIUM
Definition: mainloop.h:182
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:961
#define F_SUBTYPE
Definition: msg_xml.h:65
#define XML_ATTR_STONITH_TARGET_ATTRIBUTE
Definition: msg_xml.h:445
#define XML_TAG_FENCING_LEVEL
Definition: msg_xml.h:440
#define F_XML_TAGNAME
Definition: msg_xml.h:77
#define XML_ATTR_ID
Definition: msg_xml.h:135
#define XML_LRM_ATTR_EXIT_REASON
Definition: msg_xml.h:321
#define XML_ATTR_STONITH_INDEX
Definition: msg_xml.h:441
#define XML_TAG_ATTRS
Definition: msg_xml.h:211
#define F_TYPE
Definition: msg_xml.h:69
#define XML_ATTR_STONITH_DEVICES
Definition: msg_xml.h:446
#define XML_ATTR_STONITH_TARGET_PATTERN
Definition: msg_xml.h:444
#define XML_ATTR_STONITH_TARGET_VALUE
Definition: msg_xml.h:443
#define XML_ATTR_STONITH_TARGET
Definition: msg_xml.h:442
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:529
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:565
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition: nvpair.c:782
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition: nvpair.c:431
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition: nvpair.c:726
int crm_element_value_ll(const xmlNode *data, const char *name, long long *dest)
Retrieve the long long integer value of an XML attribute.
Definition: nvpair.c:597
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:323
unsigned int timeout
Definition: pcmk_fence.c:31
int delay
Definition: pcmk_fence.c:33
unsigned int tolerance
Definition: pcmk_fence.c:32
stonith_t * st
Definition: pcmk_fence.c:27
const char * action
Definition: pcmk_fence.c:29
pcmk__action_result_t result
Definition: pcmk_fence.c:34
const char * target
Definition: pcmk_fence.c:28
char * strndup(const char *str, size_t len)
#define ECOMM
Definition: portability.h:125
#define ENOTUNIQ
Definition: portability.h:120
const char * pcmk_strerror(int rc)
Definition: results.c:58
#define CRM_ASSERT(expr)
Definition: results.h:42
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:370
@ CRM_EX_ERROR
Unspecified error.
Definition: results.h:240
@ CRM_EX_OK
Success.
Definition: results.h:239
@ pcmk_rc_ok
Definition: results.h:146
#define pcmk_ok
Definition: results.h:68
int pcmk_rc2legacy(int rc)
Definition: results.c:415
const char * crm_exit_str(crm_exit_t exit_code)
Definition: results.c:506
@ PCMK_EXEC_DONE
Action completed, result is known.
Definition: results.h:308
@ PCMK_EXEC_ERROR
Execution failed, may be retried.
Definition: results.h:312
@ PCMK_EXEC_TIMEOUT
Action did not complete in time.
Definition: results.h:310
@ PCMK_EXEC_UNKNOWN
Used only to initialize variables.
Definition: results.h:306
void pcmk__set_result(pcmk__action_result_t *result, int exit_status, enum pcmk_exec_status exec_status, const char *exit_reason)
Definition: results.c:814
#define PCMK__UNKNOWN_RESULT
void pcmk__reset_result(pcmk__action_result_t *result)
Definition: results.c:903
void stonith_api_delete(stonith_t *stonith)
Definition: st_client.c:1676
gboolean stonith__watchdog_fencing_enabled_for_node(const char *node)
Definition: st_client.c:231
const char * stonith_namespace2text(enum stonith_namespace st_namespace)
Get agent namespace name.
Definition: st_client.c:130
time_t stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
Definition: st_client.c:1947
stonith_key_value_t * stonith_key_value_add(stonith_key_value_t *head, const char *key, const char *value)
Definition: st_client.c:1861
const char * stonith__event_exit_reason(stonith_event_t *event)
Definition: st_client.c:2461
int stonith__exit_status(stonith_callback_data_t *data)
Definition: st_client.c:2370
bool stonith__event_state_pending(stonith_history_t *history, void *user_data)
Definition: st_client.c:2302
GList * stonith__parse_targets(const char *target_spec)
Definition: st_client.c:2150
enum stonith_namespace stonith_get_namespace(const char *agent, const char *namespace_s)
Determine namespace of a fence agent.
Definition: st_client.c:151
xmlNode * stonith_create_op(int call_id, const char *token, const char *op, xmlNode *data, int call_options)
Definition: st_client.c:784
void stonith_history_free(stonith_history_t *history)
Definition: st_client.c:737
bool stonith__event_state_neq(stonith_history_t *history, void *user_data)
Definition: st_client.c:2314
enum stonith_namespace stonith_text2namespace(const char *namespace_s)
Get agent namespace by name.
Definition: st_client.c:104
void stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name, xmlNode *metadata)
Definition: st_client.c:2320
bool stonith__event_state_eq(stonith_history_t *history, void *user_data)
Definition: st_client.c:2308
const char * stonith_action_str(const char *action)
Turn stonith action into a more readable string.
Definition: st_client.c:2042
CRM_TRACE_INIT_DATA(stonith)
bool stonith_dispatch(stonith_t *st)
Definition: st_client.c:1618
struct stonith_private_s stonith_private_t
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:1840
stonith_history_t * stonith__first_matching_event(stonith_history_t *history, bool(*matching_fn)(stonith_history_t *, void *), void *user_data)
Definition: st_client.c:2288
#define api_log(level, fmt, args...)
Definition: st_client.c:1902
int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
Definition: st_client.c:1905
const char * get_stonith_provider(const char *agent, const char *provider)
Definition: st_client.c:2523
gboolean stonith__later_succeeded(stonith_history_t *event, stonith_history_t *top_history)
Definition: st_client.c:2190
stonith_history_t * stonith__sort_history(stonith_history_t *history)
Definition: st_client.c:2221
gboolean stonith__watchdog_fencing_enabled_for_node_api(stonith_t *st, const char *node)
Definition: st_client.c:172
xmlNode * create_device_registration_xml(const char *id, enum stonith_namespace namespace, const char *agent, stonith_key_value_t *params, const char *rsc_provides)
Definition: st_client.c:293
int stonith__event_execution_status(stonith_event_t *event)
Definition: st_client.c:2441
xmlNode * create_level_registration_xml(const char *node, const char *pattern, const char *attr, const char *value, int level, stonith_key_value_t *device_list)
Definition: st_client.c:413
int stonith__execution_status(stonith_callback_data_t *data)
Definition: st_client.c:2387
const char * stonith__exit_reason(stonith_callback_data_t *data)
Definition: st_client.c:2404
int(* stonith_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition: st_client.c:82
stonith_t * stonith_api_new(void)
Definition: st_client.c:1762
#define api_log_open()
Definition: st_client.c:1901
struct stonith_notify_client_s stonith_notify_client_t
void stonith_key_value_freeall(stonith_key_value_t *head, int keys, int values)
Definition: st_client.c:1884
struct stonith_callback_client_s stonith_callback_client_t
bool stonith_agent_exists(const char *agent, int timeout)
Definition: st_client.c:2011
void stonith_dump_pending_callbacks(stonith_t *stonith)
Definition: st_client.c:1335
const char * stonith_op_state_str(enum op_state state)
Return string equivalent of an operation state value.
Definition: st_client.c:2275
int stonith__event_exit_status(stonith_event_t *event)
Definition: st_client.c:2421
char * stonith__event_description(stonith_event_t *event)
Definition: st_client.c:2485
int stonith__lha_metadata(const char *agent, int timeout, char **output)
Definition: st_lha.c:170
int stonith__list_lha_agents(stonith_key_value_t **devices)
Definition: st_lha.c:110
int stonith__lha_validate(stonith_t *st, int call_options, const char *target, const char *agent, GHashTable *params, int timeout, char **output, char **error_output)
Definition: st_lha.c:272
bool stonith__agent_is_lha(const char *agent)
Determine namespace of a fence agent.
Definition: st_lha.c:83
Fencing aka. STONITH.
#define T_STONITH_NOTIFY_FENCE
Definition: stonith-ng.h:36
@ st_opt_timeout_updates
Definition: stonith-ng.h:61
@ st_opt_cs_nodeid
Definition: stonith-ng.h:57
@ st_opt_discard_reply
Definition: stonith-ng.h:53
@ st_opt_manual_ack
Definition: stonith-ng.h:52
@ st_opt_allow_suicide
Definition: stonith-ng.h:50
@ st_opt_report_only_success
Definition: stonith-ng.h:63
@ st_opt_sync_call
Definition: stonith-ng.h:58
stonith_namespace
Definition: stonith-ng.h:81
@ st_namespace_invalid
Definition: stonith-ng.h:82
@ st_namespace_rhcs
Definition: stonith-ng.h:89
@ st_namespace_internal
Definition: stonith-ng.h:84
@ st_namespace_any
Definition: stonith-ng.h:83
@ st_namespace_lha
Definition: stonith-ng.h:90
@ stonith_disconnected
Definition: stonith-ng.h:44
@ stonith_connected_command
Definition: stonith-ng.h:42
#define T_STONITH_NOTIFY_DISCONNECT
Definition: stonith-ng.h:35
op_state
Definition: stonith-ng.h:72
@ st_duplicate
Definition: stonith-ng.h:76
@ st_query
Definition: stonith-ng.h:73
@ st_failed
Definition: stonith-ng.h:77
@ st_done
Definition: stonith-ng.h:75
@ st_exec
Definition: stonith-ng.h:74
void pcmk__add_separated_word(char **list, size_t *len, const char *word, const char *separator)
Definition: strings.c:703
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:611
void pcmk__str_update(char **str, const char *value)
Definition: strings.c:1188
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:931
gboolean pcmk__str_in_list(const gchar *s, GList *lst, uint32_t flags)
Definition: strings.c:886
@ pcmk__str_none
@ pcmk__str_null_matches
@ pcmk__str_casei
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source.
Definition: mainloop.h:84
enum pcmk_exec_status execution_status
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:424
int(* free)(stonith_t *st)
Destroy the stonith api structure.
Definition: stonith-ng.h:155
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 specified node, pattern or attribute.
Definition: stonith-ng.h:379
int(* remove_callback)(stonith_t *st, int call_id, bool all_callbacks)
Remove a registered callback for a given call id.
Definition: stonith-ng.h:340
int(* register_level)(stonith_t *st, int options, const char *node, int level, stonith_key_value_t *device_list)
Register a fencing level for specified node with local fencer.
Definition: stonith-ng.h:205
int(* status)(stonith_t *st, int options, const char *id, const char *port, int timeout)
Check to see if a local stonith device's port is reachable.
Definition: stonith-ng.h:252
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:215
int(* fence)(stonith_t *st, int options, const char *node, const char *action, int timeout, int tolerance)
Issue a fencing action against a node.
Definition: stonith-ng.h:280
int(* register_notification)(stonith_t *st, const char *event, void(*notify)(stonith_t *st, stonith_event_t *e))
Definition: stonith-ng.h:298
int(* connect)(stonith_t *st, const char *name, int *stonith_fd)
Connect to the local stonith daemon.
Definition: stonith-ng.h:162
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:327
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:227
int(* register_device)(stonith_t *st, int options, const char *id, const char *provider, const char *agent, stonith_key_value_t *params)
Register a fence device with the local fencer.
Definition: stonith-ng.h:186
int(* remove_level)(stonith_t *st, int options, const char *node, int level)
Unregister a fencing level for specified node with local fencer.
Definition: stonith-ng.h:196
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:236
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:262
int(* disconnect)(stonith_t *st)
Disconnect from the local stonith daemon.
Definition: stonith-ng.h:169
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:402
int(* remove_level_full)(stonith_t *st, int options, const char *node, const char *pattern, const char *attr, const char *value, int level)
Unregister fencing level for specified node, pattern or attribute.
Definition: stonith-ng.h:358
int(* monitor)(stonith_t *st, int options, const char *id, int timeout)
Check to see if a local stonith device is reachable.
Definition: stonith-ng.h:244
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:296
int(* remove_notification)(stonith_t *st, const char *event)
Remove a previously registered notification for event, or all notifications if NULL.
Definition: stonith-ng.h:311
int(* confirm)(stonith_t *st, int options, const char *node)
Manually confirm that a node is down.
Definition: stonith-ng.h:289
int(* remove_device)(stonith_t *st, int options, const char *name)
Unregister a fence device with the local fencer.
Definition: stonith-ng.h:177
char * operation
Definition: stonith-ng.h:124
char * executioner
Definition: stonith-ng.h:130
char * client_origin
Definition: stonith-ng.h:135
struct stonith_history_s * next
Definition: stonith-ng.h:112
struct stonith_key_value_s * next
Definition: stonith-ng.h:101
int call_id
Definition: stonith-ng.h:433
enum stonith_state state
Definition: stonith-ng.h:431
void * st_private
Definition: stonith-ng.h:435
stonith_api_operations_t * cmds
Definition: stonith-ng.h:437
int call_id
Definition: internal.h:104
guint ref
Definition: internal.h:106
int timeout
Definition: internal.h:105
stonith_t * stonith
Definition: st_client.c:79
xmlXPathObjectPtr xpath_search(xmlNode *xml_top, const char *path)
Definition: xpath.c:139
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:214
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:58
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:39
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition: messages.c:162
xmlNode * string2xml(const char *input)
Definition: xml.c:869
void free_xml(xmlNode *child)
Definition: xml.c:824
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:696