pacemaker 2.1.7-2.1.7
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
st_client.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2023 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_none)) {
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
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,
295 const stonith_key_value_t *params,
296 const char *rsc_provides)
297{
298 xmlNode *data = create_xml_node(NULL, F_STONITH_DEVICE);
299 xmlNode *args = create_xml_node(data, XML_TAG_ATTRS);
300
301#if HAVE_STONITH_STONITH_H
302 if (namespace == st_namespace_any) {
303 namespace = stonith_get_namespace(agent, NULL);
304 }
305 if (namespace == st_namespace_lha) {
306 hash2field((gpointer) "plugin", (gpointer) agent, args);
307 agent = "fence_legacy";
308 }
309#endif
310
313 crm_xml_add(data, "agent", agent);
314 if ((namespace != st_namespace_any) && (namespace != st_namespace_invalid)) {
315 crm_xml_add(data, "namespace", stonith_namespace2text(namespace));
316 }
317 if (rsc_provides) {
318 crm_xml_add(data, "rsc_provides", rsc_provides);
319 }
320
321 for (; params; params = params->next) {
322 hash2field((gpointer) params->key, (gpointer) params->value, args);
323 }
324
325 return data;
326}
327
328static int
329stonith_api_register_device(stonith_t *st, int call_options,
330 const char *id, const char *namespace,
331 const char *agent,
332 const stonith_key_value_t *params)
333{
334 int rc = 0;
335 xmlNode *data = NULL;
336
338 agent, params, NULL);
339
340 rc = stonith_send_command(st, STONITH_OP_DEVICE_ADD, data, NULL, call_options, 0);
341 free_xml(data);
342
343 return rc;
344}
345
346static int
347stonith_api_remove_device(stonith_t * st, int call_options, const char *name)
348{
349 int rc = 0;
350 xmlNode *data = NULL;
351
355 rc = stonith_send_command(st, STONITH_OP_DEVICE_DEL, data, NULL, call_options, 0);
356 free_xml(data);
357
358 return rc;
359}
360
361static int
362stonith_api_remove_level_full(stonith_t *st, int options,
363 const char *node, const char *pattern,
364 const char *attr, const char *value, int level)
365{
366 int rc = 0;
367 xmlNode *data = NULL;
368
369 CRM_CHECK(node || pattern || (attr && value), return -EINVAL);
370
373
374 if (node) {
376
377 } else if (pattern) {
379
380 } else {
383 }
384
386 rc = stonith_send_command(st, STONITH_OP_LEVEL_DEL, data, NULL, options, 0);
387 free_xml(data);
388
389 return rc;
390}
391
392static int
393stonith_api_remove_level(stonith_t * st, int options, const char *node, int level)
394{
395 return stonith_api_remove_level_full(st, options, node,
396 NULL, NULL, NULL, level);
397}
398
414xmlNode *
415create_level_registration_xml(const char *node, const char *pattern,
416 const char *attr, const char *value,
417 int level, const stonith_key_value_t *device_list)
418{
419 GString *list = NULL;
420 xmlNode *data;
421
422 CRM_CHECK(node || pattern || (attr && value), return NULL);
423
425 CRM_CHECK(data, return NULL);
426
430
431 if (node) {
433
434 } else if (pattern) {
436
437 } else {
440 }
441
442 for (; device_list; device_list = device_list->next) {
443 pcmk__add_separated_word(&list, 1024, device_list->value, ",");
444 }
445
446 if (list != NULL) {
447 crm_xml_add(data, XML_ATTR_STONITH_DEVICES, (const char *) list->str);
448 g_string_free(list, TRUE);
449 }
450 return data;
451}
452
453static int
454stonith_api_register_level_full(stonith_t *st, int options, const char *node,
455 const char *pattern, const char *attr,
456 const char *value, int level,
457 const 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 const 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
505// See stonith_api_operations_t:metadata() documentation
506static int
507stonith_api_device_metadata(stonith_t *stonith, int call_options,
508 const char *agent, const char *namespace,
509 char **output, int timeout_sec)
510{
511 /* By executing meta-data directly, we can get it from stonith_admin when
512 * the cluster is not running, which is important for higher-level tools.
513 */
514
515 enum stonith_namespace ns = stonith_get_namespace(agent, namespace);
516
517 if (timeout_sec <= 0) {
519 }
520
521 crm_trace("Looking up metadata for %s agent %s",
522 stonith_namespace2text(ns), agent);
523
524 switch (ns) {
526 return stonith__rhcs_metadata(agent, timeout_sec, output);
527
528#if HAVE_STONITH_STONITH_H
529 case st_namespace_lha:
530 return stonith__lha_metadata(agent, timeout_sec, output);
531#endif
532
533 default:
534 crm_err("Can't get fence agent '%s' meta-data: No such agent",
535 agent);
536 break;
537 }
538 return -ENODEV;
539}
540
541static int
542stonith_api_query(stonith_t * stonith, int call_options, const char *target,
543 stonith_key_value_t ** devices, int timeout)
544{
545 int rc = 0, lpc = 0, max = 0;
546
547 xmlNode *data = NULL;
548 xmlNode *output = NULL;
549 xmlXPathObjectPtr xpathObj = NULL;
550
551 CRM_CHECK(devices != NULL, return -EINVAL);
552
557 rc = stonith_send_command(stonith, STONITH_OP_QUERY, data, &output, call_options, timeout);
558
559 if (rc < 0) {
560 return rc;
561 }
562
563 xpathObj = xpath_search(output, "//@agent");
564 if (xpathObj) {
565 max = numXpathResults(xpathObj);
566
567 for (lpc = 0; lpc < max; lpc++) {
568 xmlNode *match = getXpathResult(xpathObj, lpc);
569
570 CRM_LOG_ASSERT(match != NULL);
571 if(match != NULL) {
572 xmlChar *match_path = xmlGetNodePath(match);
573
574 crm_info("%s[%d] = %s", "//@agent", lpc, match_path);
575 free(match_path);
576 *devices = stonith_key_value_add(*devices, NULL, crm_element_value(match, XML_ATTR_ID));
577 }
578 }
579
580 freeXpathObject(xpathObj);
581 }
582
583 free_xml(output);
584 free_xml(data);
585 return max;
586}
587
600static int
601stonith_api_call(stonith_t *stonith, int call_options, const char *id,
602 const char *action, const char *target, int timeout_sec,
603 xmlNode **output)
604{
605 int rc = 0;
606 xmlNode *data = NULL;
607
613
614 rc = stonith_send_command(stonith, STONITH_OP_EXEC, data, output,
615 call_options, timeout_sec);
616 free_xml(data);
617
618 return rc;
619}
620
621static int
622stonith_api_list(stonith_t * stonith, int call_options, const char *id, char **list_info,
623 int timeout)
624{
625 int rc;
626 xmlNode *output = NULL;
627
628 rc = stonith_api_call(stonith, call_options, id, PCMK_ACTION_LIST, NULL,
629 timeout, &output);
630
631 if (output && list_info) {
632 const char *list_str;
633
634 list_str = crm_element_value(output, F_STONITH_OUTPUT);
635
636 if (list_str) {
637 *list_info = strdup(list_str);
638 }
639 }
640
641 if (output) {
642 free_xml(output);
643 }
644
645 return rc;
646}
647
648static int
649stonith_api_monitor(stonith_t * stonith, int call_options, const char *id, int timeout)
650{
651 return stonith_api_call(stonith, call_options, id, PCMK_ACTION_MONITOR,
652 NULL, timeout, NULL);
653}
654
655static int
656stonith_api_status(stonith_t * stonith, int call_options, const char *id, const char *port,
657 int timeout)
658{
659 return stonith_api_call(stonith, call_options, id, PCMK_ACTION_STATUS, port,
660 timeout, NULL);
661}
662
663static int
664stonith_api_fence_with_delay(stonith_t * stonith, int call_options, const char *node,
665 const char *action, int timeout, int tolerance, int delay)
666{
667 int rc = 0;
668 xmlNode *data = NULL;
669
670 data = create_xml_node(NULL, __func__);
676
677 rc = stonith_send_command(stonith, STONITH_OP_FENCE, data, NULL, call_options, timeout);
678 free_xml(data);
679
680 return rc;
681}
682
683static int
684stonith_api_fence(stonith_t * stonith, int call_options, const char *node, const char *action,
685 int timeout, int tolerance)
686{
687 return stonith_api_fence_with_delay(stonith, call_options, node, action,
688 timeout, tolerance, 0);
689}
690
691static int
692stonith_api_confirm(stonith_t * stonith, int call_options, const char *target)
693{
695 return stonith_api_fence(stonith, call_options, target, PCMK_ACTION_OFF, 0,
696 0);
697}
698
699static int
700stonith_api_history(stonith_t * stonith, int call_options, const char *node,
701 stonith_history_t ** history, int timeout)
702{
703 int rc = 0;
704 xmlNode *data = NULL;
705 xmlNode *output = NULL;
706 stonith_history_t *last = NULL;
707
708 *history = NULL;
709
710 if (node) {
711 data = create_xml_node(NULL, __func__);
713 }
714
715 stonith__set_call_options(call_options, node, st_opt_sync_call);
716 rc = stonith_send_command(stonith, STONITH_OP_FENCE_HISTORY, data, &output,
717 call_options, timeout);
718 free_xml(data);
719
720 if (rc == 0) {
721 xmlNode *op = NULL;
722 xmlNode *reply = get_xpath_object("//" F_STONITH_HISTORY_LIST, output,
723 LOG_NEVER);
724
725 for (op = pcmk__xml_first_child(reply); op != NULL;
726 op = pcmk__xml_next(op)) {
728 long long completed;
729 long long completed_nsec = 0L;
730
731 kvp = calloc(1, sizeof(stonith_history_t));
737 crm_element_value_ll(op, F_STONITH_DATE, &completed);
738 kvp->completed = (time_t) completed;
739 crm_element_value_ll(op, F_STONITH_DATE_NSEC, &completed_nsec);
740 kvp->completed_nsec = completed_nsec;
744
745 if (last) {
746 last->next = kvp;
747 } else {
748 *history = kvp;
749 }
750 last = kvp;
751 }
752 }
753
754 free_xml(output);
755
756 return rc;
757}
758
760{
761 stonith_history_t *hp, *hp_old;
762
763 for (hp = history; hp; hp_old = hp, hp = hp->next, free(hp_old)) {
764 free(hp->target);
765 free(hp->action);
766 free(hp->origin);
767 free(hp->delegate);
768 free(hp->client);
769 free(hp->exit_reason);
770 }
771}
772
773static gint
774stonithlib_GCompareFunc(gconstpointer a, gconstpointer b)
775{
776 int rc = 0;
777 const stonith_notify_client_t *a_client = a;
778 const stonith_notify_client_t *b_client = b;
779
780 if (a_client->delete || b_client->delete) {
781 /* make entries marked for deletion not findable */
782 return -1;
783 }
784 CRM_CHECK(a_client->event != NULL && b_client->event != NULL, return 0);
785 rc = strcmp(a_client->event, b_client->event);
786 if (rc == 0) {
787 if (a_client->notify == NULL || b_client->notify == NULL) {
788 return 0;
789
790 } else if (a_client->notify == b_client->notify) {
791 return 0;
792
793 } else if (((long)a_client->notify) < ((long)b_client->notify)) {
794 crm_err("callbacks for %s are not equal: %p vs. %p",
795 a_client->event, a_client->notify, b_client->notify);
796 return -1;
797 }
798 crm_err("callbacks for %s are not equal: %p vs. %p",
799 a_client->event, a_client->notify, b_client->notify);
800 return 1;
801 }
802 return rc;
803}
804
805xmlNode *
806stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data, int call_options)
807{
808 xmlNode *op_msg = create_xml_node(NULL, "stonith_command");
809
810 CRM_CHECK(op_msg != NULL, return NULL);
811 CRM_CHECK(token != NULL, return NULL);
812
813 crm_xml_add(op_msg, F_XML_TAGNAME, "stonith_command");
814
817 crm_xml_add(op_msg, F_STONITH_OPERATION, op);
818 crm_xml_add_int(op_msg, F_STONITH_CALLID, call_id);
819 crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
820 crm_xml_add_int(op_msg, F_STONITH_CALLOPTS, call_options);
821
822 if (data != NULL) {
824 }
825
826 return op_msg;
827}
828
829static void
830stonith_destroy_op_callback(gpointer data)
831{
833
834 if (blob->timer && blob->timer->ref > 0) {
835 g_source_remove(blob->timer->ref);
836 }
837 free(blob->timer);
838 free(blob);
839}
840
841static int
842stonith_api_signoff(stonith_t * stonith)
843{
844 stonith_private_t *native = stonith->st_private;
845
846 crm_debug("Disconnecting from the fencer");
847
848 if (native->source != NULL) {
849 /* Attached to mainloop */
850 mainloop_del_ipc_client(native->source);
851 native->source = NULL;
852 native->ipc = NULL;
853
854 } else if (native->ipc) {
855 /* Not attached to mainloop */
856 crm_ipc_t *ipc = native->ipc;
857
858 native->ipc = NULL;
859 crm_ipc_close(ipc);
860 crm_ipc_destroy(ipc);
861 }
862
863 free(native->token); native->token = NULL;
864 stonith->state = stonith_disconnected;
865 return pcmk_ok;
866}
867
868static int
869stonith_api_del_callback(stonith_t * stonith, int call_id, bool all_callbacks)
870{
871 stonith_private_t *private = stonith->st_private;
872
873 if (all_callbacks) {
874 private->op_callback = NULL;
875 g_hash_table_destroy(private->stonith_op_callback_table);
876 private->stonith_op_callback_table = pcmk__intkey_table(stonith_destroy_op_callback);
877
878 } else if (call_id == 0) {
879 private->op_callback = NULL;
880
881 } else {
882 pcmk__intkey_table_remove(private->stonith_op_callback_table, call_id);
883 }
884 return pcmk_ok;
885}
886
898static void
899invoke_fence_action_callback(stonith_t *st, int call_id,
901 void *userdata,
902 void (*callback) (stonith_t *st,
904{
906
907 data.call_id = call_id;
909 data.userdata = userdata;
910 data.opaque = (void *) result;
911
912 callback(st, &data);
913}
914
926static void
927invoke_registered_callbacks(stonith_t *stonith, const xmlNode *msg, int call_id)
928{
929 stonith_private_t *private = NULL;
930 stonith_callback_client_t *cb_info = NULL;
932
933 CRM_CHECK(stonith != NULL, return);
934 CRM_CHECK(stonith->st_private != NULL, return);
935
936 private = stonith->st_private;
937
938 if (msg == NULL) {
939 // Fencer didn't reply in time
941 "Fencer accepted request but did not reply in time");
942 CRM_LOG_ASSERT(call_id > 0);
943
944 } else {
945 // We have the fencer reply
946 if ((crm_element_value_int(msg, F_STONITH_CALLID, &call_id) != 0)
947 || (call_id <= 0)) {
948 crm_log_xml_warn(msg, "Bad fencer reply");
949 }
951 }
952
953 if (call_id > 0) {
954 cb_info = pcmk__intkey_table_lookup(private->stonith_op_callback_table,
955 call_id);
956 }
957
958 if ((cb_info != NULL) && (cb_info->callback != NULL)
959 && (pcmk__result_ok(&result) || !(cb_info->only_success))) {
960 crm_trace("Invoking callback %s for call %d",
961 pcmk__s(cb_info->id, "without ID"), call_id);
962 invoke_fence_action_callback(stonith, call_id, &result,
963 cb_info->user_data, cb_info->callback);
964
965 } else if ((private->op_callback == NULL) && !pcmk__result_ok(&result)) {
966 crm_warn("Fencing action without registered callback failed: %d (%s%s%s)",
968 pcmk_exec_status_str(result.execution_status),
969 ((result.exit_reason == NULL)? "" : ": "),
970 ((result.exit_reason == NULL)? "" : result.exit_reason));
971 crm_log_xml_debug(msg, "Failed fence update");
972 }
973
974 if (private->op_callback != NULL) {
975 crm_trace("Invoking global callback for call %d", call_id);
976 invoke_fence_action_callback(stonith, call_id, &result, NULL,
977 private->op_callback);
978 }
979
980 if (cb_info != NULL) {
981 stonith_api_del_callback(stonith, call_id, FALSE);
982 }
984}
985
986static gboolean
987stonith_async_timeout_handler(gpointer data)
988{
989 struct timer_rec_s *timer = data;
990
991 crm_err("Async call %d timed out after %dms", timer->call_id, timer->timeout);
992 invoke_registered_callbacks(timer->stonith, NULL, timer->call_id);
993
994 /* Always return TRUE, never remove the handler
995 * We do that in stonith_del_callback()
996 */
997 return TRUE;
998}
999
1000static void
1001set_callback_timeout(stonith_callback_client_t * callback, stonith_t * stonith, int call_id,
1002 int timeout)
1003{
1004 struct timer_rec_s *async_timer = callback->timer;
1005
1006 if (timeout <= 0) {
1007 return;
1008 }
1009
1010 if (!async_timer) {
1011 async_timer = calloc(1, sizeof(struct timer_rec_s));
1012 callback->timer = async_timer;
1013 }
1014
1015 async_timer->stonith = stonith;
1016 async_timer->call_id = call_id;
1017 /* Allow a fair bit of grace to allow the server to tell us of a timeout
1018 * This is only a fallback
1019 */
1020 async_timer->timeout = (timeout + 60) * 1000;
1021 if (async_timer->ref) {
1022 g_source_remove(async_timer->ref);
1023 }
1024 async_timer->ref =
1025 g_timeout_add(async_timer->timeout, stonith_async_timeout_handler, async_timer);
1026}
1027
1028static void
1029update_callback_timeout(int call_id, int timeout, stonith_t * st)
1030{
1031 stonith_callback_client_t *callback = NULL;
1032 stonith_private_t *private = st->st_private;
1033
1034 callback = pcmk__intkey_table_lookup(private->stonith_op_callback_table,
1035 call_id);
1036 if (!callback || !callback->allow_timeout_updates) {
1037 return;
1038 }
1039
1040 set_callback_timeout(callback, st, call_id, timeout);
1041}
1042
1043static int
1044stonith_dispatch_internal(const char *buffer, ssize_t length, gpointer userdata)
1045{
1046 const char *type = NULL;
1047 struct notify_blob_s blob;
1048
1049 stonith_t *st = userdata;
1050 stonith_private_t *private = NULL;
1051
1052 CRM_ASSERT(st != NULL);
1053 private = st->st_private;
1054
1055 blob.stonith = st;
1056 blob.xml = string2xml(buffer);
1057 if (blob.xml == NULL) {
1058 crm_warn("Received malformed message from fencer: %s", buffer);
1059 return 0;
1060 }
1061
1062 /* do callbacks */
1063 type = crm_element_value(blob.xml, F_TYPE);
1064 crm_trace("Activating %s callbacks...", type);
1065
1066 if (pcmk__str_eq(type, T_STONITH_NG, pcmk__str_none)) {
1067 invoke_registered_callbacks(st, blob.xml, 0);
1068
1069 } else if (pcmk__str_eq(type, T_STONITH_NOTIFY, pcmk__str_none)) {
1070 foreach_notify_entry(private, stonith_send_notification, &blob);
1071 } else if (pcmk__str_eq(type, T_STONITH_TIMEOUT_VALUE, pcmk__str_none)) {
1072 int call_id = 0;
1073 int timeout = 0;
1074
1076 crm_element_value_int(blob.xml, F_STONITH_CALLID, &call_id);
1077
1078 update_callback_timeout(call_id, timeout, st);
1079 } else {
1080 crm_err("Unknown message type: %s", type);
1081 crm_log_xml_warn(blob.xml, "BadReply");
1082 }
1083
1084 free_xml(blob.xml);
1085 return 1;
1086}
1087
1088static int
1089stonith_api_signon(stonith_t * stonith, const char *name, int *stonith_fd)
1090{
1091 int rc = pcmk_ok;
1092 stonith_private_t *native = NULL;
1093 const char *display_name = name? name : "client";
1094
1095 struct ipc_client_callbacks st_callbacks = {
1096 .dispatch = stonith_dispatch_internal,
1097 .destroy = stonith_connection_destroy
1098 };
1099
1100 CRM_CHECK(stonith != NULL, return -EINVAL);
1101
1102 native = stonith->st_private;
1103 CRM_ASSERT(native != NULL);
1104
1105 crm_debug("Attempting fencer connection by %s with%s mainloop",
1106 display_name, (stonith_fd? "out" : ""));
1107
1109 if (stonith_fd) {
1110 /* No mainloop */
1111 native->ipc = crm_ipc_new("stonith-ng", 0);
1112 if (native->ipc != NULL) {
1113 rc = pcmk__connect_generic_ipc(native->ipc);
1114 if (rc == pcmk_rc_ok) {
1115 rc = pcmk__ipc_fd(native->ipc, stonith_fd);
1116 if (rc != pcmk_rc_ok) {
1117 crm_debug("Couldn't get file descriptor for IPC: %s",
1118 pcmk_rc_str(rc));
1119 }
1120 }
1121 if (rc != pcmk_rc_ok) {
1122 crm_ipc_close(native->ipc);
1123 crm_ipc_destroy(native->ipc);
1124 native->ipc = NULL;
1125 }
1126 }
1127
1128 } else {
1129 /* With mainloop */
1130 native->source =
1131 mainloop_add_ipc_client("stonith-ng", G_PRIORITY_MEDIUM, 0, stonith, &st_callbacks);
1132 native->ipc = mainloop_get_ipc_client(native->source);
1133 }
1134
1135 if (native->ipc == NULL) {
1136 rc = -ENOTCONN;
1137 } else {
1138 xmlNode *reply = NULL;
1139 xmlNode *hello = create_xml_node(NULL, "stonith_command");
1140
1144 rc = crm_ipc_send(native->ipc, hello, crm_ipc_client_response, -1, &reply);
1145
1146 if (rc < 0) {
1147 crm_debug("Couldn't register with the fencer: %s "
1148 CRM_XS " rc=%d", pcmk_strerror(rc), rc);
1149 rc = -ECOMM;
1150
1151 } else if (reply == NULL) {
1152 crm_debug("Couldn't register with the fencer: no reply");
1153 rc = -EPROTO;
1154
1155 } else {
1156 const char *msg_type = crm_element_value(reply, F_STONITH_OPERATION);
1157
1158 native->token = crm_element_value_copy(reply, F_STONITH_CLIENTID);
1159 if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_none)) {
1160 crm_debug("Couldn't register with the fencer: invalid reply type '%s'",
1161 (msg_type? msg_type : "(missing)"));
1162 crm_log_xml_debug(reply, "Invalid fencer reply");
1163 rc = -EPROTO;
1164
1165 } else if (native->token == NULL) {
1166 crm_debug("Couldn't register with the fencer: no token in reply");
1167 crm_log_xml_debug(reply, "Invalid fencer reply");
1168 rc = -EPROTO;
1169
1170 } else {
1171 crm_debug("Connection to fencer by %s succeeded (registration token: %s)",
1172 display_name, native->token);
1173 rc = pcmk_ok;
1174 }
1175 }
1176
1177 free_xml(reply);
1178 free_xml(hello);
1179 }
1180
1181 if (rc != pcmk_ok) {
1182 crm_debug("Connection attempt to fencer by %s failed: %s "
1183 CRM_XS " rc=%d", display_name, pcmk_strerror(rc), rc);
1184 stonith->cmds->disconnect(stonith);
1185 }
1186 return rc;
1187}
1188
1189static int
1190stonith_set_notification(stonith_t * stonith, const char *callback, int enabled)
1191{
1192 int rc = pcmk_ok;
1193 xmlNode *notify_msg = create_xml_node(NULL, __func__);
1194 stonith_private_t *native = stonith->st_private;
1195
1196 if (stonith->state != stonith_disconnected) {
1197
1199 if (enabled) {
1200 crm_xml_add(notify_msg, F_STONITH_NOTIFY_ACTIVATE, callback);
1201 } else {
1202 crm_xml_add(notify_msg, F_STONITH_NOTIFY_DEACTIVATE, callback);
1203 }
1204
1205 rc = crm_ipc_send(native->ipc, notify_msg, crm_ipc_client_response, -1, NULL);
1206 if (rc < 0) {
1207 crm_perror(LOG_DEBUG, "Couldn't register for fencing notifications: %d", rc);
1208 rc = -ECOMM;
1209 } else {
1210 rc = pcmk_ok;
1211 }
1212 }
1213
1214 free_xml(notify_msg);
1215 return rc;
1216}
1217
1218static int
1219stonith_api_add_notification(stonith_t * stonith, const char *event,
1220 void (*callback) (stonith_t * stonith, stonith_event_t * e))
1221{
1222 GList *list_item = NULL;
1223 stonith_notify_client_t *new_client = NULL;
1224 stonith_private_t *private = NULL;
1225
1226 private = stonith->st_private;
1227 crm_trace("Adding callback for %s events (%d)", event, g_list_length(private->notify_list));
1228
1229 new_client = calloc(1, sizeof(stonith_notify_client_t));
1230 new_client->event = event;
1231 new_client->notify = callback;
1232
1233 list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1234
1235 if (list_item != NULL) {
1236 crm_warn("Callback already present");
1237 free(new_client);
1238 return -ENOTUNIQ;
1239
1240 } else {
1241 private->notify_list = g_list_append(private->notify_list, new_client);
1242
1243 stonith_set_notification(stonith, event, 1);
1244
1245 crm_trace("Callback added (%d)", g_list_length(private->notify_list));
1246 }
1247 return pcmk_ok;
1248}
1249
1250static void
1251del_notify_entry(gpointer data, gpointer user_data)
1252{
1254 stonith_t * stonith = user_data;
1255
1256 if (!entry->delete) {
1257 crm_debug("Removing callback for %s events", entry->event);
1258 stonith_api_del_notification(stonith, entry->event);
1259 }
1260}
1261
1262static int
1263stonith_api_del_notification(stonith_t * stonith, const char *event)
1264{
1265 GList *list_item = NULL;
1266 stonith_notify_client_t *new_client = NULL;
1267 stonith_private_t *private = stonith->st_private;
1268
1269 if (event == NULL) {
1270 foreach_notify_entry(private, del_notify_entry, stonith);
1271 crm_trace("Removed callback");
1272
1273 return pcmk_ok;
1274 }
1275
1276 crm_debug("Removing callback for %s events", event);
1277
1278 new_client = calloc(1, sizeof(stonith_notify_client_t));
1279 new_client->event = event;
1280 new_client->notify = NULL;
1281
1282 list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1283
1284 stonith_set_notification(stonith, event, 0);
1285
1286 if (list_item != NULL) {
1287 stonith_notify_client_t *list_client = list_item->data;
1288
1289 if (private->notify_refcnt) {
1290 list_client->delete = TRUE;
1291 private->notify_deletes = TRUE;
1292 } else {
1293 private->notify_list = g_list_remove(private->notify_list, list_client);
1294 free(list_client);
1295 }
1296
1297 crm_trace("Removed callback");
1298
1299 } else {
1300 crm_trace("Callback not present");
1301 }
1302 free(new_client);
1303 return pcmk_ok;
1304}
1305
1306static int
1307stonith_api_add_callback(stonith_t * stonith, int call_id, int timeout, int options,
1308 void *user_data, const char *callback_name,
1309 void (*callback) (stonith_t * st, stonith_callback_data_t * data))
1310{
1311 stonith_callback_client_t *blob = NULL;
1312 stonith_private_t *private = NULL;
1313
1314 CRM_CHECK(stonith != NULL, return -EINVAL);
1315 CRM_CHECK(stonith->st_private != NULL, return -EINVAL);
1316 private = stonith->st_private;
1317
1318 if (call_id == 0) { // Add global callback
1319 private->op_callback = callback;
1320
1321 } else if (call_id < 0) { // Call failed immediately, so call callback now
1322 if (!(options & st_opt_report_only_success)) {
1324
1325 crm_trace("Call failed, calling %s: %s", callback_name, pcmk_strerror(call_id));
1327 stonith__legacy2status(call_id), NULL);
1328 invoke_fence_action_callback(stonith, call_id, &result,
1329 user_data, callback);
1330 } else {
1331 crm_warn("Fencer call failed: %s", pcmk_strerror(call_id));
1332 }
1333 return FALSE;
1334 }
1335
1336 blob = calloc(1, sizeof(stonith_callback_client_t));
1337 blob->id = callback_name;
1338 blob->only_success = (options & st_opt_report_only_success) ? TRUE : FALSE;
1339 blob->user_data = user_data;
1340 blob->callback = callback;
1341 blob->allow_timeout_updates = (options & st_opt_timeout_updates) ? TRUE : FALSE;
1342
1343 if (timeout > 0) {
1344 set_callback_timeout(blob, stonith, call_id, timeout);
1345 }
1346
1347 pcmk__intkey_table_insert(private->stonith_op_callback_table, call_id,
1348 blob);
1349 crm_trace("Added callback to %s for call %d", callback_name, call_id);
1350
1351 return TRUE;
1352}
1353
1354static void
1355stonith_dump_pending_op(gpointer key, gpointer value, gpointer user_data)
1356{
1357 int call = GPOINTER_TO_INT(key);
1358 stonith_callback_client_t *blob = value;
1359
1360 crm_debug("Call %d (%s): pending", call, pcmk__s(blob->id, "no ID"));
1361}
1362
1363void
1365{
1366 stonith_private_t *private = stonith->st_private;
1367
1368 if (private->stonith_op_callback_table == NULL) {
1369 return;
1370 }
1371 return g_hash_table_foreach(private->stonith_op_callback_table, stonith_dump_pending_op, NULL);
1372}
1373
1381static xmlNode *
1382get_event_data_xml(xmlNode *msg, const char *ntype)
1383{
1384 char *data_addr = crm_strdup_printf("//%s", ntype);
1385 xmlNode *data = get_xpath_object(data_addr, msg, LOG_DEBUG);
1386
1387 free(data_addr);
1388 return data;
1389}
1390
1391/*
1392 <notify t="st_notify" subt="st_device_register" st_op="st_device_register" st_rc="0" >
1393 <st_calldata >
1394 <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" >
1395 <st_calldata >
1396 <st_device_id id="test-id" origin="create_device_registration_xml" agent="fence_virsh" namespace="stonith-ng" >
1397 <attributes ipaddr="localhost" pcmk-portmal="some-host=pcmk-1 pcmk-3=3,4" login="root" identity_file="/root/.ssh/id_dsa" />
1398 </st_device_id>
1399 </st_calldata>
1400 </stonith_command>
1401 </st_calldata>
1402 </notify>
1403
1404 <notify t="st_notify" subt="st_notify_fence" st_op="st_notify_fence" st_rc="0" >
1405 <st_calldata >
1406 <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" />
1407 </st_calldata>
1408 </notify>
1409*/
1410static stonith_event_t *
1411xml_to_event(xmlNode *msg)
1412{
1413 stonith_event_t *event = calloc(1, sizeof(stonith_event_t));
1414 struct event_private *event_private = NULL;
1415
1416 CRM_ASSERT(event != NULL);
1417
1418 event->opaque = calloc(1, sizeof(struct event_private));
1419 CRM_ASSERT(event->opaque != NULL);
1420 event_private = (struct event_private *) event->opaque;
1421
1422 crm_log_xml_trace(msg, "stonith_notify");
1423
1424 // All notification types have the operation result and notification subtype
1425 stonith__xe_get_result(msg, &event_private->result);
1426 event->operation = crm_element_value_copy(msg, F_STONITH_OPERATION);
1427
1428 // @COMPAT The API originally provided the result as a legacy return code
1429 event->result = pcmk_rc2legacy(stonith__result2rc(&event_private->result));
1430
1431 // Some notification subtypes have additional information
1432
1433 if (pcmk__str_eq(event->operation, T_STONITH_NOTIFY_FENCE,
1434 pcmk__str_none)) {
1435 xmlNode *data = get_event_data_xml(msg, event->operation);
1436
1437 if (data == NULL) {
1438 crm_err("No data for %s event", event->operation);
1439 crm_log_xml_notice(msg, "BadEvent");
1440 } else {
1444 event->executioner = crm_element_value_copy(data, F_STONITH_DELEGATE);
1446 event->client_origin = crm_element_value_copy(data, F_STONITH_CLIENTNAME);
1448 }
1449
1450 } else if (pcmk__str_any_of(event->operation,
1453 NULL)) {
1454 xmlNode *data = get_event_data_xml(msg, event->operation);
1455
1456 if (data == NULL) {
1457 crm_err("No data for %s event", event->operation);
1458 crm_log_xml_notice(msg, "BadEvent");
1459 } else {
1461 }
1462 }
1463
1464 return event;
1465}
1466
1467static void
1468event_free(stonith_event_t * event)
1469{
1470 struct event_private *event_private = event->opaque;
1471
1472 free(event->id);
1473 free(event->type);
1474 free(event->message);
1475 free(event->operation);
1476 free(event->origin);
1477 free(event->action);
1478 free(event->target);
1479 free(event->executioner);
1480 free(event->device);
1481 free(event->client_origin);
1482 pcmk__reset_result(&event_private->result);
1483 free(event->opaque);
1484 free(event);
1485}
1486
1487static void
1488stonith_send_notification(gpointer data, gpointer user_data)
1489{
1490 struct notify_blob_s *blob = user_data;
1492 stonith_event_t *st_event = NULL;
1493 const char *event = NULL;
1494
1495 if (blob->xml == NULL) {
1496 crm_warn("Skipping callback - NULL message");
1497 return;
1498 }
1499
1500 event = crm_element_value(blob->xml, F_SUBTYPE);
1501
1502 if (entry == NULL) {
1503 crm_warn("Skipping callback - NULL callback client");
1504 return;
1505
1506 } else if (entry->delete) {
1507 crm_trace("Skipping callback - marked for deletion");
1508 return;
1509
1510 } else if (entry->notify == NULL) {
1511 crm_warn("Skipping callback - NULL callback");
1512 return;
1513
1514 } else if (!pcmk__str_eq(entry->event, event, pcmk__str_none)) {
1515 crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
1516 return;
1517 }
1518
1519 st_event = xml_to_event(blob->xml);
1520
1521 crm_trace("Invoking callback for %p/%s event...", entry, event);
1522 entry->notify(blob->stonith, st_event);
1523 crm_trace("Callback invoked...");
1524
1525 event_free(st_event);
1526}
1527
1542static int
1543stonith_send_command(stonith_t * stonith, const char *op, xmlNode * data, xmlNode ** output_data,
1544 int call_options, int timeout)
1545{
1546 int rc = 0;
1547 int reply_id = -1;
1548
1549 xmlNode *op_msg = NULL;
1550 xmlNode *op_reply = NULL;
1551 stonith_private_t *native = NULL;
1552
1553 CRM_ASSERT(stonith && stonith->st_private && op);
1554 native = stonith->st_private;
1555
1556 if (output_data != NULL) {
1557 *output_data = NULL;
1558 }
1559
1560 if ((stonith->state == stonith_disconnected) || (native->token == NULL)) {
1561 return -ENOTCONN;
1562 }
1563
1564 /* Increment the call ID, which must be positive to avoid conflicting with
1565 * error codes. This shouldn't be a problem unless the client mucked with
1566 * it or the counter wrapped around.
1567 */
1568 stonith->call_id++;
1569 if (stonith->call_id < 1) {
1570 stonith->call_id = 1;
1571 }
1572
1573 op_msg = stonith_create_op(stonith->call_id, native->token, op, data, call_options);
1574 if (op_msg == NULL) {
1575 return -EINVAL;
1576 }
1577
1579 crm_trace("Sending %s message to fencer with timeout %ds", op, timeout);
1580
1581 if (data) {
1582 const char *delay_s = crm_element_value(data, F_STONITH_DELAY);
1583
1584 if (delay_s) {
1585 crm_xml_add(op_msg, F_STONITH_DELAY, delay_s);
1586 }
1587 }
1588
1589 {
1590 enum crm_ipc_flags ipc_flags = crm_ipc_flags_none;
1591
1592 if (call_options & st_opt_sync_call) {
1593 pcmk__set_ipc_flags(ipc_flags, "stonith command",
1595 }
1596 rc = crm_ipc_send(native->ipc, op_msg, ipc_flags,
1597 1000 * (timeout + 60), &op_reply);
1598 }
1599 free_xml(op_msg);
1600
1601 if (rc < 0) {
1602 crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%ds): %d", op, timeout, rc);
1603 rc = -ECOMM;
1604 goto done;
1605 }
1606
1607 crm_log_xml_trace(op_reply, "Reply");
1608
1609 if (!(call_options & st_opt_sync_call)) {
1610 crm_trace("Async call %d, returning", stonith->call_id);
1611 free_xml(op_reply);
1612 return stonith->call_id;
1613 }
1614
1615 crm_element_value_int(op_reply, F_STONITH_CALLID, &reply_id);
1616
1617 if (reply_id == stonith->call_id) {
1619
1620 crm_trace("Synchronous reply %d received", reply_id);
1621
1622 stonith__xe_get_result(op_reply, &result);
1625
1626 if ((call_options & st_opt_discard_reply) || output_data == NULL) {
1627 crm_trace("Discarding reply");
1628
1629 } else {
1630 *output_data = op_reply;
1631 op_reply = NULL; /* Prevent subsequent free */
1632 }
1633
1634 } else if (reply_id <= 0) {
1635 crm_err("Received bad reply: No id set");
1636 crm_log_xml_err(op_reply, "Bad reply");
1637 free_xml(op_reply);
1638 rc = -ENOMSG;
1639
1640 } else {
1641 crm_err("Received bad reply: %d (wanted %d)", reply_id, stonith->call_id);
1642 crm_log_xml_err(op_reply, "Old reply");
1643 free_xml(op_reply);
1644 rc = -ENOMSG;
1645 }
1646
1647 done:
1648 if (!crm_ipc_connected(native->ipc)) {
1649 crm_err("Fencer disconnected");
1650 free(native->token); native->token = NULL;
1651 stonith->state = stonith_disconnected;
1652 }
1653
1654 free_xml(op_reply);
1655 return rc;
1656}
1657
1658/* Not used with mainloop */
1659bool
1661{
1662 gboolean stay_connected = TRUE;
1663 stonith_private_t *private = NULL;
1664
1665 CRM_ASSERT(st != NULL);
1666 private = st->st_private;
1667
1668 while (crm_ipc_ready(private->ipc)) {
1669
1670 if (crm_ipc_read(private->ipc) > 0) {
1671 const char *msg = crm_ipc_buffer(private->ipc);
1672
1673 stonith_dispatch_internal(msg, strlen(msg), st);
1674 }
1675
1676 if (!crm_ipc_connected(private->ipc)) {
1677 crm_err("Connection closed");
1678 stay_connected = FALSE;
1679 }
1680 }
1681
1682 return stay_connected;
1683}
1684
1685static int
1686stonith_api_free(stonith_t * stonith)
1687{
1688 int rc = pcmk_ok;
1689
1690 crm_trace("Destroying %p", stonith);
1691
1692 if (stonith->state != stonith_disconnected) {
1693 crm_trace("Unregistering notifications and disconnecting %p first",
1694 stonith);
1695 stonith->cmds->remove_notification(stonith, NULL);
1696 rc = stonith->cmds->disconnect(stonith);
1697 }
1698
1699 if (stonith->state == stonith_disconnected) {
1700 stonith_private_t *private = stonith->st_private;
1701
1702 crm_trace("Removing %d callbacks", g_hash_table_size(private->stonith_op_callback_table));
1703 g_hash_table_destroy(private->stonith_op_callback_table);
1704
1705 crm_trace("Destroying %d notification clients", g_list_length(private->notify_list));
1706 g_list_free_full(private->notify_list, free);
1707
1708 free(stonith->st_private);
1709 free(stonith->cmds);
1710 free(stonith);
1711
1712 } else {
1713 crm_err("Not free'ing active connection: %s (%d)", pcmk_strerror(rc), rc);
1714 }
1715
1716 return rc;
1717}
1718
1719void
1721{
1722 crm_trace("Destroying %p", stonith);
1723 if(stonith) {
1724 stonith->cmds->free(stonith);
1725 }
1726}
1727
1728static int
1729stonith_api_validate(stonith_t *st, int call_options, const char *rsc_id,
1730 const char *namespace_s, const char *agent,
1731 const stonith_key_value_t *params, int timeout_sec,
1732 char **output, char **error_output)
1733{
1734 /* Validation should be done directly via the agent, so we can get it from
1735 * stonith_admin when the cluster is not running, which is important for
1736 * higher-level tools.
1737 */
1738
1739 int rc = pcmk_ok;
1740
1741 /* Use a dummy node name in case the agent requires a target. We assume the
1742 * actual target doesn't matter for validation purposes (if in practice,
1743 * that is incorrect, we will need to allow the caller to pass the target).
1744 */
1745 const char *target = "node1";
1746 const char *host_arg = NULL;
1747
1748 GHashTable *params_table = pcmk__strkey_table(free, free);
1749
1750 // Convert parameter list to a hash table
1751 for (; params; params = params->next) {
1752 if (pcmk__str_eq(params->key, PCMK_STONITH_HOST_ARGUMENT,
1753 pcmk__str_none)) {
1754 host_arg = params->value;
1755 }
1756 if (!pcmk_stonith_param(params->key)) {
1757 g_hash_table_insert(params_table, strdup(params->key),
1758 strdup(params->value));
1759 }
1760 }
1761
1762#if SUPPORT_CIBSECRETS
1763 rc = pcmk__substitute_secrets(rsc_id, params_table);
1764 if (rc != pcmk_rc_ok) {
1765 crm_warn("Could not replace secret parameters for validation of %s: %s",
1766 agent, pcmk_rc_str(rc));
1767 // rc is standard return value, don't return it in this function
1768 }
1769#endif
1770
1771 if (output) {
1772 *output = NULL;
1773 }
1774 if (error_output) {
1775 *error_output = NULL;
1776 }
1777
1778 if (timeout_sec <= 0) {
1779 timeout_sec = PCMK_DEFAULT_METADATA_TIMEOUT_MS; // Questionable
1780 }
1781
1782 switch (stonith_get_namespace(agent, namespace_s)) {
1783 case st_namespace_rhcs:
1784 rc = stonith__rhcs_validate(st, call_options, target, agent,
1785 params_table, host_arg, timeout_sec,
1786 output, error_output);
1787 break;
1788
1789#if HAVE_STONITH_STONITH_H
1790 case st_namespace_lha:
1791 rc = stonith__lha_validate(st, call_options, target, agent,
1792 params_table, timeout_sec, output,
1793 error_output);
1794 break;
1795#endif
1796
1798 errno = ENOENT;
1799 rc = -errno;
1800
1801 if (error_output) {
1802 *error_output = crm_strdup_printf("Agent %s not found", agent);
1803 } else {
1804 crm_err("Agent %s not found", agent);
1805 }
1806
1807 break;
1808
1809 default:
1810 errno = EOPNOTSUPP;
1811 rc = -errno;
1812
1813 if (error_output) {
1814 *error_output = crm_strdup_printf("Agent %s does not support validation",
1815 agent);
1816 } else {
1817 crm_err("Agent %s does not support validation", agent);
1818 }
1819
1820 break;
1821 }
1822
1823 g_hash_table_destroy(params_table);
1824 return rc;
1825}
1826
1827stonith_t *
1829{
1830 stonith_t *new_stonith = NULL;
1831 stonith_private_t *private = NULL;
1832
1833 new_stonith = calloc(1, sizeof(stonith_t));
1834 if (new_stonith == NULL) {
1835 return NULL;
1836 }
1837
1838 private = calloc(1, sizeof(stonith_private_t));
1839 if (private == NULL) {
1840 free(new_stonith);
1841 return NULL;
1842 }
1843 new_stonith->st_private = private;
1844
1845 private->stonith_op_callback_table = pcmk__intkey_table(stonith_destroy_op_callback);
1846 private->notify_list = NULL;
1847 private->notify_refcnt = 0;
1848 private->notify_deletes = FALSE;
1849
1850 new_stonith->call_id = 1;
1851 new_stonith->state = stonith_disconnected;
1852
1853 new_stonith->cmds = calloc(1, sizeof(stonith_api_operations_t));
1854 if (new_stonith->cmds == NULL) {
1855 free(new_stonith->st_private);
1856 free(new_stonith);
1857 return NULL;
1858 }
1859
1860/* *INDENT-OFF* */
1861 new_stonith->cmds->free = stonith_api_free;
1862 new_stonith->cmds->connect = stonith_api_signon;
1863 new_stonith->cmds->disconnect = stonith_api_signoff;
1864
1865 new_stonith->cmds->list = stonith_api_list;
1866 new_stonith->cmds->monitor = stonith_api_monitor;
1867 new_stonith->cmds->status = stonith_api_status;
1868 new_stonith->cmds->fence = stonith_api_fence;
1869 new_stonith->cmds->fence_with_delay = stonith_api_fence_with_delay;
1870 new_stonith->cmds->confirm = stonith_api_confirm;
1871 new_stonith->cmds->history = stonith_api_history;
1872
1873 new_stonith->cmds->list_agents = stonith_api_device_list;
1874 new_stonith->cmds->metadata = stonith_api_device_metadata;
1875
1876 new_stonith->cmds->query = stonith_api_query;
1877 new_stonith->cmds->remove_device = stonith_api_remove_device;
1878 new_stonith->cmds->register_device = stonith_api_register_device;
1879
1880 new_stonith->cmds->remove_level = stonith_api_remove_level;
1881 new_stonith->cmds->remove_level_full = stonith_api_remove_level_full;
1882 new_stonith->cmds->register_level = stonith_api_register_level;
1883 new_stonith->cmds->register_level_full = stonith_api_register_level_full;
1884
1885 new_stonith->cmds->remove_callback = stonith_api_del_callback;
1886 new_stonith->cmds->register_callback = stonith_api_add_callback;
1887 new_stonith->cmds->remove_notification = stonith_api_del_notification;
1888 new_stonith->cmds->register_notification = stonith_api_add_notification;
1889
1890 new_stonith->cmds->validate = stonith_api_validate;
1891/* *INDENT-ON* */
1892
1893 return new_stonith;
1894}
1895
1905int
1906stonith_api_connect_retry(stonith_t *st, const char *name, int max_attempts)
1907{
1908 int rc = -EINVAL; // if max_attempts is not positive
1909
1910 for (int attempt = 1; attempt <= max_attempts; attempt++) {
1911 rc = st->cmds->connect(st, name, NULL);
1912 if (rc == pcmk_ok) {
1913 return pcmk_ok;
1914 } else if (attempt < max_attempts) {
1915 crm_notice("Fencer connection attempt %d of %d failed (retrying in 2s): %s "
1916 CRM_XS " rc=%d",
1917 attempt, max_attempts, pcmk_strerror(rc), rc);
1918 sleep(2);
1919 }
1920 }
1921 crm_notice("Could not connect to fencer: %s " CRM_XS " rc=%d",
1922 pcmk_strerror(rc), rc);
1923 return rc;
1924}
1925
1927stonith_key_value_add(stonith_key_value_t * head, const char *key, const char *value)
1928{
1929 stonith_key_value_t *p, *end;
1930
1931 p = calloc(1, sizeof(stonith_key_value_t));
1932 pcmk__str_update(&p->key, key);
1933 pcmk__str_update(&p->value, value);
1934
1935 end = head;
1936 while (end && end->next) {
1937 end = end->next;
1938 }
1939
1940 if (end) {
1941 end->next = p;
1942 } else {
1943 head = p;
1944 }
1945
1946 return head;
1947}
1948
1949void
1951{
1953
1954 while (head) {
1955 p = head->next;
1956 if (keys) {
1957 free(head->key);
1958 }
1959 if (values) {
1960 free(head->value);
1961 }
1962 free(head);
1963 head = p;
1964 }
1965}
1966
1967#define api_log_open() openlog("stonith-api", LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON)
1968#define api_log(level, fmt, args...) syslog(level, "%s: "fmt, __func__, args)
1969
1970int
1971stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
1972{
1973 int rc = pcmk_ok;
1975 const char *action = off? PCMK_ACTION_OFF : PCMK_ACTION_REBOOT;
1976
1977 api_log_open();
1978 if (st == NULL) {
1979 api_log(LOG_ERR, "API initialization failed, could not kick (%s) node %u/%s",
1980 action, nodeid, uname);
1981 return -EPROTO;
1982 }
1983
1984 rc = st->cmds->connect(st, "stonith-api", NULL);
1985 if (rc != pcmk_ok) {
1986 api_log(LOG_ERR, "Connection failed, could not kick (%s) node %u/%s : %s (%d)",
1987 action, nodeid, uname, pcmk_strerror(rc), rc);
1988 } else {
1989 char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
1990 int opts = 0;
1991
1994 if ((uname == NULL) && (nodeid > 0)) {
1996 }
1997 rc = st->cmds->fence(st, opts, name, action, timeout, 0);
1998 free(name);
1999
2000 if (rc != pcmk_ok) {
2001 api_log(LOG_ERR, "Could not kick (%s) node %u/%s : %s (%d)",
2002 action, nodeid, uname, pcmk_strerror(rc), rc);
2003 } else {
2004 api_log(LOG_NOTICE, "Node %u/%s kicked: %s", nodeid, uname, action);
2005 }
2006 }
2007
2009 return rc;
2010}
2011
2012time_t
2013stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
2014{
2015 int rc = pcmk_ok;
2016 time_t when = 0;
2018 stonith_history_t *history = NULL, *hp = NULL;
2019
2020 if (st == NULL) {
2021 api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: "
2022 "API initialization failed", nodeid, uname);
2023 return when;
2024 }
2025
2026 rc = st->cmds->connect(st, "stonith-api", NULL);
2027 if (rc != pcmk_ok) {
2028 api_log(LOG_NOTICE, "Connection failed: %s (%d)", pcmk_strerror(rc), rc);
2029 } else {
2030 int entries = 0;
2031 int progress = 0;
2032 int completed = 0;
2033 int opts = 0;
2034 char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
2035
2037 if ((uname == NULL) && (nodeid > 0)) {
2039 }
2040 rc = st->cmds->history(st, opts, name, &history, 120);
2041 free(name);
2042
2043 for (hp = history; hp; hp = hp->next) {
2044 entries++;
2045 if (in_progress) {
2046 progress++;
2047 if (hp->state != st_done && hp->state != st_failed) {
2048 when = time(NULL);
2049 }
2050
2051 } else if (hp->state == st_done) {
2052 completed++;
2053 if (hp->completed > when) {
2054 when = hp->completed;
2055 }
2056 }
2057 }
2058
2059 stonith_history_free(history);
2060
2061 if(rc == pcmk_ok) {
2062 api_log(LOG_INFO, "Found %d entries for %u/%s: %d in progress, %d completed", entries, nodeid, uname, progress, completed);
2063 } else {
2064 api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: %s (%d)", nodeid, uname, pcmk_strerror(rc), rc);
2065 }
2066 }
2067
2069
2070 if(when) {
2071 api_log(LOG_INFO, "Node %u/%s last kicked at: %ld", nodeid, uname, (long int)when);
2072 }
2073 return when;
2074}
2075
2076bool
2077stonith_agent_exists(const char *agent, int timeout)
2078{
2079 stonith_t *st = NULL;
2080 stonith_key_value_t *devices = NULL;
2081 stonith_key_value_t *dIter = NULL;
2082 bool rc = FALSE;
2083
2084 if (agent == NULL) {
2085 return rc;
2086 }
2087
2088 st = stonith_api_new();
2089 if (st == NULL) {
2090 crm_err("Could not list fence agents: API memory allocation failed");
2091 return FALSE;
2092 }
2093 st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, timeout == 0 ? 120 : timeout);
2094
2095 for (dIter = devices; dIter != NULL; dIter = dIter->next) {
2096 if (pcmk__str_eq(dIter->value, agent, pcmk__str_none)) {
2097 rc = TRUE;
2098 break;
2099 }
2100 }
2101
2102 stonith_key_value_freeall(devices, 1, 1);
2104 return rc;
2105}
2106
2107const char *
2109{
2110 if (action == NULL) {
2111 return "fencing";
2112 } else if (strcmp(action, PCMK_ACTION_ON) == 0) {
2113 return "unfencing";
2114 } else if (strcmp(action, PCMK_ACTION_OFF) == 0) {
2115 return "turning off";
2116 } else {
2117 return action;
2118 }
2119}
2120
2129static void
2130parse_list_line(const char *line, int len, GList **output)
2131{
2132 size_t i = 0;
2133 size_t entry_start = 0;
2134
2135 /* Skip complaints about additional parameters device doesn't understand
2136 *
2137 * @TODO Document or eliminate the implied restriction of target names
2138 */
2139 if (strstr(line, "invalid") || strstr(line, "variable")) {
2140 crm_debug("Skipping list output line: %s", line);
2141 return;
2142 }
2143
2144 // Process line content, character by character
2145 for (i = 0; i <= len; i++) {
2146
2147 if (isspace(line[i]) || (line[i] == ',') || (line[i] == ';')
2148 || (line[i] == '\0')) {
2149 // We've found a separator (i.e. the end of an entry)
2150
2151 int rc = 0;
2152 char *entry = NULL;
2153
2154 if (i == entry_start) {
2155 // Skip leading and sequential separators
2156 entry_start = i + 1;
2157 continue;
2158 }
2159
2160 entry = calloc(i - entry_start + 1, sizeof(char));
2161 CRM_ASSERT(entry != NULL);
2162
2163 /* Read entry, stopping at first separator
2164 *
2165 * @TODO Document or eliminate these character restrictions
2166 */
2167 rc = sscanf(line + entry_start, "%[a-zA-Z0-9_-.]", entry);
2168 if (rc != 1) {
2169 crm_warn("Could not parse list output entry: %s "
2170 CRM_XS " entry_start=%d position=%d",
2171 line + entry_start, entry_start, i);
2172 free(entry);
2173
2174 } else if (pcmk__strcase_any_of(entry, PCMK_ACTION_ON,
2175 PCMK_ACTION_OFF, NULL)) {
2176 /* Some agents print the target status in the list output,
2177 * though none are known now (the separate list-status command
2178 * is used for this, but it can also print "UNKNOWN"). To handle
2179 * this possibility, skip such entries.
2180 *
2181 * @TODO Document or eliminate the implied restriction of target
2182 * names.
2183 */
2184 free(entry);
2185
2186 } else {
2187 // We have a valid entry
2188 *output = g_list_append(*output, entry);
2189 }
2190 entry_start = i + 1;
2191 }
2192 }
2193}
2194
2216GList *
2217stonith__parse_targets(const char *target_spec)
2218{
2219 GList *targets = NULL;
2220
2221 if (target_spec != NULL) {
2222 size_t out_len = strlen(target_spec);
2223 size_t line_start = 0; // Starting index of line being processed
2224
2225 for (size_t i = 0; i <= out_len; ++i) {
2226 if ((target_spec[i] == '\n') || (target_spec[i] == '\0')
2227 || ((target_spec[i] == '\\') && (target_spec[i + 1] == 'n'))) {
2228 // We've reached the end of one line of output
2229
2230 int len = i - line_start;
2231
2232 if (len > 0) {
2233 char *line = strndup(target_spec + line_start, len);
2234
2235 line[len] = '\0'; // Because it might be a newline
2236 parse_list_line(line, len, &targets);
2237 free(line);
2238 }
2239 if (target_spec[i] == '\\') {
2240 ++i; // backslash-n takes up two positions
2241 }
2242 line_start = i + 1;
2243 }
2244 }
2245 }
2246 return targets;
2247}
2248
2260const char *
2262 const stonith_history_t *top_history)
2263{
2264 const char *other = NULL;
2265
2266 for (const stonith_history_t *prev_hp = top_history;
2267 prev_hp != NULL; prev_hp = prev_hp->next) {
2268 if (prev_hp == event) {
2269 break;
2270 }
2271 if ((prev_hp->state == st_done) &&
2272 pcmk__str_eq(event->target, prev_hp->target, pcmk__str_casei) &&
2273 pcmk__str_eq(event->action, prev_hp->action, pcmk__str_none) &&
2274 ((event->completed < prev_hp->completed) ||
2275 ((event->completed == prev_hp->completed) && (event->completed_nsec < prev_hp->completed_nsec)))) {
2276
2277 if ((event->delegate == NULL)
2278 || pcmk__str_eq(event->delegate, prev_hp->delegate,
2279 pcmk__str_casei)) {
2280 // Prefer equivalent fencing by same executioner
2281 return prev_hp->delegate;
2282
2283 } else if (other == NULL) {
2284 // Otherwise remember first successful executioner
2285 other = (prev_hp->delegate == NULL)? "some node" : prev_hp->delegate;
2286 }
2287 }
2288 }
2289 return other;
2290}
2291
2302{
2303 stonith_history_t *new = NULL, *pending = NULL, *hp, *np, *tmp;
2304
2305 for (hp = history; hp; ) {
2306 tmp = hp->next;
2307 if ((hp->state == st_done) || (hp->state == st_failed)) {
2308 /* sort into new */
2309 if ((!new) || (hp->completed > new->completed) ||
2310 ((hp->completed == new->completed) && (hp->completed_nsec > new->completed_nsec))) {
2311 hp->next = new;
2312 new = hp;
2313 } else {
2314 np = new;
2315 do {
2316 if ((!np->next) || (hp->completed > np->next->completed) ||
2317 ((hp->completed == np->next->completed) && (hp->completed_nsec > np->next->completed_nsec))) {
2318 hp->next = np->next;
2319 np->next = hp;
2320 break;
2321 }
2322 np = np->next;
2323 } while (1);
2324 }
2325 } else {
2326 /* put into pending */
2327 hp->next = pending;
2328 pending = hp;
2329 }
2330 hp = tmp;
2331 }
2332
2333 /* pending actions don't have a completed-stamp so make them go front */
2334 if (pending) {
2335 stonith_history_t *last_pending = pending;
2336
2337 while (last_pending->next) {
2338 last_pending = last_pending->next;
2339 }
2340
2341 last_pending->next = new;
2342 new = pending;
2343 }
2344 return new;
2345}
2346
2354const char *
2356{
2357 switch (state) {
2358 case st_query: return "querying";
2359 case st_exec: return "executing";
2360 case st_done: return "completed";
2361 case st_duplicate: return "duplicate";
2362 case st_failed: return "failed";
2363 }
2364 return "unknown";
2365}
2366
2369 bool (*matching_fn)(stonith_history_t *, void *),
2370 void *user_data)
2371{
2372 for (stonith_history_t *hp = history; hp; hp = hp->next) {
2373 if (matching_fn(hp, user_data)) {
2374 return hp;
2375 }
2376 }
2377
2378 return NULL;
2379}
2380
2381bool
2383{
2384 return history->state != st_failed && history->state != st_done;
2385}
2386
2387bool
2389{
2390 return history->state == GPOINTER_TO_INT(user_data);
2391}
2392
2393bool
2395{
2396 return history->state != GPOINTER_TO_INT(user_data);
2397}
2398
2399void
2400stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name,
2401 xmlNode *metadata)
2402{
2403 xmlXPathObjectPtr xpath = NULL;
2404 int max = 0;
2405 int lpc = 0;
2406
2407 CRM_CHECK((device_flags != NULL) && (metadata != NULL), return);
2408
2409 xpath = xpath_search(metadata, "//parameter");
2410 max = numXpathResults(xpath);
2411
2412 if (max <= 0) {
2413 freeXpathObject(xpath);
2414 return;
2415 }
2416
2417 for (lpc = 0; lpc < max; lpc++) {
2418 const char *parameter = NULL;
2419 xmlNode *match = getXpathResult(xpath, lpc);
2420
2421 CRM_LOG_ASSERT(match != NULL);
2422 if (match == NULL) {
2423 continue;
2424 }
2425
2426 parameter = crm_element_value(match, "name");
2427
2428 if (pcmk__str_eq(parameter, "plug", pcmk__str_casei)) {
2429 stonith__set_device_flags(*device_flags, device_name,
2431
2432 } else if (pcmk__str_eq(parameter, "port", pcmk__str_casei)) {
2433 stonith__set_device_flags(*device_flags, device_name,
2435 }
2436 }
2437
2438 freeXpathObject(xpath);
2439}
2440
2460int
2461stonith__metadata_async(const char *agent, int timeout_sec,
2462 void (*callback)(int pid,
2464 void *user_data),
2465 void *user_data)
2466{
2467 switch (stonith_get_namespace(agent, NULL)) {
2468 case st_namespace_rhcs:
2469 {
2470 stonith_action_t *action = NULL;
2471 int rc = pcmk_ok;
2472
2473 action = stonith__action_create(agent, "metadata", NULL, 0,
2474 timeout_sec, NULL, NULL, NULL);
2475
2476 rc = stonith__execute_async(action, user_data, callback, NULL);
2477 if (rc != pcmk_ok) {
2478 callback(0, stonith__action_result(action), user_data);
2480 }
2481 return pcmk_legacy2rc(rc);
2482 }
2483
2484#if HAVE_STONITH_STONITH_H
2485 case st_namespace_lha:
2486 // LHA metadata is simply synthesized, so simulate async
2487 {
2490 .execution_status = PCMK_EXEC_DONE,
2491 .exit_reason = NULL,
2492 .action_stdout = NULL,
2493 .action_stderr = NULL,
2494 };
2495
2496 stonith__lha_metadata(agent, timeout_sec,
2498 callback(0, &result, user_data);
2500 return pcmk_rc_ok;
2501 }
2502#endif
2503
2504 default:
2505 {
2508 .execution_status = PCMK_EXEC_ERROR_HARD,
2509 .exit_reason = crm_strdup_printf("No such agent '%s'",
2510 agent),
2511 .action_stdout = NULL,
2512 .action_stderr = NULL,
2513 };
2514
2515 callback(0, &result, user_data);
2517 return ENOENT;
2518 }
2519 }
2520}
2521
2530int
2532{
2533 if ((data == NULL) || (data->opaque == NULL)) {
2534 return CRM_EX_ERROR;
2535 }
2536 return ((pcmk__action_result_t *) data->opaque)->exit_status;
2537}
2538
2547int
2549{
2550 if ((data == NULL) || (data->opaque == NULL)) {
2551 return PCMK_EXEC_UNKNOWN;
2552 }
2553 return ((pcmk__action_result_t *) data->opaque)->execution_status;
2554}
2555
2564const char *
2566{
2567 if ((data == NULL) || (data->opaque == NULL)) {
2568 return NULL;
2569 }
2570 return ((pcmk__action_result_t *) data->opaque)->exit_reason;
2571}
2572
2581int
2583{
2584 if ((event == NULL) || (event->opaque == NULL)) {
2585 return CRM_EX_ERROR;
2586 } else {
2587 struct event_private *event_private = event->opaque;
2588
2589 return event_private->result.exit_status;
2590 }
2591}
2592
2601int
2603{
2604 if ((event == NULL) || (event->opaque == NULL)) {
2605 return PCMK_EXEC_UNKNOWN;
2606 } else {
2607 struct event_private *event_private = event->opaque;
2608
2609 return event_private->result.execution_status;
2610 }
2611}
2612
2621const char *
2623{
2624 if ((event == NULL) || (event->opaque == NULL)) {
2625 return NULL;
2626 } else {
2627 struct event_private *event_private = event->opaque;
2628
2629 return event_private->result.exit_reason;
2630 }
2631}
2632
2643char *
2645{
2646 // Use somewhat readable defaults
2647 const char *origin = pcmk__s(event->client_origin, "a client");
2648 const char *origin_node = pcmk__s(event->origin, "a node");
2649 const char *executioner = pcmk__s(event->executioner, "the cluster");
2650 const char *device = pcmk__s(event->device, "unknown");
2651 const char *action = pcmk__s(event->action, event->operation);
2652 const char *target = pcmk__s(event->target, "no node");
2653 const char *reason = stonith__event_exit_reason(event);
2654 const char *status;
2655
2656 if (action == NULL) {
2657 action = "(unknown)";
2658 }
2659
2661 status = pcmk_exec_status_str(stonith__event_execution_status(event));
2662 } else if (stonith__event_exit_status(event) != CRM_EX_OK) {
2663 status = pcmk_exec_status_str(PCMK_EXEC_ERROR);
2664 } else {
2665 status = crm_exit_str(CRM_EX_OK);
2666 }
2667
2668 if (pcmk__str_eq(event->operation, T_STONITH_NOTIFY_HISTORY,
2669 pcmk__str_none)) {
2670 return crm_strdup_printf("Fencing history may have changed");
2671
2672 } else if (pcmk__str_eq(event->operation, STONITH_OP_DEVICE_ADD,
2673 pcmk__str_none)) {
2674 return crm_strdup_printf("A fencing device (%s) was added", device);
2675
2676 } else if (pcmk__str_eq(event->operation, STONITH_OP_DEVICE_DEL,
2677 pcmk__str_none)) {
2678 return crm_strdup_printf("A fencing device (%s) was removed", device);
2679
2680 } else if (pcmk__str_eq(event->operation, STONITH_OP_LEVEL_ADD,
2681 pcmk__str_none)) {
2682 return crm_strdup_printf("A fencing topology level (%s) was added",
2683 device);
2684
2685 } else if (pcmk__str_eq(event->operation, STONITH_OP_LEVEL_DEL,
2686 pcmk__str_none)) {
2687 return crm_strdup_printf("A fencing topology level (%s) was removed",
2688 device);
2689 }
2690
2691 // event->operation should be T_STONITH_NOTIFY_FENCE at this point
2692
2693 return crm_strdup_printf("Operation %s of %s by %s for %s@%s: %s%s%s%s (ref=%s)",
2694 action, target, executioner, origin, origin_node,
2695 status,
2696 ((reason == NULL)? "" : " ("), pcmk__s(reason, ""),
2697 ((reason == NULL)? "" : ")"),
2698 pcmk__s(event->id, "(none)"));
2699}
2700
2701
2702// Deprecated functions kept only for backward API compatibility
2703// LCOV_EXCL_START
2704
2705const char *get_stonith_provider(const char *agent, const char *provider);
2706
2707const char *
2708get_stonith_provider(const char *agent, const char *provider)
2709{
2710 return stonith_namespace2text(stonith_get_namespace(agent, provider));
2711}
2712
2713// LCOV_EXCL_STOP
2714// End deprecated API
#define PCMK_ACTION_STATUS
Definition actions.h:72
#define PCMK_ACTION_LIST
Definition actions.h:52
#define PCMK_ACTION_REBOOT
Definition actions.h:67
#define PCMK_ACTION_MONITOR
Definition actions.h:59
#define PCMK_DEFAULT_METADATA_TIMEOUT_MS
Definition actions.h:42
#define PCMK_ACTION_ON
Definition actions.h:63
#define PCMK_ACTION_OFF
Definition actions.h:62
#define PCMK_STONITH_HOST_ARGUMENT
Definition agents.h:44
bool pcmk_stonith_param(const char *param)
Check whether a given stonith parameter is handled by Pacemaker.
Definition agents.c:174
const char * name
Definition cib.c:26
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
uint32_t pid
Definition cpg.c:1
A dumping ground.
#define CRM_OP_REGISTER
Definition crm.h:144
#define F_STONITH_DATE_NSEC
Definition internal.h:148
int stonith__legacy2status(int rc)
Definition st_actions.c:404
#define F_STONITH_HISTORY_LIST
Definition internal.h:146
#define F_STONITH_ORIGIN
Definition internal.h:145
int stonith__execute_async(stonith_action_t *action, void *userdata, void(*done)(int pid, const pcmk__action_result_t *result, void *user_data), void(*fork_cb)(int pid, void *user_data))
Definition st_actions.c:671
#define T_STONITH_TIMEOUT_VALUE
Definition internal.h:162
@ 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:169
#define STONITH_OP_FENCE
Definition internal.h:170
#define F_STONITH_DELAY
Definition internal.h:118
#define F_STONITH_CLIENTID
Definition internal.h:105
void stonith__destroy_action(stonith_action_t *action)
Definition st_actions.c:217
#define F_STONITH_REMOTE_OP_ID
Definition internal.h:111
#define STONITH_OP_DEVICE_ADD
Definition internal.h:172
#define F_STONITH_DEVICE
Definition internal.h:153
#define F_STONITH_DATE
Definition internal.h:147
stonith_action_t * stonith__action_create(const char *agent, const char *action_name, const char *target, uint32_t target_nodeid, int timeout_sec, GHashTable *device_args, GHashTable *port_map, const char *host_arg)
Definition st_actions.c:265
#define F_STONITH_TOLERANCE
Definition internal.h:117
#define STONITH_OP_EXEC
Definition internal.h:167
#define F_STONITH_TARGET
Definition internal.h:110
#define stonith__set_device_flags(device_flags, device_id, flags_to_set)
Definition internal.h:29
#define F_STONITH_NOTIFY_ACTIVATE
Definition internal.h:137
#define F_STONITH_NOTIFY_DEACTIVATE
Definition internal.h:138
#define F_STONITH_STATE
Definition internal.h:149
#define F_STONITH_CALLDATA
Definition internal.h:108
#define T_STONITH_NG
Definition internal.h:157
#define STONITH_WATCHDOG_ID
Definition internal.h:181
#define F_STONITH_CLIENTNAME
Definition internal.h:135
#define F_STONITH_DELEGATE
Definition internal.h:139
#define F_STONITH_ACTION
Definition internal.h:154
#define STONITH_OP_LEVEL_ADD
Definition internal.h:175
#define T_STONITH_NOTIFY
Definition internal.h:163
#define STONITH_OP_FENCE_HISTORY
Definition internal.h:174
pcmk__action_result_t * stonith__action_result(stonith_action_t *action)
Definition st_actions.c:242
struct stonith_action_s stonith_action_t
Definition internal.h:51
#define stonith__set_call_options(st_call_opts, call_for, flags_to_set)
Definition internal.h:36
#define F_STONITH_OUTPUT
Definition internal.h:114
void stonith__xe_get_result(const xmlNode *xml, pcmk__action_result_t *result)
Definition st_actions.c:494
#define STONITH_OP_LEVEL_DEL
Definition internal.h:176
int stonith__result2rc(const pcmk__action_result_t *result)
Definition st_actions.c:330
#define F_STONITH_OPERATION
Definition internal.h:109
#define F_STONITH_CALLBACK_TOKEN
Definition internal.h:134
#define F_STONITH_CALLOPTS
Definition internal.h:106
#define STONITH_OP_DEVICE_DEL
Definition internal.h:173
#define F_STONITH_CALLID
Definition internal.h:107
#define F_STONITH_TIMEOUT
Definition internal.h:116
G_GNUC_INTERNAL bool stonith__agent_is_rhcs(const char *agent)
Definition st_rhcs.c:246
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:257
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)
Retrieve metadata for RHCS-compatible fence agent.
Definition st_rhcs.c:220
void crm_ipc_destroy(crm_ipc_t *client)
int crm_ipc_send(crm_ipc_t *client, const xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
long crm_ipc_read(crm_ipc_t *client)
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.
bool crm_ipc_connected(crm_ipc_t *client)
void crm_ipc_close(crm_ipc_t *client)
Definition ipc_client.c:992
const char * crm_ipc_buffer(crm_ipc_t *client)
struct crm_ipc_s crm_ipc_t
Definition ipc.h:165
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:849
int pcmk__connect_generic_ipc(crm_ipc_t *ipc)
Definition ipc_client.c:895
int pcmk__ipc_fd(crm_ipc_t *ipc, int *fd)
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
#define CRM_TRACE_INIT_DATA(name)
Definition logging.h:137
#define crm_info(fmt, args...)
Definition logging.h:382
#define crm_warn(fmt, args...)
Definition logging.h:380
#define CRM_XS
Definition logging.h:56
#define crm_log_xml_debug(xml, text)
Definition logging.h:392
#define CRM_LOG_ASSERT(expr)
Definition logging.h:222
#define crm_log_xml_err(xml, text)
Definition logging.h:388
#define crm_notice(fmt, args...)
Definition logging.h:381
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition logging.h:323
#define CRM_CHECK(expr, failure_action)
Definition logging.h:238
#define crm_debug(fmt, args...)
Definition logging.h:384
#define crm_err(fmt, args...)
Definition logging.h:379
#define LOG_NEVER
Definition logging.h:48
#define crm_log_xml_trace(xml, text)
Definition logging.h:393
#define crm_log_xml_warn(xml, text)
Definition logging.h:389
#define crm_trace(fmt, args...)
Definition logging.h:385
#define crm_log_xml_notice(xml, text)
Definition logging.h:390
Wrappers for and extensions to glib mainloop.
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition mainloop.c:950
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:919
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:944
#define F_SUBTYPE
Definition msg_xml.h:87
#define XML_ATTR_STONITH_TARGET_ATTRIBUTE
Definition msg_xml.h:459
#define XML_TAG_FENCING_LEVEL
Definition msg_xml.h:454
#define F_XML_TAGNAME
Definition msg_xml.h:99
#define XML_ATTR_ID
Definition msg_xml.h:156
#define XML_LRM_ATTR_EXIT_REASON
Definition msg_xml.h:324
#define XML_ATTR_STONITH_INDEX
Definition msg_xml.h:455
#define XML_TAG_ATTRS
Definition msg_xml.h:229
#define F_TYPE
Definition msg_xml.h:91
#define XML_ATTR_STONITH_DEVICES
Definition msg_xml.h:460
#define XML_ATTR_STONITH_TARGET_PATTERN
Definition msg_xml.h:458
#define XML_ATTR_STONITH_TARGET_VALUE
Definition msg_xml.h:457
#define XML_ATTR_STONITH_TARGET
Definition msg_xml.h:456
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:447
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition nvpair.c:483
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition nvpair.c:700
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:349
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition nvpair.c:644
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:515
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:302
unsigned int timeout
Definition pcmk_fence.c:32
int delay
Definition pcmk_fence.c:34
unsigned int tolerance
Definition pcmk_fence.c:33
stonith_t * st
Definition pcmk_fence.c:28
const char * action
Definition pcmk_fence.c:30
pcmk__action_result_t result
Definition pcmk_fence.c:35
const char * target
Definition pcmk_fence.c:29
#define ECOMM
Definition portability.h:86
#define ENOTUNIQ
Definition portability.h:81
const char * pcmk_strerror(int rc)
Definition results.c:149
#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:501
@ CRM_EX_NOSUCH
Requested item does not exist.
Definition results.h:276
@ CRM_EX_ERROR
Unspecified error.
Definition results.h:241
@ CRM_EX_OK
Success.
Definition results.h:240
@ pcmk_rc_ok
Definition results.h:154
#define pcmk_ok
Definition results.h:68
int pcmk_rc2legacy(int rc)
Definition results.c:546
const char * crm_exit_str(crm_exit_t exit_code)
Definition results.c:640
@ PCMK_EXEC_DONE
Action completed, result is known.
Definition results.h:318
@ PCMK_EXEC_ERROR
Execution failed, may be retried.
Definition results.h:322
@ PCMK_EXEC_TIMEOUT
Action did not complete in time.
Definition results.h:320
@ PCMK_EXEC_UNKNOWN
Used only to initialize variables.
Definition results.h:316
@ PCMK_EXEC_ERROR_HARD
Execution failed, do not retry on node.
Definition results.h:323
int pcmk_legacy2rc(int legacy_rc)
Definition results.c:559
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:976
#define PCMK__UNKNOWN_RESULT
void pcmk__reset_result(pcmk__action_result_t *result)
Definition results.c:1065
int stonith__metadata_async(const char *agent, int timeout_sec, void(*callback)(int pid, const pcmk__action_result_t *result, void *user_data), void *user_data)
Definition st_client.c:2461
void stonith_api_delete(stonith_t *stonith)
Definition st_client.c:1720
gboolean stonith__watchdog_fencing_enabled_for_node(const char *node)
Definition st_client.c:231
const char * stonith__exit_reason(const stonith_callback_data_t *data)
Definition st_client.c:2565
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:2013
char * stonith__event_description(const stonith_event_t *event)
Definition st_client.c:2644
stonith_key_value_t * stonith_key_value_add(stonith_key_value_t *head, const char *key, const char *value)
Definition st_client.c:1927
xmlNode * create_device_registration_xml(const char *id, enum stonith_namespace namespace, const char *agent, const stonith_key_value_t *params, const char *rsc_provides)
Definition st_client.c:293
bool stonith__event_state_pending(stonith_history_t *history, void *user_data)
Definition st_client.c:2382
GList * stonith__parse_targets(const char *target_spec)
Definition st_client.c:2217
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:806
void stonith_history_free(stonith_history_t *history)
Definition st_client.c:759
bool stonith__event_state_neq(stonith_history_t *history, void *user_data)
Definition st_client.c:2394
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:2400
bool stonith__event_state_eq(stonith_history_t *history, void *user_data)
Definition st_client.c:2388
const char * stonith_action_str(const char *action)
Turn fence action into a more readable string.
Definition st_client.c:2108
xmlNode * create_level_registration_xml(const char *node, const char *pattern, const char *attr, const char *value, int level, const stonith_key_value_t *device_list)
Definition st_client.c:415
bool stonith_dispatch(stonith_t *st)
Definition st_client.c:1660
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:1906
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:2368
#define api_log(level, fmt, args...)
Definition st_client.c:1968
int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
Definition st_client.c:1971
int stonith__exit_status(const stonith_callback_data_t *data)
Definition st_client.c:2531
const char * get_stonith_provider(const char *agent, const char *provider)
Definition st_client.c:2708
stonith_history_t * stonith__sort_history(stonith_history_t *history)
Definition st_client.c:2301
gboolean stonith__watchdog_fencing_enabled_for_node_api(stonith_t *st, const char *node)
Definition st_client.c:172
int stonith__execution_status(const stonith_callback_data_t *data)
Definition st_client.c:2548
int(* stonith_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition st_client.c:82
int stonith__event_exit_status(const stonith_event_t *event)
Definition st_client.c:2582
int stonith__event_execution_status(const stonith_event_t *event)
Definition st_client.c:2602
stonith_t * stonith_api_new(void)
Definition st_client.c:1828
#define api_log_open()
Definition st_client.c:1967
const char * stonith__later_succeeded(const stonith_history_t *event, const stonith_history_t *top_history)
Definition st_client.c:2261
const char * stonith__event_exit_reason(const stonith_event_t *event)
Definition st_client.c:2622
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:1950
struct stonith_callback_client_s stonith_callback_client_t
bool stonith_agent_exists(const char *agent, int timeout)
Definition st_client.c:2077
void stonith_dump_pending_callbacks(stonith_t *stonith)
Definition st_client.c:1364
const char * stonith_op_state_str(enum op_state state)
Return string equivalent of an operation state value.
Definition st_client.c:2355
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:275
bool stonith__agent_is_lha(const char *agent)
Definition st_lha.c:83
Fencing aka. STONITH.
#define T_STONITH_NOTIFY_HISTORY
Definition stonith-ng.h:37
#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
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition strings.c:888
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:608
void pcmk__str_update(char **str, const char *value)
Definition strings.c:1193
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:933
@ pcmk__str_none
@ pcmk__str_null_matches
@ pcmk__str_casei
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:957
void pcmk__add_separated_word(GString **list, size_t init_size, const char *word, const char *separator)
Definition strings.c:700
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 *stonith, int call_options, const char *node, const char *action, int timeout, int tolerance, int delay)
Request delayed fencing of a target.
Definition stonith-ng.h:542
int(* register_level)(stonith_t *st, int options, const char *node, int level, const stonith_key_value_t *device_list)
Register a fencing level for specified node with local fencer.
Definition stonith-ng.h:238
int(* free)(stonith_t *st)
Destroy a fencer connection.
Definition stonith-ng.h:157
int(* register_callback)(stonith_t *stonith, int call_id, int timeout, int options, void *user_data, const char *callback_name, void(*callback)(stonith_t *st, stonith_callback_data_t *data))
Register a callback for an asynchronous fencing result.
Definition stonith-ng.h:428
int(* query)(stonith_t *stonith, int call_options, const char *target, stonith_key_value_t **devices, int timeout)
List registered fence devices.
Definition stonith-ng.h:341
int(* register_notification)(stonith_t *stonith, const char *event, void(*callback)(stonith_t *st, stonith_event_t *e))
Register a callback for fence notifications.
Definition stonith-ng.h:397
int(* metadata)(stonith_t *stonith, int call_options, const char *agent, const char *namespace, char **output, int timeout_sec)
Retrieve a fence agent's metadata.
Definition stonith-ng.h:258
int(* connect)(stonith_t *st, const char *name, int *stonith_fd)
Connect to the local fencer.
Definition stonith-ng.h:169
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:223
int(* disconnect)(stonith_t *st)
Disconnect from the local stonith daemon.
Definition stonith-ng.h:178
int(* list)(stonith_t *stonith, int call_options, const char *id, char **list_info, int timeout)
Get the output of a fence device's list action.
Definition stonith-ng.h:295
int(* remove_callback)(stonith_t *stonith, int call_id, bool all_callbacks)
Unregister callbacks for asynchronous fencing results.
Definition stonith-ng.h:444
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:467
int(* fence)(stonith_t *stonith, int call_options, const char *node, const char *action, int timeout, int tolerance)
Request that a target get fenced.
Definition stonith-ng.h:359
int(* list_agents)(stonith_t *stonith, int call_options, const char *namespace, stonith_key_value_t **devices, int timeout)
Retrieve a list of installed fence agents.
Definition stonith-ng.h:279
int(* confirm)(stonith_t *stonith, int call_options, const char *target)
Manually confirm that a node has been fenced.
Definition stonith-ng.h:372
int(* status)(stonith_t *stonith, int call_options, const char *id, const char *port, int timeout)
Check whether a fence device target is reachable by status action.
Definition stonith-ng.h:324
int(* register_level_full)(stonith_t *st, int options, const char *node, const char *pattern, const char *attr, const char *value, int level, const stonith_key_value_t *device_list)
Register fencing level for specified node, pattern or attribute.
Definition stonith-ng.h:494
int(* validate)(stonith_t *st, int call_options, const char *rsc_id, const char *namespace_s, const char *agent, const stonith_key_value_t *params, int timeout, char **output, char **error_output)
Validate an arbitrary stonith device configuration.
Definition stonith-ng.h:519
int(* monitor)(stonith_t *stonith, int call_options, const char *id, int timeout)
Check whether a fence device is reachable by monitor action.
Definition stonith-ng.h:309
int(* remove_notification)(stonith_t *stonith, const char *event)
Unregister callbacks for fence notifications.
Definition stonith-ng.h:409
int(* remove_device)(stonith_t *st, int options, const char *name)
Unregister a fence device with the local fencer.
Definition stonith-ng.h:190
int(* register_device)(stonith_t *st, int options, const char *id, const char *namespace, const char *agent, const stonith_key_value_t *params)
Register a fence device with the local fencer.
Definition stonith-ng.h:208
int(* history)(stonith_t *stonith, int call_options, const char *node, stonith_history_t **history, int timeout)
List fencing actions that have occurred for a target.
Definition stonith-ng.h:385
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
enum stonith_state state
Definition stonith-ng.h:550
void * st_private
Definition stonith-ng.h:554
stonith_api_operations_t * cmds
Definition stonith-ng.h:556
guint ref
Definition internal.h:149
stonith_t * stonith
Definition st_client.c:79
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition xpath.c:211
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:160
xmlNode * string2xml(const char *input)
Definition xml.c:800
void free_xml(xmlNode *child)
Definition xml.c:783
xmlXPathObjectPtr xpath_search(const xmlNode *xml_top, const char *path)
Definition xpath.c:139
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition xml.c:638