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