pacemaker 2.1.6-6fdc9deea29
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
st_client.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2022 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <stdbool.h>
15#include <string.h>
16#include <ctype.h>
17#include <inttypes.h>
18#include <sys/types.h>
19#include <glib.h>
20
21#include <crm/crm.h>
22#include <crm/stonith-ng.h>
24#include <crm/msg_xml.h>
25
26#include <crm/common/mainloop.h>
27
28#include "fencing_private.h"
29
31
32// Used as stonith_t:st_private
33typedef struct stonith_private_s {
34 char *token;
35 crm_ipc_t *ipc;
36 mainloop_io_t *source;
37 GHashTable *stonith_op_callback_table;
38 GList *notify_list;
39 int notify_refcnt;
40 bool notify_deletes;
41
42 void (*op_callback) (stonith_t * st, stonith_callback_data_t * data);
43
45
46// Used as stonith_event_t:opaque
47struct event_private {
49};
50
51typedef struct stonith_notify_client_s {
52 const char *event;
53 const char *obj_id; /* implement one day */
54 const char *obj_type; /* implement one day */
55 void (*notify) (stonith_t * st, stonith_event_t * e);
56 bool delete;
57
59
60typedef struct stonith_callback_client_s {
61 void (*callback) (stonith_t * st, stonith_callback_data_t * data);
62 const char *id;
63 void *user_data;
64 gboolean only_success;
65 gboolean allow_timeout_updates;
66 struct timer_rec_s *timer;
67
69
70struct notify_blob_s {
71 stonith_t *stonith;
72 xmlNode *xml;
73};
74
75struct timer_rec_s {
76 int call_id;
77 int timeout;
78 guint ref;
80};
81
82typedef int (*stonith_op_t) (const char *, int, const char *, xmlNode *,
83 xmlNode *, xmlNode *, xmlNode **, xmlNode **);
84
86xmlNode *stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data,
87 int call_options);
88static int stonith_send_command(stonith_t *stonith, const char *op,
89 xmlNode *data, xmlNode **output_data,
90 int call_options, int timeout);
91
92static void stonith_connection_destroy(gpointer user_data);
93static void stonith_send_notification(gpointer data, gpointer user_data);
94static int stonith_api_del_notification(stonith_t *stonith,
95 const char *event);
104stonith_text2namespace(const char *namespace_s)
105{
106 if (pcmk__str_eq(namespace_s, "any", pcmk__str_null_matches)) {
107 return st_namespace_any;
108
109 } else if (!strcmp(namespace_s, "redhat")
110 || !strcmp(namespace_s, "stonith-ng")) {
111 return st_namespace_rhcs;
112
113 } else if (!strcmp(namespace_s, "internal")) {
115
116 } else if (!strcmp(namespace_s, "heartbeat")) {
117 return st_namespace_lha;
118 }
120}
121
129const char *
131{
132 switch (st_namespace) {
133 case st_namespace_any: return "any";
134 case st_namespace_rhcs: return "stonith-ng";
135 case st_namespace_internal: return "internal";
136 case st_namespace_lha: return "heartbeat";
137 default: break;
138 }
139 return "unsupported";
140}
141
151stonith_get_namespace(const char *agent, const char *namespace_s)
152{
153 if (pcmk__str_eq(namespace_s, "internal", pcmk__str_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) {
518 timeout_sec = CRMD_METADATA_CALL_TIMEOUT;
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, "list", NULL, timeout, &output);
629
630 if (output && list_info) {
631 const char *list_str;
632
633 list_str = crm_element_value(output, F_STONITH_OUTPUT);
634
635 if (list_str) {
636 *list_info = strdup(list_str);
637 }
638 }
639
640 if (output) {
641 free_xml(output);
642 }
643
644 return rc;
645}
646
647static int
648stonith_api_monitor(stonith_t * stonith, int call_options, const char *id, int timeout)
649{
650 return stonith_api_call(stonith, call_options, id, "monitor", NULL, timeout, NULL);
651}
652
653static int
654stonith_api_status(stonith_t * stonith, int call_options, const char *id, const char *port,
655 int timeout)
656{
657 return stonith_api_call(stonith, call_options, id, "status", port, timeout, NULL);
658}
659
660static int
661stonith_api_fence_with_delay(stonith_t * stonith, int call_options, const char *node,
662 const char *action, int timeout, int tolerance, int delay)
663{
664 int rc = 0;
665 xmlNode *data = NULL;
666
667 data = create_xml_node(NULL, __func__);
673
674 rc = stonith_send_command(stonith, STONITH_OP_FENCE, data, NULL, call_options, timeout);
675 free_xml(data);
676
677 return rc;
678}
679
680static int
681stonith_api_fence(stonith_t * stonith, int call_options, const char *node, const char *action,
682 int timeout, int tolerance)
683{
684 return stonith_api_fence_with_delay(stonith, call_options, node, action,
685 timeout, tolerance, 0);
686}
687
688static int
689stonith_api_confirm(stonith_t * stonith, int call_options, const char *target)
690{
692 return stonith_api_fence(stonith, call_options, target, "off", 0, 0);
693}
694
695static int
696stonith_api_history(stonith_t * stonith, int call_options, const char *node,
697 stonith_history_t ** history, int timeout)
698{
699 int rc = 0;
700 xmlNode *data = NULL;
701 xmlNode *output = NULL;
702 stonith_history_t *last = NULL;
703
704 *history = NULL;
705
706 if (node) {
707 data = create_xml_node(NULL, __func__);
709 }
710
711 stonith__set_call_options(call_options, node, st_opt_sync_call);
712 rc = stonith_send_command(stonith, STONITH_OP_FENCE_HISTORY, data, &output,
713 call_options, timeout);
714 free_xml(data);
715
716 if (rc == 0) {
717 xmlNode *op = NULL;
718 xmlNode *reply = get_xpath_object("//" F_STONITH_HISTORY_LIST, output,
719 LOG_NEVER);
720
721 for (op = pcmk__xml_first_child(reply); op != NULL;
722 op = pcmk__xml_next(op)) {
724 long long completed;
725 long long completed_nsec = 0L;
726
727 kvp = calloc(1, sizeof(stonith_history_t));
733 crm_element_value_ll(op, F_STONITH_DATE, &completed);
734 kvp->completed = (time_t) completed;
735 crm_element_value_ll(op, F_STONITH_DATE_NSEC, &completed_nsec);
736 kvp->completed_nsec = completed_nsec;
740
741 if (last) {
742 last->next = kvp;
743 } else {
744 *history = kvp;
745 }
746 last = kvp;
747 }
748 }
749
750 free_xml(output);
751
752 return rc;
753}
754
756{
757 stonith_history_t *hp, *hp_old;
758
759 for (hp = history; hp; hp_old = hp, hp = hp->next, free(hp_old)) {
760 free(hp->target);
761 free(hp->action);
762 free(hp->origin);
763 free(hp->delegate);
764 free(hp->client);
765 free(hp->exit_reason);
766 }
767}
768
769static gint
770stonithlib_GCompareFunc(gconstpointer a, gconstpointer b)
771{
772 int rc = 0;
773 const stonith_notify_client_t *a_client = a;
774 const stonith_notify_client_t *b_client = b;
775
776 if (a_client->delete || b_client->delete) {
777 /* make entries marked for deletion not findable */
778 return -1;
779 }
780 CRM_CHECK(a_client->event != NULL && b_client->event != NULL, return 0);
781 rc = strcmp(a_client->event, b_client->event);
782 if (rc == 0) {
783 if (a_client->notify == NULL || b_client->notify == NULL) {
784 return 0;
785
786 } else if (a_client->notify == b_client->notify) {
787 return 0;
788
789 } else if (((long)a_client->notify) < ((long)b_client->notify)) {
790 crm_err("callbacks for %s are not equal: %p vs. %p",
791 a_client->event, a_client->notify, b_client->notify);
792 return -1;
793 }
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 return rc;
799}
800
801xmlNode *
802stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data, int call_options)
803{
804 xmlNode *op_msg = create_xml_node(NULL, "stonith_command");
805
806 CRM_CHECK(op_msg != NULL, return NULL);
807 CRM_CHECK(token != NULL, return NULL);
808
809 crm_xml_add(op_msg, F_XML_TAGNAME, "stonith_command");
810
813 crm_xml_add(op_msg, F_STONITH_OPERATION, op);
814 crm_xml_add_int(op_msg, F_STONITH_CALLID, call_id);
815 crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
816 crm_xml_add_int(op_msg, F_STONITH_CALLOPTS, call_options);
817
818 if (data != NULL) {
820 }
821
822 return op_msg;
823}
824
825static void
826stonith_destroy_op_callback(gpointer data)
827{
829
830 if (blob->timer && blob->timer->ref > 0) {
831 g_source_remove(blob->timer->ref);
832 }
833 free(blob->timer);
834 free(blob);
835}
836
837static int
838stonith_api_signoff(stonith_t * stonith)
839{
840 stonith_private_t *native = stonith->st_private;
841
842 crm_debug("Disconnecting from the fencer");
843
844 if (native->source != NULL) {
845 /* Attached to mainloop */
846 mainloop_del_ipc_client(native->source);
847 native->source = NULL;
848 native->ipc = NULL;
849
850 } else if (native->ipc) {
851 /* Not attached to mainloop */
852 crm_ipc_t *ipc = native->ipc;
853
854 native->ipc = NULL;
855 crm_ipc_close(ipc);
856 crm_ipc_destroy(ipc);
857 }
858
859 free(native->token); native->token = NULL;
860 stonith->state = stonith_disconnected;
861 return pcmk_ok;
862}
863
864static int
865stonith_api_del_callback(stonith_t * stonith, int call_id, bool all_callbacks)
866{
867 stonith_private_t *private = stonith->st_private;
868
869 if (all_callbacks) {
870 private->op_callback = NULL;
871 g_hash_table_destroy(private->stonith_op_callback_table);
872 private->stonith_op_callback_table = pcmk__intkey_table(stonith_destroy_op_callback);
873
874 } else if (call_id == 0) {
875 private->op_callback = NULL;
876
877 } else {
878 pcmk__intkey_table_remove(private->stonith_op_callback_table, call_id);
879 }
880 return pcmk_ok;
881}
882
894static void
895invoke_fence_action_callback(stonith_t *st, int call_id,
897 void *userdata,
898 void (*callback) (stonith_t *st,
900{
902
903 data.call_id = call_id;
905 data.userdata = userdata;
906 data.opaque = (void *) result;
907
908 callback(st, &data);
909}
910
922static void
923invoke_registered_callbacks(stonith_t *stonith, const xmlNode *msg, int call_id)
924{
925 stonith_private_t *private = NULL;
926 stonith_callback_client_t *cb_info = NULL;
928
929 CRM_CHECK(stonith != NULL, return);
930 CRM_CHECK(stonith->st_private != NULL, return);
931
932 private = stonith->st_private;
933
934 if (msg == NULL) {
935 // Fencer didn't reply in time
937 "Fencer accepted request but did not reply in time");
938 CRM_LOG_ASSERT(call_id > 0);
939
940 } else {
941 // We have the fencer reply
942 if ((crm_element_value_int(msg, F_STONITH_CALLID, &call_id) != 0)
943 || (call_id <= 0)) {
944 crm_log_xml_warn(msg, "Bad fencer reply");
945 }
947 }
948
949 if (call_id > 0) {
950 cb_info = pcmk__intkey_table_lookup(private->stonith_op_callback_table,
951 call_id);
952 }
953
954 if ((cb_info != NULL) && (cb_info->callback != NULL)
955 && (pcmk__result_ok(&result) || !(cb_info->only_success))) {
956 crm_trace("Invoking callback %s for call %d",
957 pcmk__s(cb_info->id, "without ID"), call_id);
958 invoke_fence_action_callback(stonith, call_id, &result,
959 cb_info->user_data, cb_info->callback);
960
961 } else if ((private->op_callback == NULL) && !pcmk__result_ok(&result)) {
962 crm_warn("Fencing action without registered callback failed: %d (%s%s%s)",
964 pcmk_exec_status_str(result.execution_status),
965 ((result.exit_reason == NULL)? "" : ": "),
966 ((result.exit_reason == NULL)? "" : result.exit_reason));
967 crm_log_xml_debug(msg, "Failed fence update");
968 }
969
970 if (private->op_callback != NULL) {
971 crm_trace("Invoking global callback for call %d", call_id);
972 invoke_fence_action_callback(stonith, call_id, &result, NULL,
973 private->op_callback);
974 }
975
976 if (cb_info != NULL) {
977 stonith_api_del_callback(stonith, call_id, FALSE);
978 }
980}
981
982static gboolean
983stonith_async_timeout_handler(gpointer data)
984{
985 struct timer_rec_s *timer = data;
986
987 crm_err("Async call %d timed out after %dms", timer->call_id, timer->timeout);
988 invoke_registered_callbacks(timer->stonith, NULL, timer->call_id);
989
990 /* Always return TRUE, never remove the handler
991 * We do that in stonith_del_callback()
992 */
993 return TRUE;
994}
995
996static void
997set_callback_timeout(stonith_callback_client_t * callback, stonith_t * stonith, int call_id,
998 int timeout)
999{
1000 struct timer_rec_s *async_timer = callback->timer;
1001
1002 if (timeout <= 0) {
1003 return;
1004 }
1005
1006 if (!async_timer) {
1007 async_timer = calloc(1, sizeof(struct timer_rec_s));
1008 callback->timer = async_timer;
1009 }
1010
1011 async_timer->stonith = stonith;
1012 async_timer->call_id = call_id;
1013 /* Allow a fair bit of grace to allow the server to tell us of a timeout
1014 * This is only a fallback
1015 */
1016 async_timer->timeout = (timeout + 60) * 1000;
1017 if (async_timer->ref) {
1018 g_source_remove(async_timer->ref);
1019 }
1020 async_timer->ref =
1021 g_timeout_add(async_timer->timeout, stonith_async_timeout_handler, async_timer);
1022}
1023
1024static void
1025update_callback_timeout(int call_id, int timeout, stonith_t * st)
1026{
1027 stonith_callback_client_t *callback = NULL;
1028 stonith_private_t *private = st->st_private;
1029
1030 callback = pcmk__intkey_table_lookup(private->stonith_op_callback_table,
1031 call_id);
1032 if (!callback || !callback->allow_timeout_updates) {
1033 return;
1034 }
1035
1036 set_callback_timeout(callback, st, call_id, timeout);
1037}
1038
1039static int
1040stonith_dispatch_internal(const char *buffer, ssize_t length, gpointer userdata)
1041{
1042 const char *type = NULL;
1043 struct notify_blob_s blob;
1044
1045 stonith_t *st = userdata;
1046 stonith_private_t *private = NULL;
1047
1048 CRM_ASSERT(st != NULL);
1049 private = st->st_private;
1050
1051 blob.stonith = st;
1052 blob.xml = string2xml(buffer);
1053 if (blob.xml == NULL) {
1054 crm_warn("Received malformed message from fencer: %s", buffer);
1055 return 0;
1056 }
1057
1058 /* do callbacks */
1059 type = crm_element_value(blob.xml, F_TYPE);
1060 crm_trace("Activating %s callbacks...", type);
1061
1062 if (pcmk__str_eq(type, T_STONITH_NG, pcmk__str_none)) {
1063 invoke_registered_callbacks(st, blob.xml, 0);
1064
1065 } else if (pcmk__str_eq(type, T_STONITH_NOTIFY, pcmk__str_none)) {
1066 foreach_notify_entry(private, stonith_send_notification, &blob);
1067 } else if (pcmk__str_eq(type, T_STONITH_TIMEOUT_VALUE, pcmk__str_none)) {
1068 int call_id = 0;
1069 int timeout = 0;
1070
1072 crm_element_value_int(blob.xml, F_STONITH_CALLID, &call_id);
1073
1074 update_callback_timeout(call_id, timeout, st);
1075 } else {
1076 crm_err("Unknown message type: %s", type);
1077 crm_log_xml_warn(blob.xml, "BadReply");
1078 }
1079
1080 free_xml(blob.xml);
1081 return 1;
1082}
1083
1084static int
1085stonith_api_signon(stonith_t * stonith, const char *name, int *stonith_fd)
1086{
1087 int rc = pcmk_ok;
1088 stonith_private_t *native = NULL;
1089 const char *display_name = name? name : "client";
1090
1091 struct ipc_client_callbacks st_callbacks = {
1092 .dispatch = stonith_dispatch_internal,
1093 .destroy = stonith_connection_destroy
1094 };
1095
1096 CRM_CHECK(stonith != NULL, return -EINVAL);
1097
1098 native = stonith->st_private;
1099 CRM_ASSERT(native != NULL);
1100
1101 crm_debug("Attempting fencer connection by %s with%s mainloop",
1102 display_name, (stonith_fd? "out" : ""));
1103
1105 if (stonith_fd) {
1106 /* No mainloop */
1107 native->ipc = crm_ipc_new("stonith-ng", 0);
1108
1109 if (native->ipc && crm_ipc_connect(native->ipc)) {
1110 *stonith_fd = crm_ipc_get_fd(native->ipc);
1111 } else if (native->ipc) {
1112 crm_ipc_close(native->ipc);
1113 crm_ipc_destroy(native->ipc);
1114 native->ipc = NULL;
1115 }
1116
1117 } else {
1118 /* With mainloop */
1119 native->source =
1120 mainloop_add_ipc_client("stonith-ng", G_PRIORITY_MEDIUM, 0, stonith, &st_callbacks);
1121 native->ipc = mainloop_get_ipc_client(native->source);
1122 }
1123
1124 if (native->ipc == NULL) {
1125 rc = -ENOTCONN;
1126 } else {
1127 xmlNode *reply = NULL;
1128 xmlNode *hello = create_xml_node(NULL, "stonith_command");
1129
1133 rc = crm_ipc_send(native->ipc, hello, crm_ipc_client_response, -1, &reply);
1134
1135 if (rc < 0) {
1136 crm_debug("Couldn't register with the fencer: %s "
1137 CRM_XS " rc=%d", pcmk_strerror(rc), rc);
1138 rc = -ECOMM;
1139
1140 } else if (reply == NULL) {
1141 crm_debug("Couldn't register with the fencer: no reply");
1142 rc = -EPROTO;
1143
1144 } else {
1145 const char *msg_type = crm_element_value(reply, F_STONITH_OPERATION);
1146
1147 native->token = crm_element_value_copy(reply, F_STONITH_CLIENTID);
1148 if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_none)) {
1149 crm_debug("Couldn't register with the fencer: invalid reply type '%s'",
1150 (msg_type? msg_type : "(missing)"));
1151 crm_log_xml_debug(reply, "Invalid fencer reply");
1152 rc = -EPROTO;
1153
1154 } else if (native->token == NULL) {
1155 crm_debug("Couldn't register with the fencer: no token in reply");
1156 crm_log_xml_debug(reply, "Invalid fencer reply");
1157 rc = -EPROTO;
1158
1159 } else {
1160 crm_debug("Connection to fencer by %s succeeded (registration token: %s)",
1161 display_name, native->token);
1162 rc = pcmk_ok;
1163 }
1164 }
1165
1166 free_xml(reply);
1167 free_xml(hello);
1168 }
1169
1170 if (rc != pcmk_ok) {
1171 crm_debug("Connection attempt to fencer by %s failed: %s "
1172 CRM_XS " rc=%d", display_name, pcmk_strerror(rc), rc);
1173 stonith->cmds->disconnect(stonith);
1174 }
1175 return rc;
1176}
1177
1178static int
1179stonith_set_notification(stonith_t * stonith, const char *callback, int enabled)
1180{
1181 int rc = pcmk_ok;
1182 xmlNode *notify_msg = create_xml_node(NULL, __func__);
1183 stonith_private_t *native = stonith->st_private;
1184
1185 if (stonith->state != stonith_disconnected) {
1186
1188 if (enabled) {
1189 crm_xml_add(notify_msg, F_STONITH_NOTIFY_ACTIVATE, callback);
1190 } else {
1191 crm_xml_add(notify_msg, F_STONITH_NOTIFY_DEACTIVATE, callback);
1192 }
1193
1194 rc = crm_ipc_send(native->ipc, notify_msg, crm_ipc_client_response, -1, NULL);
1195 if (rc < 0) {
1196 crm_perror(LOG_DEBUG, "Couldn't register for fencing notifications: %d", rc);
1197 rc = -ECOMM;
1198 } else {
1199 rc = pcmk_ok;
1200 }
1201 }
1202
1203 free_xml(notify_msg);
1204 return rc;
1205}
1206
1207static int
1208stonith_api_add_notification(stonith_t * stonith, const char *event,
1209 void (*callback) (stonith_t * stonith, stonith_event_t * e))
1210{
1211 GList *list_item = NULL;
1212 stonith_notify_client_t *new_client = NULL;
1213 stonith_private_t *private = NULL;
1214
1215 private = stonith->st_private;
1216 crm_trace("Adding callback for %s events (%d)", event, g_list_length(private->notify_list));
1217
1218 new_client = calloc(1, sizeof(stonith_notify_client_t));
1219 new_client->event = event;
1220 new_client->notify = callback;
1221
1222 list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1223
1224 if (list_item != NULL) {
1225 crm_warn("Callback already present");
1226 free(new_client);
1227 return -ENOTUNIQ;
1228
1229 } else {
1230 private->notify_list = g_list_append(private->notify_list, new_client);
1231
1232 stonith_set_notification(stonith, event, 1);
1233
1234 crm_trace("Callback added (%d)", g_list_length(private->notify_list));
1235 }
1236 return pcmk_ok;
1237}
1238
1239static void
1240del_notify_entry(gpointer data, gpointer user_data)
1241{
1243 stonith_t * stonith = user_data;
1244
1245 if (!entry->delete) {
1246 crm_debug("Removing callback for %s events", entry->event);
1247 stonith_api_del_notification(stonith, entry->event);
1248 }
1249}
1250
1251static int
1252stonith_api_del_notification(stonith_t * stonith, const char *event)
1253{
1254 GList *list_item = NULL;
1255 stonith_notify_client_t *new_client = NULL;
1256 stonith_private_t *private = stonith->st_private;
1257
1258 if (event == NULL) {
1259 foreach_notify_entry(private, del_notify_entry, stonith);
1260 crm_trace("Removed callback");
1261
1262 return pcmk_ok;
1263 }
1264
1265 crm_debug("Removing callback for %s events", event);
1266
1267 new_client = calloc(1, sizeof(stonith_notify_client_t));
1268 new_client->event = event;
1269 new_client->notify = NULL;
1270
1271 list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1272
1273 stonith_set_notification(stonith, event, 0);
1274
1275 if (list_item != NULL) {
1276 stonith_notify_client_t *list_client = list_item->data;
1277
1278 if (private->notify_refcnt) {
1279 list_client->delete = TRUE;
1280 private->notify_deletes = TRUE;
1281 } else {
1282 private->notify_list = g_list_remove(private->notify_list, list_client);
1283 free(list_client);
1284 }
1285
1286 crm_trace("Removed callback");
1287
1288 } else {
1289 crm_trace("Callback not present");
1290 }
1291 free(new_client);
1292 return pcmk_ok;
1293}
1294
1295static int
1296stonith_api_add_callback(stonith_t * stonith, int call_id, int timeout, int options,
1297 void *user_data, const char *callback_name,
1298 void (*callback) (stonith_t * st, stonith_callback_data_t * data))
1299{
1300 stonith_callback_client_t *blob = NULL;
1301 stonith_private_t *private = NULL;
1302
1303 CRM_CHECK(stonith != NULL, return -EINVAL);
1304 CRM_CHECK(stonith->st_private != NULL, return -EINVAL);
1305 private = stonith->st_private;
1306
1307 if (call_id == 0) { // Add global callback
1308 private->op_callback = callback;
1309
1310 } else if (call_id < 0) { // Call failed immediately, so call callback now
1311 if (!(options & st_opt_report_only_success)) {
1313
1314 crm_trace("Call failed, calling %s: %s", callback_name, pcmk_strerror(call_id));
1316 stonith__legacy2status(call_id), NULL);
1317 invoke_fence_action_callback(stonith, call_id, &result,
1318 user_data, callback);
1319 } else {
1320 crm_warn("Fencer call failed: %s", pcmk_strerror(call_id));
1321 }
1322 return FALSE;
1323 }
1324
1325 blob = calloc(1, sizeof(stonith_callback_client_t));
1326 blob->id = callback_name;
1327 blob->only_success = (options & st_opt_report_only_success) ? TRUE : FALSE;
1328 blob->user_data = user_data;
1329 blob->callback = callback;
1330 blob->allow_timeout_updates = (options & st_opt_timeout_updates) ? TRUE : FALSE;
1331
1332 if (timeout > 0) {
1333 set_callback_timeout(blob, stonith, call_id, timeout);
1334 }
1335
1336 pcmk__intkey_table_insert(private->stonith_op_callback_table, call_id,
1337 blob);
1338 crm_trace("Added callback to %s for call %d", callback_name, call_id);
1339
1340 return TRUE;
1341}
1342
1343static void
1344stonith_dump_pending_op(gpointer key, gpointer value, gpointer user_data)
1345{
1346 int call = GPOINTER_TO_INT(key);
1347 stonith_callback_client_t *blob = value;
1348
1349 crm_debug("Call %d (%s): pending", call, pcmk__s(blob->id, "no ID"));
1350}
1351
1352void
1354{
1355 stonith_private_t *private = stonith->st_private;
1356
1357 if (private->stonith_op_callback_table == NULL) {
1358 return;
1359 }
1360 return g_hash_table_foreach(private->stonith_op_callback_table, stonith_dump_pending_op, NULL);
1361}
1362
1370static xmlNode *
1371get_event_data_xml(xmlNode *msg, const char *ntype)
1372{
1373 char *data_addr = crm_strdup_printf("//%s", ntype);
1374 xmlNode *data = get_xpath_object(data_addr, msg, LOG_DEBUG);
1375
1376 free(data_addr);
1377 return data;
1378}
1379
1380/*
1381 <notify t="st_notify" subt="st_device_register" st_op="st_device_register" st_rc="0" >
1382 <st_calldata >
1383 <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" >
1384 <st_calldata >
1385 <st_device_id id="test-id" origin="create_device_registration_xml" agent="fence_virsh" namespace="stonith-ng" >
1386 <attributes ipaddr="localhost" pcmk-portmal="some-host=pcmk-1 pcmk-3=3,4" login="root" identity_file="/root/.ssh/id_dsa" />
1387 </st_device_id>
1388 </st_calldata>
1389 </stonith_command>
1390 </st_calldata>
1391 </notify>
1392
1393 <notify t="st_notify" subt="st_notify_fence" st_op="st_notify_fence" st_rc="0" >
1394 <st_calldata >
1395 <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" />
1396 </st_calldata>
1397 </notify>
1398*/
1399static stonith_event_t *
1400xml_to_event(xmlNode *msg)
1401{
1402 stonith_event_t *event = calloc(1, sizeof(stonith_event_t));
1403 struct event_private *event_private = NULL;
1404
1405 CRM_ASSERT(event != NULL);
1406
1407 event->opaque = calloc(1, sizeof(struct event_private));
1408 CRM_ASSERT(event->opaque != NULL);
1409 event_private = (struct event_private *) event->opaque;
1410
1411 crm_log_xml_trace(msg, "stonith_notify");
1412
1413 // All notification types have the operation result and notification subtype
1414 stonith__xe_get_result(msg, &event_private->result);
1415 event->operation = crm_element_value_copy(msg, F_STONITH_OPERATION);
1416
1417 // @COMPAT The API originally provided the result as a legacy return code
1418 event->result = pcmk_rc2legacy(stonith__result2rc(&event_private->result));
1419
1420 // Some notification subtypes have additional information
1421
1422 if (pcmk__str_eq(event->operation, T_STONITH_NOTIFY_FENCE,
1423 pcmk__str_none)) {
1424 xmlNode *data = get_event_data_xml(msg, event->operation);
1425
1426 if (data == NULL) {
1427 crm_err("No data for %s event", event->operation);
1428 crm_log_xml_notice(msg, "BadEvent");
1429 } else {
1433 event->executioner = crm_element_value_copy(data, F_STONITH_DELEGATE);
1435 event->client_origin = crm_element_value_copy(data, F_STONITH_CLIENTNAME);
1437 }
1438
1439 } else if (pcmk__str_any_of(event->operation,
1442 NULL)) {
1443 xmlNode *data = get_event_data_xml(msg, event->operation);
1444
1445 if (data == NULL) {
1446 crm_err("No data for %s event", event->operation);
1447 crm_log_xml_notice(msg, "BadEvent");
1448 } else {
1450 }
1451 }
1452
1453 return event;
1454}
1455
1456static void
1457event_free(stonith_event_t * event)
1458{
1459 struct event_private *event_private = event->opaque;
1460
1461 free(event->id);
1462 free(event->type);
1463 free(event->message);
1464 free(event->operation);
1465 free(event->origin);
1466 free(event->action);
1467 free(event->target);
1468 free(event->executioner);
1469 free(event->device);
1470 free(event->client_origin);
1471 pcmk__reset_result(&event_private->result);
1472 free(event->opaque);
1473 free(event);
1474}
1475
1476static void
1477stonith_send_notification(gpointer data, gpointer user_data)
1478{
1479 struct notify_blob_s *blob = user_data;
1481 stonith_event_t *st_event = NULL;
1482 const char *event = NULL;
1483
1484 if (blob->xml == NULL) {
1485 crm_warn("Skipping callback - NULL message");
1486 return;
1487 }
1488
1489 event = crm_element_value(blob->xml, F_SUBTYPE);
1490
1491 if (entry == NULL) {
1492 crm_warn("Skipping callback - NULL callback client");
1493 return;
1494
1495 } else if (entry->delete) {
1496 crm_trace("Skipping callback - marked for deletion");
1497 return;
1498
1499 } else if (entry->notify == NULL) {
1500 crm_warn("Skipping callback - NULL callback");
1501 return;
1502
1503 } else if (!pcmk__str_eq(entry->event, event, pcmk__str_none)) {
1504 crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
1505 return;
1506 }
1507
1508 st_event = xml_to_event(blob->xml);
1509
1510 crm_trace("Invoking callback for %p/%s event...", entry, event);
1511 entry->notify(blob->stonith, st_event);
1512 crm_trace("Callback invoked...");
1513
1514 event_free(st_event);
1515}
1516
1531static int
1532stonith_send_command(stonith_t * stonith, const char *op, xmlNode * data, xmlNode ** output_data,
1533 int call_options, int timeout)
1534{
1535 int rc = 0;
1536 int reply_id = -1;
1537
1538 xmlNode *op_msg = NULL;
1539 xmlNode *op_reply = NULL;
1540 stonith_private_t *native = NULL;
1541
1542 CRM_ASSERT(stonith && stonith->st_private && op);
1543 native = stonith->st_private;
1544
1545 if (output_data != NULL) {
1546 *output_data = NULL;
1547 }
1548
1549 if ((stonith->state == stonith_disconnected) || (native->token == NULL)) {
1550 return -ENOTCONN;
1551 }
1552
1553 /* Increment the call ID, which must be positive to avoid conflicting with
1554 * error codes. This shouldn't be a problem unless the client mucked with
1555 * it or the counter wrapped around.
1556 */
1557 stonith->call_id++;
1558 if (stonith->call_id < 1) {
1559 stonith->call_id = 1;
1560 }
1561
1562 op_msg = stonith_create_op(stonith->call_id, native->token, op, data, call_options);
1563 if (op_msg == NULL) {
1564 return -EINVAL;
1565 }
1566
1568 crm_trace("Sending %s message to fencer with timeout %ds", op, timeout);
1569
1570 if (data) {
1571 const char *delay_s = crm_element_value(data, F_STONITH_DELAY);
1572
1573 if (delay_s) {
1574 crm_xml_add(op_msg, F_STONITH_DELAY, delay_s);
1575 }
1576 }
1577
1578 {
1579 enum crm_ipc_flags ipc_flags = crm_ipc_flags_none;
1580
1581 if (call_options & st_opt_sync_call) {
1582 pcmk__set_ipc_flags(ipc_flags, "stonith command",
1584 }
1585 rc = crm_ipc_send(native->ipc, op_msg, ipc_flags,
1586 1000 * (timeout + 60), &op_reply);
1587 }
1588 free_xml(op_msg);
1589
1590 if (rc < 0) {
1591 crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%ds): %d", op, timeout, rc);
1592 rc = -ECOMM;
1593 goto done;
1594 }
1595
1596 crm_log_xml_trace(op_reply, "Reply");
1597
1598 if (!(call_options & st_opt_sync_call)) {
1599 crm_trace("Async call %d, returning", stonith->call_id);
1600 free_xml(op_reply);
1601 return stonith->call_id;
1602 }
1603
1604 crm_element_value_int(op_reply, F_STONITH_CALLID, &reply_id);
1605
1606 if (reply_id == stonith->call_id) {
1608
1609 crm_trace("Synchronous reply %d received", reply_id);
1610
1611 stonith__xe_get_result(op_reply, &result);
1614
1615 if ((call_options & st_opt_discard_reply) || output_data == NULL) {
1616 crm_trace("Discarding reply");
1617
1618 } else {
1619 *output_data = op_reply;
1620 op_reply = NULL; /* Prevent subsequent free */
1621 }
1622
1623 } else if (reply_id <= 0) {
1624 crm_err("Received bad reply: No id set");
1625 crm_log_xml_err(op_reply, "Bad reply");
1626 free_xml(op_reply);
1627 rc = -ENOMSG;
1628
1629 } else {
1630 crm_err("Received bad reply: %d (wanted %d)", reply_id, stonith->call_id);
1631 crm_log_xml_err(op_reply, "Old reply");
1632 free_xml(op_reply);
1633 rc = -ENOMSG;
1634 }
1635
1636 done:
1637 if (!crm_ipc_connected(native->ipc)) {
1638 crm_err("Fencer disconnected");
1639 free(native->token); native->token = NULL;
1640 stonith->state = stonith_disconnected;
1641 }
1642
1643 free_xml(op_reply);
1644 return rc;
1645}
1646
1647/* Not used with mainloop */
1648bool
1650{
1651 gboolean stay_connected = TRUE;
1652 stonith_private_t *private = NULL;
1653
1654 CRM_ASSERT(st != NULL);
1655 private = st->st_private;
1656
1657 while (crm_ipc_ready(private->ipc)) {
1658
1659 if (crm_ipc_read(private->ipc) > 0) {
1660 const char *msg = crm_ipc_buffer(private->ipc);
1661
1662 stonith_dispatch_internal(msg, strlen(msg), st);
1663 }
1664
1665 if (!crm_ipc_connected(private->ipc)) {
1666 crm_err("Connection closed");
1667 stay_connected = FALSE;
1668 }
1669 }
1670
1671 return stay_connected;
1672}
1673
1674static int
1675stonith_api_free(stonith_t * stonith)
1676{
1677 int rc = pcmk_ok;
1678
1679 crm_trace("Destroying %p", stonith);
1680
1681 if (stonith->state != stonith_disconnected) {
1682 crm_trace("Unregistering notifications and disconnecting %p first",
1683 stonith);
1684 stonith->cmds->remove_notification(stonith, NULL);
1685 rc = stonith->cmds->disconnect(stonith);
1686 }
1687
1688 if (stonith->state == stonith_disconnected) {
1689 stonith_private_t *private = stonith->st_private;
1690
1691 crm_trace("Removing %d callbacks", g_hash_table_size(private->stonith_op_callback_table));
1692 g_hash_table_destroy(private->stonith_op_callback_table);
1693
1694 crm_trace("Destroying %d notification clients", g_list_length(private->notify_list));
1695 g_list_free_full(private->notify_list, free);
1696
1697 free(stonith->st_private);
1698 free(stonith->cmds);
1699 free(stonith);
1700
1701 } else {
1702 crm_err("Not free'ing active connection: %s (%d)", pcmk_strerror(rc), rc);
1703 }
1704
1705 return rc;
1706}
1707
1708void
1710{
1711 crm_trace("Destroying %p", stonith);
1712 if(stonith) {
1713 stonith->cmds->free(stonith);
1714 }
1715}
1716
1717static int
1718stonith_api_validate(stonith_t *st, int call_options, const char *rsc_id,
1719 const char *namespace_s, const char *agent,
1720 const stonith_key_value_t *params, int timeout_sec,
1721 char **output, char **error_output)
1722{
1723 /* Validation should be done directly via the agent, so we can get it from
1724 * stonith_admin when the cluster is not running, which is important for
1725 * higher-level tools.
1726 */
1727
1728 int rc = pcmk_ok;
1729
1730 /* Use a dummy node name in case the agent requires a target. We assume the
1731 * actual target doesn't matter for validation purposes (if in practice,
1732 * that is incorrect, we will need to allow the caller to pass the target).
1733 */
1734 const char *target = "node1";
1735 const char *host_arg = NULL;
1736
1737 GHashTable *params_table = pcmk__strkey_table(free, free);
1738
1739 // Convert parameter list to a hash table
1740 for (; params; params = params->next) {
1741 if (pcmk__str_eq(params->key, PCMK_STONITH_HOST_ARGUMENT,
1742 pcmk__str_none)) {
1743 host_arg = params->value;
1744 }
1745 if (!pcmk_stonith_param(params->key)) {
1746 g_hash_table_insert(params_table, strdup(params->key),
1747 strdup(params->value));
1748 }
1749 }
1750
1751#if SUPPORT_CIBSECRETS
1752 rc = pcmk__substitute_secrets(rsc_id, params_table);
1753 if (rc != pcmk_rc_ok) {
1754 crm_warn("Could not replace secret parameters for validation of %s: %s",
1755 agent, pcmk_rc_str(rc));
1756 // rc is standard return value, don't return it in this function
1757 }
1758#endif
1759
1760 if (output) {
1761 *output = NULL;
1762 }
1763 if (error_output) {
1764 *error_output = NULL;
1765 }
1766
1767 if (timeout_sec <= 0) {
1768 timeout_sec = CRMD_METADATA_CALL_TIMEOUT; // Questionable
1769 }
1770
1771 switch (stonith_get_namespace(agent, namespace_s)) {
1772 case st_namespace_rhcs:
1773 rc = stonith__rhcs_validate(st, call_options, target, agent,
1774 params_table, host_arg, timeout_sec,
1775 output, error_output);
1776 break;
1777
1778#if HAVE_STONITH_STONITH_H
1779 case st_namespace_lha:
1780 rc = stonith__lha_validate(st, call_options, target, agent,
1781 params_table, timeout_sec, output,
1782 error_output);
1783 break;
1784#endif
1785
1787 errno = ENOENT;
1788 rc = -errno;
1789
1790 if (error_output) {
1791 *error_output = crm_strdup_printf("Agent %s not found", agent);
1792 } else {
1793 crm_err("Agent %s not found", agent);
1794 }
1795
1796 break;
1797
1798 default:
1799 errno = EOPNOTSUPP;
1800 rc = -errno;
1801
1802 if (error_output) {
1803 *error_output = crm_strdup_printf("Agent %s does not support validation",
1804 agent);
1805 } else {
1806 crm_err("Agent %s does not support validation", agent);
1807 }
1808
1809 break;
1810 }
1811
1812 g_hash_table_destroy(params_table);
1813 return rc;
1814}
1815
1816stonith_t *
1818{
1819 stonith_t *new_stonith = NULL;
1820 stonith_private_t *private = NULL;
1821
1822 new_stonith = calloc(1, sizeof(stonith_t));
1823 if (new_stonith == NULL) {
1824 return NULL;
1825 }
1826
1827 private = calloc(1, sizeof(stonith_private_t));
1828 if (private == NULL) {
1829 free(new_stonith);
1830 return NULL;
1831 }
1832 new_stonith->st_private = private;
1833
1834 private->stonith_op_callback_table = pcmk__intkey_table(stonith_destroy_op_callback);
1835 private->notify_list = NULL;
1836 private->notify_refcnt = 0;
1837 private->notify_deletes = FALSE;
1838
1839 new_stonith->call_id = 1;
1840 new_stonith->state = stonith_disconnected;
1841
1842 new_stonith->cmds = calloc(1, sizeof(stonith_api_operations_t));
1843 if (new_stonith->cmds == NULL) {
1844 free(new_stonith->st_private);
1845 free(new_stonith);
1846 return NULL;
1847 }
1848
1849/* *INDENT-OFF* */
1850 new_stonith->cmds->free = stonith_api_free;
1851 new_stonith->cmds->connect = stonith_api_signon;
1852 new_stonith->cmds->disconnect = stonith_api_signoff;
1853
1854 new_stonith->cmds->list = stonith_api_list;
1855 new_stonith->cmds->monitor = stonith_api_monitor;
1856 new_stonith->cmds->status = stonith_api_status;
1857 new_stonith->cmds->fence = stonith_api_fence;
1858 new_stonith->cmds->fence_with_delay = stonith_api_fence_with_delay;
1859 new_stonith->cmds->confirm = stonith_api_confirm;
1860 new_stonith->cmds->history = stonith_api_history;
1861
1862 new_stonith->cmds->list_agents = stonith_api_device_list;
1863 new_stonith->cmds->metadata = stonith_api_device_metadata;
1864
1865 new_stonith->cmds->query = stonith_api_query;
1866 new_stonith->cmds->remove_device = stonith_api_remove_device;
1867 new_stonith->cmds->register_device = stonith_api_register_device;
1868
1869 new_stonith->cmds->remove_level = stonith_api_remove_level;
1870 new_stonith->cmds->remove_level_full = stonith_api_remove_level_full;
1871 new_stonith->cmds->register_level = stonith_api_register_level;
1872 new_stonith->cmds->register_level_full = stonith_api_register_level_full;
1873
1874 new_stonith->cmds->remove_callback = stonith_api_del_callback;
1875 new_stonith->cmds->register_callback = stonith_api_add_callback;
1876 new_stonith->cmds->remove_notification = stonith_api_del_notification;
1877 new_stonith->cmds->register_notification = stonith_api_add_notification;
1878
1879 new_stonith->cmds->validate = stonith_api_validate;
1880/* *INDENT-ON* */
1881
1882 return new_stonith;
1883}
1884
1894int
1895stonith_api_connect_retry(stonith_t *st, const char *name, int max_attempts)
1896{
1897 int rc = -EINVAL; // if max_attempts is not positive
1898
1899 for (int attempt = 1; attempt <= max_attempts; attempt++) {
1900 rc = st->cmds->connect(st, name, NULL);
1901 if (rc == pcmk_ok) {
1902 return pcmk_ok;
1903 } else if (attempt < max_attempts) {
1904 crm_notice("Fencer connection attempt %d of %d failed (retrying in 2s): %s "
1905 CRM_XS " rc=%d",
1906 attempt, max_attempts, pcmk_strerror(rc), rc);
1907 sleep(2);
1908 }
1909 }
1910 crm_notice("Could not connect to fencer: %s " CRM_XS " rc=%d",
1911 pcmk_strerror(rc), rc);
1912 return rc;
1913}
1914
1916stonith_key_value_add(stonith_key_value_t * head, const char *key, const char *value)
1917{
1918 stonith_key_value_t *p, *end;
1919
1920 p = calloc(1, sizeof(stonith_key_value_t));
1921 pcmk__str_update(&p->key, key);
1922 pcmk__str_update(&p->value, value);
1923
1924 end = head;
1925 while (end && end->next) {
1926 end = end->next;
1927 }
1928
1929 if (end) {
1930 end->next = p;
1931 } else {
1932 head = p;
1933 }
1934
1935 return head;
1936}
1937
1938void
1940{
1942
1943 while (head) {
1944 p = head->next;
1945 if (keys) {
1946 free(head->key);
1947 }
1948 if (values) {
1949 free(head->value);
1950 }
1951 free(head);
1952 head = p;
1953 }
1954}
1955
1956#define api_log_open() openlog("stonith-api", LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON)
1957#define api_log(level, fmt, args...) syslog(level, "%s: "fmt, __func__, args)
1958
1959int
1960stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
1961{
1962 int rc = pcmk_ok;
1964 const char *action = off? "off" : "reboot";
1965
1966 api_log_open();
1967 if (st == NULL) {
1968 api_log(LOG_ERR, "API initialization failed, could not kick (%s) node %u/%s",
1969 action, nodeid, uname);
1970 return -EPROTO;
1971 }
1972
1973 rc = st->cmds->connect(st, "stonith-api", NULL);
1974 if (rc != pcmk_ok) {
1975 api_log(LOG_ERR, "Connection failed, could not kick (%s) node %u/%s : %s (%d)",
1976 action, nodeid, uname, pcmk_strerror(rc), rc);
1977 } else {
1978 char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
1979 int opts = 0;
1980
1983 if ((uname == NULL) && (nodeid > 0)) {
1985 }
1986 rc = st->cmds->fence(st, opts, name, action, timeout, 0);
1987 free(name);
1988
1989 if (rc != pcmk_ok) {
1990 api_log(LOG_ERR, "Could not kick (%s) node %u/%s : %s (%d)",
1991 action, nodeid, uname, pcmk_strerror(rc), rc);
1992 } else {
1993 api_log(LOG_NOTICE, "Node %u/%s kicked: %s", nodeid, uname, action);
1994 }
1995 }
1996
1998 return rc;
1999}
2000
2001time_t
2002stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
2003{
2004 int rc = pcmk_ok;
2005 time_t when = 0;
2007 stonith_history_t *history = NULL, *hp = NULL;
2008
2009 if (st == NULL) {
2010 api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: "
2011 "API initialization failed", nodeid, uname);
2012 return when;
2013 }
2014
2015 rc = st->cmds->connect(st, "stonith-api", NULL);
2016 if (rc != pcmk_ok) {
2017 api_log(LOG_NOTICE, "Connection failed: %s (%d)", pcmk_strerror(rc), rc);
2018 } else {
2019 int entries = 0;
2020 int progress = 0;
2021 int completed = 0;
2022 int opts = 0;
2023 char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
2024
2026 if ((uname == NULL) && (nodeid > 0)) {
2028 }
2029 rc = st->cmds->history(st, opts, name, &history, 120);
2030 free(name);
2031
2032 for (hp = history; hp; hp = hp->next) {
2033 entries++;
2034 if (in_progress) {
2035 progress++;
2036 if (hp->state != st_done && hp->state != st_failed) {
2037 when = time(NULL);
2038 }
2039
2040 } else if (hp->state == st_done) {
2041 completed++;
2042 if (hp->completed > when) {
2043 when = hp->completed;
2044 }
2045 }
2046 }
2047
2048 stonith_history_free(history);
2049
2050 if(rc == pcmk_ok) {
2051 api_log(LOG_INFO, "Found %d entries for %u/%s: %d in progress, %d completed", entries, nodeid, uname, progress, completed);
2052 } else {
2053 api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: %s (%d)", nodeid, uname, pcmk_strerror(rc), rc);
2054 }
2055 }
2056
2058
2059 if(when) {
2060 api_log(LOG_INFO, "Node %u/%s last kicked at: %ld", nodeid, uname, (long int)when);
2061 }
2062 return when;
2063}
2064
2065bool
2066stonith_agent_exists(const char *agent, int timeout)
2067{
2068 stonith_t *st = NULL;
2069 stonith_key_value_t *devices = NULL;
2070 stonith_key_value_t *dIter = NULL;
2071 bool rc = FALSE;
2072
2073 if (agent == NULL) {
2074 return rc;
2075 }
2076
2077 st = stonith_api_new();
2078 if (st == NULL) {
2079 crm_err("Could not list fence agents: API memory allocation failed");
2080 return FALSE;
2081 }
2082 st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, timeout == 0 ? 120 : timeout);
2083
2084 for (dIter = devices; dIter != NULL; dIter = dIter->next) {
2085 if (pcmk__str_eq(dIter->value, agent, pcmk__str_none)) {
2086 rc = TRUE;
2087 break;
2088 }
2089 }
2090
2091 stonith_key_value_freeall(devices, 1, 1);
2093 return rc;
2094}
2095
2096const char *
2098{
2099 if (action == NULL) {
2100 return "fencing";
2101 } else if (!strcmp(action, "on")) {
2102 return "unfencing";
2103 } else if (!strcmp(action, "off")) {
2104 return "turning off";
2105 } else {
2106 return action;
2107 }
2108}
2109
2118static void
2119parse_list_line(const char *line, int len, GList **output)
2120{
2121 size_t i = 0;
2122 size_t entry_start = 0;
2123
2124 /* Skip complaints about additional parameters device doesn't understand
2125 *
2126 * @TODO Document or eliminate the implied restriction of target names
2127 */
2128 if (strstr(line, "invalid") || strstr(line, "variable")) {
2129 crm_debug("Skipping list output line: %s", line);
2130 return;
2131 }
2132
2133 // Process line content, character by character
2134 for (i = 0; i <= len; i++) {
2135
2136 if (isspace(line[i]) || (line[i] == ',') || (line[i] == ';')
2137 || (line[i] == '\0')) {
2138 // We've found a separator (i.e. the end of an entry)
2139
2140 int rc = 0;
2141 char *entry = NULL;
2142
2143 if (i == entry_start) {
2144 // Skip leading and sequential separators
2145 entry_start = i + 1;
2146 continue;
2147 }
2148
2149 entry = calloc(i - entry_start + 1, sizeof(char));
2150 CRM_ASSERT(entry != NULL);
2151
2152 /* Read entry, stopping at first separator
2153 *
2154 * @TODO Document or eliminate these character restrictions
2155 */
2156 rc = sscanf(line + entry_start, "%[a-zA-Z0-9_-.]", entry);
2157 if (rc != 1) {
2158 crm_warn("Could not parse list output entry: %s "
2159 CRM_XS " entry_start=%d position=%d",
2160 line + entry_start, entry_start, i);
2161 free(entry);
2162
2163 } else if (pcmk__strcase_any_of(entry, "on", "off", NULL)) {
2164 /* Some agents print the target status in the list output,
2165 * though none are known now (the separate list-status command
2166 * is used for this, but it can also print "UNKNOWN"). To handle
2167 * this possibility, skip such entries.
2168 *
2169 * @TODO Document or eliminate the implied restriction of target
2170 * names.
2171 */
2172 free(entry);
2173
2174 } else {
2175 // We have a valid entry
2176 *output = g_list_append(*output, entry);
2177 }
2178 entry_start = i + 1;
2179 }
2180 }
2181}
2182
2204GList *
2205stonith__parse_targets(const char *target_spec)
2206{
2207 GList *targets = NULL;
2208
2209 if (target_spec != NULL) {
2210 size_t out_len = strlen(target_spec);
2211 size_t line_start = 0; // Starting index of line being processed
2212
2213 for (size_t i = 0; i <= out_len; ++i) {
2214 if ((target_spec[i] == '\n') || (target_spec[i] == '\0')
2215 || ((target_spec[i] == '\\') && (target_spec[i + 1] == 'n'))) {
2216 // We've reached the end of one line of output
2217
2218 int len = i - line_start;
2219
2220 if (len > 0) {
2221 char *line = strndup(target_spec + line_start, len);
2222
2223 line[len] = '\0'; // Because it might be a newline
2224 parse_list_line(line, len, &targets);
2225 free(line);
2226 }
2227 if (target_spec[i] == '\\') {
2228 ++i; // backslash-n takes up two positions
2229 }
2230 line_start = i + 1;
2231 }
2232 }
2233 }
2234 return targets;
2235}
2236
2248const char *
2250 const stonith_history_t *top_history)
2251{
2252 const char *other = NULL;
2253
2254 for (const stonith_history_t *prev_hp = top_history;
2255 prev_hp != NULL; prev_hp = prev_hp->next) {
2256 if (prev_hp == event) {
2257 break;
2258 }
2259 if ((prev_hp->state == st_done) &&
2260 pcmk__str_eq(event->target, prev_hp->target, pcmk__str_casei) &&
2261 pcmk__str_eq(event->action, prev_hp->action, pcmk__str_none) &&
2262 ((event->completed < prev_hp->completed) ||
2263 ((event->completed == prev_hp->completed) && (event->completed_nsec < prev_hp->completed_nsec)))) {
2264
2265 if ((event->delegate == NULL)
2266 || pcmk__str_eq(event->delegate, prev_hp->delegate,
2267 pcmk__str_casei)) {
2268 // Prefer equivalent fencing by same executioner
2269 return prev_hp->delegate;
2270
2271 } else if (other == NULL) {
2272 // Otherwise remember first successful executioner
2273 other = (prev_hp->delegate == NULL)? "some node" : prev_hp->delegate;
2274 }
2275 }
2276 }
2277 return other;
2278}
2279
2290{
2291 stonith_history_t *new = NULL, *pending = NULL, *hp, *np, *tmp;
2292
2293 for (hp = history; hp; ) {
2294 tmp = hp->next;
2295 if ((hp->state == st_done) || (hp->state == st_failed)) {
2296 /* sort into new */
2297 if ((!new) || (hp->completed > new->completed) ||
2298 ((hp->completed == new->completed) && (hp->completed_nsec > new->completed_nsec))) {
2299 hp->next = new;
2300 new = hp;
2301 } else {
2302 np = new;
2303 do {
2304 if ((!np->next) || (hp->completed > np->next->completed) ||
2305 ((hp->completed == np->next->completed) && (hp->completed_nsec > np->next->completed_nsec))) {
2306 hp->next = np->next;
2307 np->next = hp;
2308 break;
2309 }
2310 np = np->next;
2311 } while (1);
2312 }
2313 } else {
2314 /* put into pending */
2315 hp->next = pending;
2316 pending = hp;
2317 }
2318 hp = tmp;
2319 }
2320
2321 /* pending actions don't have a completed-stamp so make them go front */
2322 if (pending) {
2323 stonith_history_t *last_pending = pending;
2324
2325 while (last_pending->next) {
2326 last_pending = last_pending->next;
2327 }
2328
2329 last_pending->next = new;
2330 new = pending;
2331 }
2332 return new;
2333}
2334
2342const char *
2344{
2345 switch (state) {
2346 case st_query: return "querying";
2347 case st_exec: return "executing";
2348 case st_done: return "completed";
2349 case st_duplicate: return "duplicate";
2350 case st_failed: return "failed";
2351 }
2352 return "unknown";
2353}
2354
2357 bool (*matching_fn)(stonith_history_t *, void *),
2358 void *user_data)
2359{
2360 for (stonith_history_t *hp = history; hp; hp = hp->next) {
2361 if (matching_fn(hp, user_data)) {
2362 return hp;
2363 }
2364 }
2365
2366 return NULL;
2367}
2368
2369bool
2371{
2372 return history->state != st_failed && history->state != st_done;
2373}
2374
2375bool
2377{
2378 return history->state == GPOINTER_TO_INT(user_data);
2379}
2380
2381bool
2383{
2384 return history->state != GPOINTER_TO_INT(user_data);
2385}
2386
2387void
2388stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name,
2389 xmlNode *metadata)
2390{
2391 xmlXPathObjectPtr xpath = NULL;
2392 int max = 0;
2393 int lpc = 0;
2394
2395 CRM_CHECK((device_flags != NULL) && (metadata != NULL), return);
2396
2397 xpath = xpath_search(metadata, "//parameter");
2398 max = numXpathResults(xpath);
2399
2400 if (max <= 0) {
2401 freeXpathObject(xpath);
2402 return;
2403 }
2404
2405 for (lpc = 0; lpc < max; lpc++) {
2406 const char *parameter = NULL;
2407 xmlNode *match = getXpathResult(xpath, lpc);
2408
2409 CRM_LOG_ASSERT(match != NULL);
2410 if (match == NULL) {
2411 continue;
2412 }
2413
2414 parameter = crm_element_value(match, "name");
2415
2416 if (pcmk__str_eq(parameter, "plug", pcmk__str_casei)) {
2417 stonith__set_device_flags(*device_flags, device_name,
2419
2420 } else if (pcmk__str_eq(parameter, "port", pcmk__str_casei)) {
2421 stonith__set_device_flags(*device_flags, device_name,
2423 }
2424 }
2425
2426 freeXpathObject(xpath);
2427}
2428
2448int
2449stonith__metadata_async(const char *agent, int timeout_sec,
2450 void (*callback)(int pid,
2452 void *user_data),
2453 void *user_data)
2454{
2455 switch (stonith_get_namespace(agent, NULL)) {
2456 case st_namespace_rhcs:
2457 {
2458 stonith_action_t *action = NULL;
2459 int rc = pcmk_ok;
2460
2461 action = stonith__action_create(agent, "metadata", NULL, 0,
2462 timeout_sec, NULL, NULL, NULL);
2463
2464 rc = stonith__execute_async(action, user_data, callback, NULL);
2465 if (rc != pcmk_ok) {
2466 callback(0, stonith__action_result(action), user_data);
2468 }
2469 return pcmk_legacy2rc(rc);
2470 }
2471
2472#if HAVE_STONITH_STONITH_H
2473 case st_namespace_lha:
2474 // LHA metadata is simply synthesized, so simulate async
2475 {
2478 .execution_status = PCMK_EXEC_DONE,
2479 .exit_reason = NULL,
2480 .action_stdout = NULL,
2481 .action_stderr = NULL,
2482 };
2483
2484 stonith__lha_metadata(agent, timeout_sec,
2486 callback(0, &result, user_data);
2488 return pcmk_rc_ok;
2489 }
2490#endif
2491
2492 default:
2493 {
2496 .execution_status = PCMK_EXEC_ERROR_HARD,
2497 .exit_reason = crm_strdup_printf("No such agent '%s'",
2498 agent),
2499 .action_stdout = NULL,
2500 .action_stderr = NULL,
2501 };
2502
2503 callback(0, &result, user_data);
2505 return ENOENT;
2506 }
2507 }
2508}
2509
2518int
2520{
2521 if ((data == NULL) || (data->opaque == NULL)) {
2522 return CRM_EX_ERROR;
2523 }
2524 return ((pcmk__action_result_t *) data->opaque)->exit_status;
2525}
2526
2535int
2537{
2538 if ((data == NULL) || (data->opaque == NULL)) {
2539 return PCMK_EXEC_UNKNOWN;
2540 }
2541 return ((pcmk__action_result_t *) data->opaque)->execution_status;
2542}
2543
2552const char *
2554{
2555 if ((data == NULL) || (data->opaque == NULL)) {
2556 return NULL;
2557 }
2558 return ((pcmk__action_result_t *) data->opaque)->exit_reason;
2559}
2560
2569int
2571{
2572 if ((event == NULL) || (event->opaque == NULL)) {
2573 return CRM_EX_ERROR;
2574 } else {
2575 struct event_private *event_private = event->opaque;
2576
2577 return event_private->result.exit_status;
2578 }
2579}
2580
2589int
2591{
2592 if ((event == NULL) || (event->opaque == NULL)) {
2593 return PCMK_EXEC_UNKNOWN;
2594 } else {
2595 struct event_private *event_private = event->opaque;
2596
2597 return event_private->result.execution_status;
2598 }
2599}
2600
2609const char *
2611{
2612 if ((event == NULL) || (event->opaque == NULL)) {
2613 return NULL;
2614 } else {
2615 struct event_private *event_private = event->opaque;
2616
2617 return event_private->result.exit_reason;
2618 }
2619}
2620
2631char *
2633{
2634 // Use somewhat readable defaults
2635 const char *origin = pcmk__s(event->client_origin, "a client");
2636 const char *origin_node = pcmk__s(event->origin, "a node");
2637 const char *executioner = pcmk__s(event->executioner, "the cluster");
2638 const char *device = pcmk__s(event->device, "unknown");
2639 const char *action = pcmk__s(event->action, event->operation);
2640 const char *target = pcmk__s(event->target, "no node");
2641 const char *reason = stonith__event_exit_reason(event);
2642 const char *status;
2643
2644 if (action == NULL) {
2645 action = "(unknown)";
2646 }
2647
2649 status = pcmk_exec_status_str(stonith__event_execution_status(event));
2650 } else if (stonith__event_exit_status(event) != CRM_EX_OK) {
2651 status = pcmk_exec_status_str(PCMK_EXEC_ERROR);
2652 } else {
2653 status = crm_exit_str(CRM_EX_OK);
2654 }
2655
2656 if (pcmk__str_eq(event->operation, T_STONITH_NOTIFY_HISTORY,
2657 pcmk__str_none)) {
2658 return crm_strdup_printf("Fencing history may have changed");
2659
2660 } else if (pcmk__str_eq(event->operation, STONITH_OP_DEVICE_ADD,
2661 pcmk__str_none)) {
2662 return crm_strdup_printf("A fencing device (%s) was added", device);
2663
2664 } else if (pcmk__str_eq(event->operation, STONITH_OP_DEVICE_DEL,
2665 pcmk__str_none)) {
2666 return crm_strdup_printf("A fencing device (%s) was removed", device);
2667
2668 } else if (pcmk__str_eq(event->operation, STONITH_OP_LEVEL_ADD,
2669 pcmk__str_none)) {
2670 return crm_strdup_printf("A fencing topology level (%s) was added",
2671 device);
2672
2673 } else if (pcmk__str_eq(event->operation, STONITH_OP_LEVEL_DEL,
2674 pcmk__str_none)) {
2675 return crm_strdup_printf("A fencing topology level (%s) was removed",
2676 device);
2677 }
2678
2679 // event->operation should be T_STONITH_NOTIFY_FENCE at this point
2680
2681 return crm_strdup_printf("Operation %s of %s by %s for %s@%s: %s%s%s%s (ref=%s)",
2682 action, target, executioner, origin, origin_node,
2683 status,
2684 ((reason == NULL)? "" : " ("), pcmk__s(reason, ""),
2685 ((reason == NULL)? "" : ")"),
2686 pcmk__s(event->id, "(none)"));
2687}
2688
2689
2690// Deprecated functions kept only for backward API compatibility
2691// LCOV_EXCL_START
2692
2693const char *get_stonith_provider(const char *agent, const char *provider);
2694
2695const char *
2696get_stonith_provider(const char *agent, const char *provider)
2697{
2698 return stonith_namespace2text(stonith_get_namespace(agent, provider));
2699}
2700
2701// LCOV_EXCL_STOP
2702// End deprecated API
#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:24
int pcmk__substitute_secrets(const char *rsc_id, GHashTable *params)
Definition cib_secrets.c:96
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
enum crm_ais_msg_types type
Definition cpg.c:3
char uname[MAX_NAME]
Definition cpg.c:5
char data[0]
Definition cpg.c:10
uint32_t id
Definition cpg.c:0
uint32_t pid
Definition cpg.c:1
A dumping ground.
#define CRM_OP_REGISTER
Definition crm.h:145
#define CRMD_METADATA_CALL_TIMEOUT
Definition crm.h:190
#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:243
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:254
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:217
void crm_ipc_destroy(crm_ipc_t *client)
Definition ipc_client.c:955
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
long crm_ipc_read(crm_ipc_t *client)
int crm_ipc_get_fd(crm_ipc_t *client)
Definition ipc_client.c:981
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)
Definition ipc_client.c:995
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition ipc_client.c:867
void crm_ipc_close(crm_ipc_t *client)
Definition ipc_client.c:942
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:820
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
#define CRM_TRACE_INIT_DATA(name)
Definition logging.h:134
#define crm_info(fmt, args...)
Definition logging.h:378
#define crm_warn(fmt, args...)
Definition logging.h:376
#define CRM_XS
Definition logging.h:55
#define crm_log_xml_debug(xml, text)
Definition logging.h:388
#define CRM_LOG_ASSERT(expr)
Definition logging.h:219
#define crm_log_xml_err(xml, text)
Definition logging.h:384
#define crm_notice(fmt, args...)
Definition logging.h:377
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition logging.h:319
#define CRM_CHECK(expr, failure_action)
Definition logging.h:235
#define crm_debug(fmt, args...)
Definition logging.h:380
#define crm_err(fmt, args...)
Definition logging.h:375
#define LOG_NEVER
Definition logging.h:47
#define crm_log_xml_trace(xml, text)
Definition logging.h:389
#define crm_log_xml_warn(xml, text)
Definition logging.h:385
#define crm_trace(fmt, args...)
Definition logging.h:381
#define crm_log_xml_notice(xml, text)
Definition logging.h:386
Wrappers for and extensions to glib mainloop.
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition mainloop.c:946
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:915
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:940
#define F_SUBTYPE
Definition msg_xml.h:78
#define XML_ATTR_STONITH_TARGET_ATTRIBUTE
Definition msg_xml.h:465
#define XML_TAG_FENCING_LEVEL
Definition msg_xml.h:460
#define F_XML_TAGNAME
Definition msg_xml.h:90
#define XML_ATTR_ID
Definition msg_xml.h:147
#define XML_LRM_ATTR_EXIT_REASON
Definition msg_xml.h:333
#define XML_ATTR_STONITH_INDEX
Definition msg_xml.h:461
#define XML_TAG_ATTRS
Definition msg_xml.h:224
#define F_TYPE
Definition msg_xml.h:82
#define XML_ATTR_STONITH_DEVICES
Definition msg_xml.h:466
#define XML_ATTR_STONITH_TARGET_PATTERN
Definition msg_xml.h:464
#define XML_ATTR_STONITH_TARGET_VALUE
Definition msg_xml.h:463
#define XML_ATTR_STONITH_TARGET
Definition msg_xml.h:462
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:496
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition nvpair.c:532
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition nvpair.c:749
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:398
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition nvpair.c:693
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:564
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
char * strndup(const char *str, size_t len)
#define ECOMM
#define ENOTUNIQ
const char * pcmk_strerror(int rc)
Definition results.c:148
#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:488
@ CRM_EX_NOSUCH
Requested item does not exist.
Definition results.h:273
@ CRM_EX_ERROR
Unspecified error.
Definition results.h:238
@ CRM_EX_OK
Success.
Definition results.h:237
@ pcmk_rc_ok
Definition results.h:151
#define pcmk_ok
Definition results.h:68
int pcmk_rc2legacy(int rc)
Definition results.c:533
const char * crm_exit_str(crm_exit_t exit_code)
Definition results.c:627
@ PCMK_EXEC_DONE
Action completed, result is known.
Definition results.h:315
@ PCMK_EXEC_ERROR
Execution failed, may be retried.
Definition results.h:319
@ PCMK_EXEC_TIMEOUT
Action did not complete in time.
Definition results.h:317
@ PCMK_EXEC_UNKNOWN
Used only to initialize variables.
Definition results.h:313
@ PCMK_EXEC_ERROR_HARD
Execution failed, do not retry on node.
Definition results.h:320
int pcmk_legacy2rc(int legacy_rc)
Definition results.c:546
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:914
#define PCMK__UNKNOWN_RESULT
void pcmk__reset_result(pcmk__action_result_t *result)
Definition results.c:1003
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:2449
void stonith_api_delete(stonith_t *stonith)
Definition st_client.c:1709
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:2553
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:2002
char * stonith__event_description(const stonith_event_t *event)
Definition st_client.c:2632
stonith_key_value_t * stonith_key_value_add(stonith_key_value_t *head, const char *key, const char *value)
Definition st_client.c:1916
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:2370
GList * stonith__parse_targets(const char *target_spec)
Definition st_client.c:2205
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:802
void stonith_history_free(stonith_history_t *history)
Definition st_client.c:755
bool stonith__event_state_neq(stonith_history_t *history, void *user_data)
Definition st_client.c:2382
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:2388
bool stonith__event_state_eq(stonith_history_t *history, void *user_data)
Definition st_client.c:2376
const char * stonith_action_str(const char *action)
Turn fence action into a more readable string.
Definition st_client.c:2097
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:1649
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:1895
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:2356
#define api_log(level, fmt, args...)
Definition st_client.c:1957
int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
Definition st_client.c:1960
int stonith__exit_status(const stonith_callback_data_t *data)
Definition st_client.c:2519
const char * get_stonith_provider(const char *agent, const char *provider)
Definition st_client.c:2696
stonith_history_t * stonith__sort_history(stonith_history_t *history)
Definition st_client.c:2289
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:2536
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:2570
int stonith__event_execution_status(const stonith_event_t *event)
Definition st_client.c:2590
stonith_t * stonith_api_new(void)
Definition st_client.c:1817
#define api_log_open()
Definition st_client.c:1956
const char * stonith__later_succeeded(const stonith_history_t *event, const stonith_history_t *top_history)
Definition st_client.c:2249
const char * stonith__event_exit_reason(const stonith_event_t *event)
Definition st_client.c:2610
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:1939
struct stonith_callback_client_s stonith_callback_client_t
bool stonith_agent_exists(const char *agent, int timeout)
Definition st_client.c:2066
void stonith_dump_pending_callbacks(stonith_t *stonith)
Definition st_client.c:1353
const char * stonith_op_state_str(enum op_state state)
Return string equivalent of an operation state value.
Definition st_client.c:2343
int stonith__lha_metadata(const char *agent, int timeout, char **output)
Definition st_lha.c:170
int stonith__list_lha_agents(stonith_key_value_t **devices)
Definition st_lha.c:110
int stonith__lha_validate(stonith_t *st, int call_options, const char *target, const char *agent, GHashTable *params, int timeout, char **output, char **error_output)
Definition st_lha.c:272
bool stonith__agent_is_lha(const char *agent)
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:611
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:703
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:111
stonith_t * stonith
Definition st_client.c:79
xmlXPathObjectPtr xpath_search(xmlNode *xml_top, const char *path)
Definition xpath.c:139
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition xpath.c:214
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition xpath.c:58
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition xpath.c:39
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition messages.c:160
xmlNode * string2xml(const char *input)
Definition xml.c:831
void free_xml(xmlNode *child)
Definition xml.c:813
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition xml.c:677