pacemaker  2.1.9-49aab99839
Scalable High-Availability cluster resource manager
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>
23 #include <crm/fencing/internal.h>
24 #include <crm/common/xml.h>
25 
26 #include <crm/common/mainloop.h>
27 
28 #include "fencing_private.h"
29 
30 CRM_TRACE_INIT_DATA(stonith);
31 
32 // Used as stonith_t:st_private
33 typedef 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
47 struct event_private {
49 };
50 
51 typedef 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 
60 typedef 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 
70 struct notify_blob_s {
71  stonith_t *stonith;
72  xmlNode *xml;
73 };
74 
75 struct timer_rec_s {
76  int call_id;
77  int timeout;
78  guint ref;
80 };
81 
82 typedef int (*stonith_op_t) (const char *, int, const char *, xmlNode *,
83  xmlNode *, xmlNode *, xmlNode **, xmlNode **);
84 
86 xmlNode *stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data,
87  int call_options);
88 static int stonith_send_command(stonith_t *stonith, const char *op,
89  xmlNode *data, xmlNode **output_data,
90  int call_options, int timeout);
91 
92 static void stonith_connection_destroy(gpointer user_data);
93 static void stonith_send_notification(gpointer data, gpointer user_data);
94 static int stonith_api_del_notification(stonith_t *stonith,
95  const char *event);
104 stonith_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")) {
114  return st_namespace_internal;
115 
116  } else if (!strcmp(namespace_s, "heartbeat")) {
117  return st_namespace_lha;
118  }
119  return st_namespace_invalid;
120 }
121 
129 const 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 
151 stonith_get_namespace(const char *agent, const char *namespace_s)
152 {
153  if (pcmk__str_eq(namespace_s, "internal", pcmk__str_none)) {
154  return st_namespace_internal;
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);
168  return st_namespace_invalid;
169 }
170 
171 gboolean
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 
230 gboolean
232 {
234 }
235 
236 /* when cycling through the list we don't want to delete items
237  so just mark them and when we know nobody is using the list
238  loop over it to remove the marked items
239  */
240 static void
241 foreach_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 
268 static void
269 stonith_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 
292 xmlNode *
293 create_device_registration_xml(const char *id, enum stonith_namespace namespace,
294  const char *agent,
295  const stonith_key_value_t *params,
296  const char *rsc_provides)
297 {
298  xmlNode *data = pcmk__xe_create(NULL, PCMK__XE_ST_DEVICE_ID);
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 
312  crm_xml_add(data, PCMK__XA_ST_ORIGIN, __func__);
313  crm_xml_add(data, PCMK_XA_AGENT, agent);
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 
329 static int
330 stonith_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 
348 static int
349 stonith_api_remove_device(stonith_t * st, int call_options, const char *name)
350 {
351  int rc = 0;
352  xmlNode *data = NULL;
353 
355  crm_xml_add(data, PCMK__XA_ST_ORIGIN, __func__);
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 
363 static int
364 stonith_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 
374  crm_xml_add(data, PCMK__XA_ST_ORIGIN, __func__);
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 
394 static int
395 stonith_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 
416 xmlNode *
417 create_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 
428  crm_xml_add(data, PCMK__XA_ST_ORIGIN, __func__);
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 
454 static int
455 stonith_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 
471 static int
472 stonith_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 
479 static int
480 stonith_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
508 static int
509 stonith_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) {
520  timeout_sec = PCMK_DEFAULT_METADATA_TIMEOUT_MS;
521  }
522 
523  crm_trace("Looking up metadata for %s agent %s",
524  stonith_namespace2text(ns), agent);
525 
526  switch (ns) {
527  case st_namespace_rhcs:
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 
543 static int
544 stonith_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 
556  crm_xml_add(data, PCMK__XA_ST_ORIGIN, __func__);
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 
604 static int
605 stonith_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 
613  crm_xml_add(data, PCMK__XA_ST_ORIGIN, __func__);
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 
625 static int
626 stonith_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 
652 static int
653 stonith_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 
659 static int
660 stonith_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 
667 static int
668 stonith_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 
687 static int
688 stonith_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 
695 static int
696 stonith_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 
703 static int
704 stonith_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)) {
731  stonith_history_t *kvp;
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 
776 static gint
777 stonithlib_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 
808 xmlNode *
809 stonith_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 
831 static void
832 stonith_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 
843 static int
844 stonith_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 
870 static int
871 stonith_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 
900 static void
901 invoke_fence_action_callback(stonith_t *st, int call_id,
903  void *userdata,
904  void (*callback) (stonith_t *st,
906 {
907  stonith_callback_data_t data = { 0, };
908 
909  data.call_id = call_id;
911  data.userdata = userdata;
912  data.opaque = (void *) result;
913 
914  callback(st, &data);
915 }
916 
928 static void
929 invoke_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 
988 static gboolean
989 stonith_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 
1002 static void
1003 set_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 
1030 static void
1031 update_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 
1045 static int
1046 stonith_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  pcmk__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 
1092 static int
1093 stonith_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  pcmk__assert(native != NULL);
1108 
1109  crm_debug("Attempting fencer connection by %s with%s mainloop",
1110  display_name, (stonith_fd? "out" : ""));
1111 
1112  stonith->state = stonith_connected_command;
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 
1193 static int
1194 stonith_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 
1222 static int
1223 stonith_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 
1254 static void
1255 del_notify_entry(gpointer data, gpointer user_data)
1256 {
1257  stonith_notify_client_t *entry = data;
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 
1266 static int
1267 stonith_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 
1310 static int
1311 stonith_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 
1340  blob = pcmk__assert_alloc(1, sizeof(stonith_callback_client_t));
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 
1358 static void
1359 stonith_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 
1367 void
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 
1385 static xmlNode *
1386 get_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 */
1414 static stonith_event_t *
1415 xml_to_event(xmlNode *msg)
1416 {
1417  stonith_event_t *event = pcmk__assert_alloc(1, sizeof(stonith_event_t));
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 
1471 static void
1472 event_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 
1491 static void
1492 stonith_send_notification(gpointer data, gpointer user_data)
1493 {
1494  struct notify_blob_s *blob = user_data;
1495  stonith_notify_client_t *entry = 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 
1546 static int
1547 stonith_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  pcmk__assert((stonith != NULL) && (stonith->st_private != NULL)
1558  && (op != NULL));
1559  native = stonith->st_private;
1560 
1561  if (output_data != NULL) {
1562  *output_data = NULL;
1563  }
1564 
1565  if ((stonith->state == stonith_disconnected) || (native->token == NULL)) {
1566  return -ENOTCONN;
1567  }
1568 
1569  /* Increment the call ID, which must be positive to avoid conflicting with
1570  * error codes. This shouldn't be a problem unless the client mucked with
1571  * it or the counter wrapped around.
1572  */
1573  stonith->call_id++;
1574  if (stonith->call_id < 1) {
1575  stonith->call_id = 1;
1576  }
1577 
1578  op_msg = stonith_create_op(stonith->call_id, native->token, op, data, call_options);
1579  if (op_msg == NULL) {
1580  return -EINVAL;
1581  }
1582 
1584  crm_trace("Sending %s message to fencer with timeout %ds", op, timeout);
1585 
1586  if (data) {
1587  const char *delay_s = crm_element_value(data, PCMK__XA_ST_DELAY);
1588 
1589  if (delay_s) {
1590  crm_xml_add(op_msg, PCMK__XA_ST_DELAY, delay_s);
1591  }
1592  }
1593 
1594  {
1595  enum crm_ipc_flags ipc_flags = crm_ipc_flags_none;
1596 
1597  if (call_options & st_opt_sync_call) {
1598  pcmk__set_ipc_flags(ipc_flags, "stonith command",
1600  }
1601  rc = crm_ipc_send(native->ipc, op_msg, ipc_flags,
1602  1000 * (timeout + 60), &op_reply);
1603  }
1604  free_xml(op_msg);
1605 
1606  if (rc < 0) {
1607  crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%ds): %d", op, timeout, rc);
1608  rc = -ECOMM;
1609  goto done;
1610  }
1611 
1612  crm_log_xml_trace(op_reply, "Reply");
1613 
1614  if (!(call_options & st_opt_sync_call)) {
1615  crm_trace("Async call %d, returning", stonith->call_id);
1616  free_xml(op_reply);
1617  return stonith->call_id;
1618  }
1619 
1620  crm_element_value_int(op_reply, PCMK__XA_ST_CALLID, &reply_id);
1621 
1622  if (reply_id == stonith->call_id) {
1624 
1625  crm_trace("Synchronous reply %d received", reply_id);
1626 
1627  stonith__xe_get_result(op_reply, &result);
1630 
1631  if ((call_options & st_opt_discard_reply) || output_data == NULL) {
1632  crm_trace("Discarding reply");
1633 
1634  } else {
1635  *output_data = op_reply;
1636  op_reply = NULL; /* Prevent subsequent free */
1637  }
1638 
1639  } else if (reply_id <= 0) {
1640  crm_err("Received bad reply: No id set");
1641  crm_log_xml_err(op_reply, "Bad reply");
1642  free_xml(op_reply);
1643  op_reply = NULL;
1644  rc = -ENOMSG;
1645 
1646  } else {
1647  crm_err("Received bad reply: %d (wanted %d)", reply_id, stonith->call_id);
1648  crm_log_xml_err(op_reply, "Old reply");
1649  free_xml(op_reply);
1650  op_reply = NULL;
1651  rc = -ENOMSG;
1652  }
1653 
1654  done:
1655  if (!crm_ipc_connected(native->ipc)) {
1656  crm_err("Fencer disconnected");
1657  free(native->token); native->token = NULL;
1658  stonith->state = stonith_disconnected;
1659  }
1660 
1661  free_xml(op_reply);
1662  return rc;
1663 }
1664 
1665 /* Not used with mainloop */
1666 bool
1668 {
1669  gboolean stay_connected = TRUE;
1670  stonith_private_t *private = NULL;
1671 
1672  pcmk__assert(st != NULL);
1673  private = st->st_private;
1674 
1675  while (crm_ipc_ready(private->ipc)) {
1676 
1677  if (crm_ipc_read(private->ipc) > 0) {
1678  const char *msg = crm_ipc_buffer(private->ipc);
1679 
1680  stonith_dispatch_internal(msg, strlen(msg), st);
1681  }
1682 
1683  if (!crm_ipc_connected(private->ipc)) {
1684  crm_err("Connection closed");
1685  stay_connected = FALSE;
1686  }
1687  }
1688 
1689  return stay_connected;
1690 }
1691 
1692 static int
1693 stonith_api_free(stonith_t * stonith)
1694 {
1695  int rc = pcmk_ok;
1696 
1697  crm_trace("Destroying %p", stonith);
1698 
1699  if (stonith->state != stonith_disconnected) {
1700  crm_trace("Unregistering notifications and disconnecting %p first",
1701  stonith);
1702  stonith->cmds->remove_notification(stonith, NULL);
1703  rc = stonith->cmds->disconnect(stonith);
1704  }
1705 
1706  if (stonith->state == stonith_disconnected) {
1707  stonith_private_t *private = stonith->st_private;
1708 
1709  crm_trace("Removing %d callbacks", g_hash_table_size(private->stonith_op_callback_table));
1710  g_hash_table_destroy(private->stonith_op_callback_table);
1711 
1712  crm_trace("Destroying %d notification clients", g_list_length(private->notify_list));
1713  g_list_free_full(private->notify_list, free);
1714 
1715  free(stonith->st_private);
1716  free(stonith->cmds);
1717  free(stonith);
1718 
1719  } else {
1720  crm_err("Not free'ing active connection: %s (%d)", pcmk_strerror(rc), rc);
1721  }
1722 
1723  return rc;
1724 }
1725 
1726 void
1728 {
1729  crm_trace("Destroying %p", stonith);
1730  if(stonith) {
1731  stonith->cmds->free(stonith);
1732  }
1733 }
1734 
1735 static int
1736 stonith_api_validate(stonith_t *st, int call_options, const char *rsc_id,
1737  const char *namespace_s, const char *agent,
1738  const stonith_key_value_t *params, int timeout_sec,
1739  char **output, char **error_output)
1740 {
1741  /* Validation should be done directly via the agent, so we can get it from
1742  * stonith_admin when the cluster is not running, which is important for
1743  * higher-level tools.
1744  */
1745 
1746  int rc = pcmk_ok;
1747 
1748  /* Use a dummy node name in case the agent requires a target. We assume the
1749  * actual target doesn't matter for validation purposes (if in practice,
1750  * that is incorrect, we will need to allow the caller to pass the target).
1751  */
1752  const char *target = "node1";
1753  const char *host_arg = NULL;
1754 
1755  GHashTable *params_table = pcmk__strkey_table(free, free);
1756 
1757  // Convert parameter list to a hash table
1758  for (; params; params = params->next) {
1759  if (pcmk__str_eq(params->key, PCMK_STONITH_HOST_ARGUMENT,
1760  pcmk__str_none)) {
1761  host_arg = params->value;
1762  }
1763  if (!pcmk_stonith_param(params->key)) {
1764  pcmk__insert_dup(params_table, params->key, params->value);
1765  }
1766  }
1767 
1768 #if SUPPORT_CIBSECRETS
1769  rc = pcmk__substitute_secrets(rsc_id, params_table);
1770  if (rc != pcmk_rc_ok) {
1771  crm_warn("Could not replace secret parameters for validation of %s: %s",
1772  agent, pcmk_rc_str(rc));
1773  // rc is standard return value, don't return it in this function
1774  }
1775 #endif
1776 
1777  if (output) {
1778  *output = NULL;
1779  }
1780  if (error_output) {
1781  *error_output = NULL;
1782  }
1783 
1784  if (timeout_sec <= 0) {
1785  timeout_sec = PCMK_DEFAULT_METADATA_TIMEOUT_MS; // Questionable
1786  }
1787 
1788  switch (stonith_get_namespace(agent, namespace_s)) {
1789  case st_namespace_rhcs:
1790  rc = stonith__rhcs_validate(st, call_options, target, agent,
1791  params_table, host_arg, timeout_sec,
1792  output, error_output);
1793  break;
1794 
1795 #if HAVE_STONITH_STONITH_H
1796  case st_namespace_lha:
1797  rc = stonith__lha_validate(st, call_options, target, agent,
1798  params_table, timeout_sec, output,
1799  error_output);
1800  break;
1801 #endif
1802 
1803  case st_namespace_invalid:
1804  errno = ENOENT;
1805  rc = -errno;
1806 
1807  if (error_output) {
1808  *error_output = crm_strdup_printf("Agent %s not found", agent);
1809  } else {
1810  crm_err("Agent %s not found", agent);
1811  }
1812 
1813  break;
1814 
1815  default:
1816  errno = EOPNOTSUPP;
1817  rc = -errno;
1818 
1819  if (error_output) {
1820  *error_output = crm_strdup_printf("Agent %s does not support validation",
1821  agent);
1822  } else {
1823  crm_err("Agent %s does not support validation", agent);
1824  }
1825 
1826  break;
1827  }
1828 
1829  g_hash_table_destroy(params_table);
1830  return rc;
1831 }
1832 
1833 stonith_t *
1835 {
1836  stonith_t *new_stonith = NULL;
1837  stonith_private_t *private = NULL;
1838 
1839  new_stonith = calloc(1, sizeof(stonith_t));
1840  if (new_stonith == NULL) {
1841  return NULL;
1842  }
1843 
1844  private = calloc(1, sizeof(stonith_private_t));
1845  if (private == NULL) {
1846  free(new_stonith);
1847  return NULL;
1848  }
1849  new_stonith->st_private = private;
1850 
1851  private->stonith_op_callback_table = pcmk__intkey_table(stonith_destroy_op_callback);
1852  private->notify_list = NULL;
1853  private->notify_refcnt = 0;
1854  private->notify_deletes = FALSE;
1855 
1856  new_stonith->call_id = 1;
1857  new_stonith->state = stonith_disconnected;
1858 
1859  new_stonith->cmds = calloc(1, sizeof(stonith_api_operations_t));
1860  if (new_stonith->cmds == NULL) {
1861  free(new_stonith->st_private);
1862  free(new_stonith);
1863  return NULL;
1864  }
1865 
1866 /* *INDENT-OFF* */
1867  new_stonith->cmds->free = stonith_api_free;
1868  new_stonith->cmds->connect = stonith_api_signon;
1869  new_stonith->cmds->disconnect = stonith_api_signoff;
1870 
1871  new_stonith->cmds->list = stonith_api_list;
1872  new_stonith->cmds->monitor = stonith_api_monitor;
1873  new_stonith->cmds->status = stonith_api_status;
1874  new_stonith->cmds->fence = stonith_api_fence;
1875  new_stonith->cmds->fence_with_delay = stonith_api_fence_with_delay;
1876  new_stonith->cmds->confirm = stonith_api_confirm;
1877  new_stonith->cmds->history = stonith_api_history;
1878 
1879  new_stonith->cmds->list_agents = stonith_api_device_list;
1880  new_stonith->cmds->metadata = stonith_api_device_metadata;
1881 
1882  new_stonith->cmds->query = stonith_api_query;
1883  new_stonith->cmds->remove_device = stonith_api_remove_device;
1884  new_stonith->cmds->register_device = stonith_api_register_device;
1885 
1886  new_stonith->cmds->remove_level = stonith_api_remove_level;
1887  new_stonith->cmds->remove_level_full = stonith_api_remove_level_full;
1888  new_stonith->cmds->register_level = stonith_api_register_level;
1889  new_stonith->cmds->register_level_full = stonith_api_register_level_full;
1890 
1891  new_stonith->cmds->remove_callback = stonith_api_del_callback;
1892  new_stonith->cmds->register_callback = stonith_api_add_callback;
1893  new_stonith->cmds->remove_notification = stonith_api_del_notification;
1894  new_stonith->cmds->register_notification = stonith_api_add_notification;
1895 
1896  new_stonith->cmds->validate = stonith_api_validate;
1897 /* *INDENT-ON* */
1898 
1899  return new_stonith;
1900 }
1901 
1911 int
1912 stonith_api_connect_retry(stonith_t *st, const char *name, int max_attempts)
1913 {
1914  int rc = -EINVAL; // if max_attempts is not positive
1915 
1916  for (int attempt = 1; attempt <= max_attempts; attempt++) {
1917  rc = st->cmds->connect(st, name, NULL);
1918  if (rc == pcmk_ok) {
1919  return pcmk_ok;
1920  } else if (attempt < max_attempts) {
1921  crm_notice("Fencer connection attempt %d of %d failed (retrying in 2s): %s "
1922  CRM_XS " rc=%d",
1923  attempt, max_attempts, pcmk_strerror(rc), rc);
1924  sleep(2);
1925  }
1926  }
1927  crm_notice("Could not connect to fencer: %s " CRM_XS " rc=%d",
1928  pcmk_strerror(rc), rc);
1929  return rc;
1930 }
1931 
1933 stonith_key_value_add(stonith_key_value_t * head, const char *key, const char *value)
1934 {
1935  stonith_key_value_t *p, *end;
1936 
1937  p = pcmk__assert_alloc(1, sizeof(stonith_key_value_t));
1938  p->key = pcmk__str_copy(key);
1939  p->value = pcmk__str_copy(value);
1940 
1941  end = head;
1942  while (end && end->next) {
1943  end = end->next;
1944  }
1945 
1946  if (end) {
1947  end->next = p;
1948  } else {
1949  head = p;
1950  }
1951 
1952  return head;
1953 }
1954 
1955 void
1956 stonith_key_value_freeall(stonith_key_value_t * head, int keys, int values)
1957 {
1959 
1960  while (head) {
1961  p = head->next;
1962  if (keys) {
1963  free(head->key);
1964  }
1965  if (values) {
1966  free(head->value);
1967  }
1968  free(head);
1969  head = p;
1970  }
1971 }
1972 
1973 #define api_log_open() openlog("stonith-api", LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON)
1974 #define api_log(level, fmt, args...) syslog(level, "%s: "fmt, __func__, args)
1975 
1976 int
1977 stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
1978 {
1979  int rc = pcmk_ok;
1981  const char *action = off? PCMK_ACTION_OFF : PCMK_ACTION_REBOOT;
1982 
1983  api_log_open();
1984  if (st == NULL) {
1985  api_log(LOG_ERR, "API initialization failed, could not kick (%s) node %u/%s",
1986  action, nodeid, uname);
1987  return -EPROTO;
1988  }
1989 
1990  rc = st->cmds->connect(st, "stonith-api", NULL);
1991  if (rc != pcmk_ok) {
1992  api_log(LOG_ERR, "Connection failed, could not kick (%s) node %u/%s : %s (%d)",
1993  action, nodeid, uname, pcmk_strerror(rc), rc);
1994  } else {
1995  char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
1996  int opts = 0;
1997 
2000  if ((uname == NULL) && (nodeid > 0)) {
2002  }
2003  rc = st->cmds->fence(st, opts, name, action, timeout, 0);
2004  free(name);
2005 
2006  if (rc != pcmk_ok) {
2007  api_log(LOG_ERR, "Could not kick (%s) node %u/%s : %s (%d)",
2008  action, nodeid, uname, pcmk_strerror(rc), rc);
2009  } else {
2010  api_log(LOG_NOTICE, "Node %u/%s kicked: %s", nodeid, uname, action);
2011  }
2012  }
2013 
2015  return rc;
2016 }
2017 
2018 time_t
2019 stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
2020 {
2021  int rc = pcmk_ok;
2022  time_t when = 0;
2024  stonith_history_t *history = NULL, *hp = NULL;
2025 
2026  if (st == NULL) {
2027  api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: "
2028  "API initialization failed", nodeid, uname);
2029  return when;
2030  }
2031 
2032  rc = st->cmds->connect(st, "stonith-api", NULL);
2033  if (rc != pcmk_ok) {
2034  api_log(LOG_NOTICE, "Connection failed: %s (%d)", pcmk_strerror(rc), rc);
2035  } else {
2036  int entries = 0;
2037  int progress = 0;
2038  int completed = 0;
2039  int opts = 0;
2040  char *name = (uname == NULL)? pcmk__itoa(nodeid) : strdup(uname);
2041 
2043  if ((uname == NULL) && (nodeid > 0)) {
2045  }
2046  rc = st->cmds->history(st, opts, name, &history, 120);
2047  free(name);
2048 
2049  for (hp = history; hp; hp = hp->next) {
2050  entries++;
2051  if (in_progress) {
2052  progress++;
2053  if (hp->state != st_done && hp->state != st_failed) {
2054  when = time(NULL);
2055  }
2056 
2057  } else if (hp->state == st_done) {
2058  completed++;
2059  if (hp->completed > when) {
2060  when = hp->completed;
2061  }
2062  }
2063  }
2064 
2065  stonith_history_free(history);
2066 
2067  if(rc == pcmk_ok) {
2068  api_log(LOG_INFO, "Found %d entries for %u/%s: %d in progress, %d completed", entries, nodeid, uname, progress, completed);
2069  } else {
2070  api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: %s (%d)", nodeid, uname, pcmk_strerror(rc), rc);
2071  }
2072  }
2073 
2075 
2076  if(when) {
2077  api_log(LOG_INFO, "Node %u/%s last kicked at: %ld", nodeid, uname, (long int)when);
2078  }
2079  return when;
2080 }
2081 
2082 bool
2083 stonith_agent_exists(const char *agent, int timeout)
2084 {
2085  stonith_t *st = NULL;
2086  stonith_key_value_t *devices = NULL;
2087  stonith_key_value_t *dIter = NULL;
2088  bool rc = FALSE;
2089 
2090  if (agent == NULL) {
2091  return rc;
2092  }
2093 
2094  st = stonith_api_new();
2095  if (st == NULL) {
2096  crm_err("Could not list fence agents: API memory allocation failed");
2097  return FALSE;
2098  }
2099  st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, timeout == 0 ? 120 : timeout);
2100 
2101  for (dIter = devices; dIter != NULL; dIter = dIter->next) {
2102  if (pcmk__str_eq(dIter->value, agent, pcmk__str_none)) {
2103  rc = TRUE;
2104  break;
2105  }
2106  }
2107 
2108  stonith_key_value_freeall(devices, 1, 1);
2110  return rc;
2111 }
2112 
2113 const char *
2115 {
2116  if (action == NULL) {
2117  return "fencing";
2118  } else if (strcmp(action, PCMK_ACTION_ON) == 0) {
2119  return "unfencing";
2120  } else if (strcmp(action, PCMK_ACTION_OFF) == 0) {
2121  return "turning off";
2122  } else {
2123  return action;
2124  }
2125 }
2126 
2135 static void
2136 parse_list_line(const char *line, int len, GList **output)
2137 {
2138  size_t i = 0;
2139  size_t entry_start = 0;
2140 
2141  /* Skip complaints about additional parameters device doesn't understand
2142  *
2143  * @TODO Document or eliminate the implied restriction of target names
2144  */
2145  if (strstr(line, "invalid") || strstr(line, "variable")) {
2146  crm_debug("Skipping list output line: %s", line);
2147  return;
2148  }
2149 
2150  // Process line content, character by character
2151  for (i = 0; i <= len; i++) {
2152 
2153  if (isspace(line[i]) || (line[i] == ',') || (line[i] == ';')
2154  || (line[i] == '\0')) {
2155  // We've found a separator (i.e. the end of an entry)
2156 
2157  int rc = 0;
2158  char *entry = NULL;
2159 
2160  if (i == entry_start) {
2161  // Skip leading and sequential separators
2162  entry_start = i + 1;
2163  continue;
2164  }
2165 
2166  entry = pcmk__assert_alloc(i - entry_start + 1, sizeof(char));
2167 
2168  /* Read entry, stopping at first separator
2169  *
2170  * @TODO Document or eliminate these character restrictions
2171  */
2172  rc = sscanf(line + entry_start, "%[a-zA-Z0-9_-.]", entry);
2173  if (rc != 1) {
2174  crm_warn("Could not parse list output entry: %s "
2175  CRM_XS " entry_start=%d position=%d",
2176  line + entry_start, entry_start, i);
2177  free(entry);
2178 
2179  } else if (pcmk__strcase_any_of(entry, PCMK_ACTION_ON,
2180  PCMK_ACTION_OFF, NULL)) {
2181  /* Some agents print the target status in the list output,
2182  * though none are known now (the separate list-status command
2183  * is used for this, but it can also print "UNKNOWN"). To handle
2184  * this possibility, skip such entries.
2185  *
2186  * @TODO Document or eliminate the implied restriction of target
2187  * names.
2188  */
2189  free(entry);
2190 
2191  } else {
2192  // We have a valid entry
2193  *output = g_list_append(*output, entry);
2194  }
2195  entry_start = i + 1;
2196  }
2197  }
2198 }
2199 
2221 GList *
2222 stonith__parse_targets(const char *target_spec)
2223 {
2224  GList *targets = NULL;
2225 
2226  if (target_spec != NULL) {
2227  size_t out_len = strlen(target_spec);
2228  size_t line_start = 0; // Starting index of line being processed
2229 
2230  for (size_t i = 0; i <= out_len; ++i) {
2231  if ((target_spec[i] == '\n') || (target_spec[i] == '\0')
2232  || ((target_spec[i] == '\\') && (target_spec[i + 1] == 'n'))) {
2233  // We've reached the end of one line of output
2234 
2235  int len = i - line_start;
2236 
2237  if (len > 0) {
2238  char *line = strndup(target_spec + line_start, len);
2239 
2240  line[len] = '\0'; // Because it might be a newline
2241  parse_list_line(line, len, &targets);
2242  free(line);
2243  }
2244  if (target_spec[i] == '\\') {
2245  ++i; // backslash-n takes up two positions
2246  }
2247  line_start = i + 1;
2248  }
2249  }
2250  }
2251  return targets;
2252 }
2253 
2265 const char *
2267  const stonith_history_t *top_history)
2268 {
2269  const char *other = NULL;
2270 
2271  for (const stonith_history_t *prev_hp = top_history;
2272  prev_hp != NULL; prev_hp = prev_hp->next) {
2273  if (prev_hp == event) {
2274  break;
2275  }
2276  if ((prev_hp->state == st_done) &&
2277  pcmk__str_eq(event->target, prev_hp->target, pcmk__str_casei) &&
2278  pcmk__str_eq(event->action, prev_hp->action, pcmk__str_none) &&
2279  ((event->completed < prev_hp->completed) ||
2280  ((event->completed == prev_hp->completed) && (event->completed_nsec < prev_hp->completed_nsec)))) {
2281 
2282  if ((event->delegate == NULL)
2283  || pcmk__str_eq(event->delegate, prev_hp->delegate,
2284  pcmk__str_casei)) {
2285  // Prefer equivalent fencing by same executioner
2286  return prev_hp->delegate;
2287 
2288  } else if (other == NULL) {
2289  // Otherwise remember first successful executioner
2290  other = (prev_hp->delegate == NULL)? "some node" : prev_hp->delegate;
2291  }
2292  }
2293  }
2294  return other;
2295 }
2296 
2307 {
2308  stonith_history_t *new = NULL, *pending = NULL, *hp, *np, *tmp;
2309 
2310  for (hp = history; hp; ) {
2311  tmp = hp->next;
2312  if ((hp->state == st_done) || (hp->state == st_failed)) {
2313  /* sort into new */
2314  if ((!new) || (hp->completed > new->completed) ||
2315  ((hp->completed == new->completed) && (hp->completed_nsec > new->completed_nsec))) {
2316  hp->next = new;
2317  new = hp;
2318  } else {
2319  np = new;
2320  do {
2321  if ((!np->next) || (hp->completed > np->next->completed) ||
2322  ((hp->completed == np->next->completed) && (hp->completed_nsec > np->next->completed_nsec))) {
2323  hp->next = np->next;
2324  np->next = hp;
2325  break;
2326  }
2327  np = np->next;
2328  } while (1);
2329  }
2330  } else {
2331  /* put into pending */
2332  hp->next = pending;
2333  pending = hp;
2334  }
2335  hp = tmp;
2336  }
2337 
2338  /* pending actions don't have a completed-stamp so make them go front */
2339  if (pending) {
2340  stonith_history_t *last_pending = pending;
2341 
2342  while (last_pending->next) {
2343  last_pending = last_pending->next;
2344  }
2345 
2346  last_pending->next = new;
2347  new = pending;
2348  }
2349  return new;
2350 }
2351 
2359 const char *
2361 {
2362  switch (state) {
2363  case st_query: return "querying";
2364  case st_exec: return "executing";
2365  case st_done: return "completed";
2366  case st_duplicate: return "duplicate";
2367  case st_failed: return "failed";
2368  }
2369  return "unknown";
2370 }
2371 
2374  bool (*matching_fn)(stonith_history_t *, void *),
2375  void *user_data)
2376 {
2377  for (stonith_history_t *hp = history; hp; hp = hp->next) {
2378  if (matching_fn(hp, user_data)) {
2379  return hp;
2380  }
2381  }
2382 
2383  return NULL;
2384 }
2385 
2386 bool
2388 {
2389  return history->state != st_failed && history->state != st_done;
2390 }
2391 
2392 bool
2393 stonith__event_state_eq(stonith_history_t *history, void *user_data)
2394 {
2395  return history->state == GPOINTER_TO_INT(user_data);
2396 }
2397 
2398 bool
2400 {
2401  return history->state != GPOINTER_TO_INT(user_data);
2402 }
2403 
2404 void
2405 stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name,
2406  xmlNode *metadata)
2407 {
2408  xmlXPathObjectPtr xpath = NULL;
2409  int max = 0;
2410  int lpc = 0;
2411 
2412  CRM_CHECK((device_flags != NULL) && (metadata != NULL), return);
2413 
2414  xpath = xpath_search(metadata, "//" PCMK_XE_PARAMETER);
2415  max = numXpathResults(xpath);
2416 
2417  if (max <= 0) {
2418  freeXpathObject(xpath);
2419  return;
2420  }
2421 
2422  for (lpc = 0; lpc < max; lpc++) {
2423  const char *parameter = NULL;
2424  xmlNode *match = getXpathResult(xpath, lpc);
2425 
2426  CRM_LOG_ASSERT(match != NULL);
2427  if (match == NULL) {
2428  continue;
2429  }
2430 
2431  parameter = crm_element_value(match, PCMK_XA_NAME);
2432 
2433  if (pcmk__str_eq(parameter, "plug", pcmk__str_casei)) {
2434  stonith__set_device_flags(*device_flags, device_name,
2436 
2437  } else if (pcmk__str_eq(parameter, "port", pcmk__str_casei)) {
2438  stonith__set_device_flags(*device_flags, device_name,
2440  }
2441  }
2442 
2443  freeXpathObject(xpath);
2444 }
2445 
2465 int
2466 stonith__metadata_async(const char *agent, int timeout_sec,
2467  void (*callback)(int pid,
2469  void *user_data),
2470  void *user_data)
2471 {
2472  switch (stonith_get_namespace(agent, NULL)) {
2473  case st_namespace_rhcs:
2474  {
2475  stonith_action_t *action = NULL;
2476  int rc = pcmk_ok;
2477 
2479  NULL, 0, timeout_sec, NULL,
2480  NULL, NULL);
2481 
2482  rc = stonith__execute_async(action, user_data, callback, NULL);
2483  if (rc != pcmk_ok) {
2484  callback(0, stonith__action_result(action), user_data);
2486  }
2487  return pcmk_legacy2rc(rc);
2488  }
2489 
2490 #if HAVE_STONITH_STONITH_H
2491  case st_namespace_lha:
2492  // LHA metadata is simply synthesized, so simulate async
2493  {
2496  .execution_status = PCMK_EXEC_DONE,
2497  .exit_reason = NULL,
2498  .action_stdout = NULL,
2499  .action_stderr = NULL,
2500  };
2501 
2502  stonith__lha_metadata(agent, timeout_sec,
2504  callback(0, &result, user_data);
2506  return pcmk_rc_ok;
2507  }
2508 #endif
2509 
2510  default:
2511  {
2514  .execution_status = PCMK_EXEC_ERROR_HARD,
2515  .exit_reason = crm_strdup_printf("No such agent '%s'",
2516  agent),
2517  .action_stdout = NULL,
2518  .action_stderr = NULL,
2519  };
2520 
2521  callback(0, &result, user_data);
2523  return ENOENT;
2524  }
2525  }
2526 }
2527 
2536 int
2538 {
2539  if ((data == NULL) || (data->opaque == NULL)) {
2540  return CRM_EX_ERROR;
2541  }
2542  return ((pcmk__action_result_t *) data->opaque)->exit_status;
2543 }
2544 
2553 int
2555 {
2556  if ((data == NULL) || (data->opaque == NULL)) {
2557  return PCMK_EXEC_UNKNOWN;
2558  }
2559  return ((pcmk__action_result_t *) data->opaque)->execution_status;
2560 }
2561 
2570 const char *
2572 {
2573  if ((data == NULL) || (data->opaque == NULL)) {
2574  return NULL;
2575  }
2576  return ((pcmk__action_result_t *) data->opaque)->exit_reason;
2577 }
2578 
2587 int
2589 {
2590  if ((event == NULL) || (event->opaque == NULL)) {
2591  return CRM_EX_ERROR;
2592  } else {
2593  struct event_private *event_private = event->opaque;
2594 
2595  return event_private->result.exit_status;
2596  }
2597 }
2598 
2607 int
2609 {
2610  if ((event == NULL) || (event->opaque == NULL)) {
2611  return PCMK_EXEC_UNKNOWN;
2612  } else {
2613  struct event_private *event_private = event->opaque;
2614 
2615  return event_private->result.execution_status;
2616  }
2617 }
2618 
2627 const char *
2629 {
2630  if ((event == NULL) || (event->opaque == NULL)) {
2631  return NULL;
2632  } else {
2633  struct event_private *event_private = event->opaque;
2634 
2635  return event_private->result.exit_reason;
2636  }
2637 }
2638 
2649 char *
2651 {
2652  // Use somewhat readable defaults
2653  const char *origin = pcmk__s(event->client_origin, "a client");
2654  const char *origin_node = pcmk__s(event->origin, "a node");
2655  const char *executioner = pcmk__s(event->executioner, "the cluster");
2656  const char *device = pcmk__s(event->device, "unknown");
2657  const char *action = pcmk__s(event->action, event->operation);
2658  const char *target = pcmk__s(event->target, "no node");
2659  const char *reason = stonith__event_exit_reason(event);
2660  const char *status;
2661 
2662  if (action == NULL) {
2663  action = "(unknown)";
2664  }
2665 
2667  status = pcmk_exec_status_str(stonith__event_execution_status(event));
2668  } else if (stonith__event_exit_status(event) != CRM_EX_OK) {
2669  status = pcmk_exec_status_str(PCMK_EXEC_ERROR);
2670  } else {
2671  status = crm_exit_str(CRM_EX_OK);
2672  }
2673 
2674  if (pcmk__str_eq(event->operation, PCMK__VALUE_ST_NOTIFY_HISTORY,
2675  pcmk__str_none)) {
2676  return crm_strdup_printf("Fencing history may have changed");
2677 
2678  } else if (pcmk__str_eq(event->operation, STONITH_OP_DEVICE_ADD,
2679  pcmk__str_none)) {
2680  return crm_strdup_printf("A fencing device (%s) was added", device);
2681 
2682  } else if (pcmk__str_eq(event->operation, STONITH_OP_DEVICE_DEL,
2683  pcmk__str_none)) {
2684  return crm_strdup_printf("A fencing device (%s) was removed", device);
2685 
2686  } else if (pcmk__str_eq(event->operation, STONITH_OP_LEVEL_ADD,
2687  pcmk__str_none)) {
2688  return crm_strdup_printf("A fencing topology level (%s) was added",
2689  device);
2690 
2691  } else if (pcmk__str_eq(event->operation, STONITH_OP_LEVEL_DEL,
2692  pcmk__str_none)) {
2693  return crm_strdup_printf("A fencing topology level (%s) was removed",
2694  device);
2695  }
2696 
2697  // event->operation should be PCMK__VALUE_ST_NOTIFY_FENCE at this point
2698 
2699  return crm_strdup_printf("Operation %s of %s by %s for %s@%s: %s%s%s%s (ref=%s)",
2700  action, target, executioner, origin, origin_node,
2701  status,
2702  ((reason == NULL)? "" : " ("), pcmk__s(reason, ""),
2703  ((reason == NULL)? "" : ")"),
2704  pcmk__s(event->id, "(none)"));
2705 }
2706 
2707 
2708 // Deprecated functions kept only for backward API compatibility
2709 // LCOV_EXCL_START
2710 
2711 const char *get_stonith_provider(const char *agent, const char *provider);
2712 
2713 const char *
2714 get_stonith_provider(const char *agent, const char *provider)
2715 {
2716  return stonith_namespace2text(stonith_get_namespace(agent, provider));
2717 }
2718 
2719 // LCOV_EXCL_STOP
2720 // End deprecated API
void stonith__destroy_action(stonith_action_t *action)
Definition: st_actions.c:215
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:245
#define PCMK__XA_ST_DELEGATE
struct stonith_action_s stonith_action_t
Definition: internal.h:51
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:567
void stonith_history_free(stonith_history_t *history)
Definition: st_client.c:762
#define PCMK__XA_ST_CALLID
#define PCMK__VALUE_STONITH_NG
#define PCMK__XA_ST_TOLERANCE
int stonith__event_execution_status(const stonith_event_t *event)
Definition: st_client.c:2608
struct stonith_history_s * next
Definition: stonith-ng.h:137
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition: xml.c:974
#define PCMK__VALUE_ST_NOTIFY
A dumping ground.
#define PCMK__XA_NAMESPACE
Invoke callback only if request succeeded.
Definition: stonith-ng.h:86
#define crm_notice(fmt, args...)
Definition: logging.h:397
const char * pcmk_strerror(int rc)
Definition: results.c:151
#define PCMK_XA_NAME
Definition: xml_names.h:330
#define PCMK__XA_ST_CALLOPT
char data[0]
Definition: cpg.c:58
void stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name, xmlNode *metadata)
Definition: st_client.c:2405
stonith_t * stonith
Definition: st_client.c:79
#define api_log_open()
Definition: st_client.c:1973
int stonith__legacy2status(int rc)
Definition: st_actions.c:400
#define PCMK__XA_ST_DEVICE_ID
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition: nvpair.c:820
Requested item does not exist.
Definition: results.h:287
int pcmk_rc2legacy(int rc)
Definition: results.c:548
bool stonith__event_state_neq(stonith_history_t *history, void *user_data)
Definition: st_client.c:2399
const char * name
Definition: cib.c:26
#define PCMK_ACTION_LIST
Definition: actions.h:52
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1038
stonith_key_value_t * stonith_key_value_add(stonith_key_value_t *head, const char *key, const char *value)
Definition: st_client.c:1933
#define PCMK__XA_ST_OUTPUT
void stonith_dump_pending_callbacks(stonith_t *stonith)
Definition: st_client.c:1368
Interpret target as node cluster layer ID instead of name.
Definition: stonith-ng.h:77
#define stonith__set_device_flags(device_flags, device_id, flags_to_set)
Definition: internal.h:29
#define PCMK_DEFAULT_METADATA_TIMEOUT_MS
Definition: actions.h:42
bool stonith__event_state_eq(stonith_history_t *history, void *user_data)
Definition: st_client.c:2393
#define PCMK_ACTION_ON
Definition: actions.h:64
int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
Definition: st_client.c:1977
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
#define PCMK_XA_TARGET_VALUE
Definition: xml_names.h:423
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:519
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:360
xmlNode * stonith_create_op(int call_id, const char *token, const char *op, xmlNode *data, int call_options)
Definition: st_client.c:809
int pcmk__substitute_secrets(const char *rsc_id, GHashTable *params)
Definition: cib_secrets.c:96
bool pcmk_stonith_param(const char *param)
Check whether a given stonith parameter is handled by Pacemaker.
Definition: agents.c:174
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:453
#define STONITH_OP_FENCE
Definition: internal.h:115
const char * stonith_action_str(const char *action)
Turn fence action into a more readable string.
Definition: st_client.c:2114
struct stonith_key_value_s * next
Definition: stonith-ng.h:126
#define PCMK_ACTION_MONITOR
Definition: actions.h:60
#define PCMK_XA_TARGET_PATTERN
Definition: xml_names.h:421
#define PCMK_XA_EXIT_REASON
Definition: xml_names.h:274
int stonith__result2rc(const pcmk__action_result_t *result)
Definition: st_actions.c:326
enum pcmk_exec_status execution_status
struct mainloop_io_s mainloop_io_t
Definition: mainloop.h:35
#define PCMK__XE_ATTRIBUTES
#define PCMK__XE_STONITH_COMMAND
Unspecified error.
Definition: results.h:252
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:313
const char * stonith__exit_reason(const stonith_callback_data_t *data)
Definition: st_client.c:2571
void stonith_key_value_freeall(stonith_key_value_t *head, int keys, int values)
Definition: st_client.c:1956
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:422
#define PCMK_XA_INDEX
Definition: xml_names.h:305
int stonith__lha_metadata(const char *agent, int timeout, char **output)
Definition: st_lha.c:179
#define PCMK__XA_ST_TIMEOUT
void pcmk__add_separated_word(GString **list, size_t init_size, const char *word, const char *separator)
Definition: strings.c:806
#define PCMK__VALUE_ST_NOTIFY_DISCONNECT
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:228
stonith_namespace
Definition: stonith-ng.h:106
#define PCMK__XA_SUBT
#define PCMK__XA_ST_NOTIFY_ACTIVATE
long crm_ipc_read(crm_ipc_t *client)
Definition: ipc_client.c:1158
#define PCMK__XA_RSC_PROVIDES
enum crm_ais_msg_types type
Definition: cpg.c:51
int call_id
Definition: internal.h:112
#define PCMK_XA_TARGET_ATTRIBUTE
Definition: xml_names.h:419
Action did not complete in time.
Definition: results.h:331
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:503
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:583
The fencing target is allowed to execute the request.
Definition: stonith-ng.h:53
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:494
Execution failed, do not retry on node.
Definition: results.h:334
Do not return any reply from server.
Definition: stonith-ng.h:65
#define LOG_NEVER
Definition: logging.h:48
#define STONITH_OP_NOTIFY
Definition: internal.h:122
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:189
Wrappers for and extensions to glib mainloop.
#define STONITH_OP_LEVEL_DEL
Definition: internal.h:121
#define STONITH_OP_DEVICE_ADD
Definition: internal.h:117
int(* confirm)(stonith_t *stonith, int call_options, const char *target)
Manually confirm that a node has been fenced.
Definition: stonith-ng.h:397
#define PCMK__XE_ST_CALLDATA
#define STONITH_OP_EXEC
Definition: internal.h:112
#define CRM_OP_REGISTER
Definition: crm.h:129
const char * action
Definition: pcmk_fence.c:30
const char * crm_ipc_buffer(crm_ipc_t *client)
Definition: ipc_client.c:1206
#define PCMK_XA_DEVICES
Definition: xml_names.h:264
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:304
const char * stonith_namespace2text(enum stonith_namespace st_namespace)
Get agent namespace name.
Definition: st_client.c:130
int stonith__list_lha_agents(stonith_key_value_t **devices)
Definition: st_lha.c:119
#define PCMK__XA_ST_REMOTE_OP
#define PCMK_XA_AGENT
Definition: xml_names.h:234
int(* remove_callback)(stonith_t *stonith, int call_id, bool all_callbacks)
Unregister callbacks for asynchronous fencing results.
Definition: stonith-ng.h:469
int pcmk__connect_generic_ipc(crm_ipc_t *ipc)
Definition: ipc_client.c:896
#define PCMK_ACTION_STATUS
Definition: actions.h:73
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:544
gboolean stonith__watchdog_fencing_enabled_for_node(const char *node)
Definition: st_client.c:231
time_t stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
Definition: st_client.c:2019
int(* free)(stonith_t *st)
Destroy a fencer connection.
Definition: stonith-ng.h:182
#define PCMK__XA_ST_ORIGIN
#define PCMK__XA_ST_DELAY
int timeout
Definition: internal.h:113
#define PCMK__XA_ST_DATE_NSEC
#define PCMK__UNKNOWN_RESULT
#define PCMK_ACTION_REBOOT
Definition: actions.h:68
#define crm_warn(fmt, args...)
Definition: logging.h:394
const char * stonith_op_state_str(enum op_state state)
Return string equivalent of an operation state value.
Definition: st_client.c:2360
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:1912
const char * crm_exit_str(crm_exit_t exit_code)
Definition: results.c:642
const char * stonith__later_succeeded(const stonith_history_t *event, const stonith_history_t *top_history)
Definition: st_client.c:2266
stonith_t * st
Definition: pcmk_fence.c:28
bool stonith_dispatch(stonith_t *st)
Definition: st_client.c:1667
uint32_t pid
Definition: cpg.c:49
#define crm_debug(fmt, args...)
Definition: logging.h:402
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
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:2373
#define STONITH_OP_LEVEL_ADD
Definition: internal.h:120
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:349
struct crm_ipc_s crm_ipc_t
Definition: ipc.h:184
enum stonith_state state
Definition: stonith-ng.h:575
unsigned int tolerance
Definition: pcmk_fence.c:33
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition: nvpair.c:758
Used only to initialize variables.
Definition: results.h:327
pcmk__action_result_t * stonith__action_result(stonith_action_t *action)
Definition: st_actions.c:240
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:458
#define STONITH_OP_QUERY
Definition: internal.h:114
op_state
Definition: stonith-ng.h:96
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml.c:481
GList * stonith__parse_targets(const char *target_spec)
Definition: st_client.c:2222
#define PCMK_XE_PARAMETER
Definition: xml_names.h:158
#define PCMK__VALUE_ST_NOTIFY_HISTORY
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
#define PCMK__XA_ST_CLIENTNAME
enum stonith_namespace stonith_text2namespace(const char *namespace_s)
Get agent namespace by name.
Definition: st_client.c:104
guint ref
Definition: internal.h:114
int stonith__execution_status(const stonith_callback_data_t *data)
Definition: st_client.c:2554
#define crm_trace(fmt, args...)
Definition: logging.h:404
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define stonith__set_call_options(st_call_opts, call_for, flags_to_set)
Definition: internal.h:36
#define crm_log_xml_debug(xml, text)
Definition: logging.h:411
bool stonith_agent_exists(const char *agent, int timeout)
Definition: st_client.c:2083
#define PCMK__XE_ST_DEVICE_ID
Wrappers for and extensions to libxml2.
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:263
#define crm_log_xml_warn(xml, text)
Definition: logging.h:408
Action completed, result is known.
Definition: results.h:329
void stonith__xe_get_result(const xmlNode *xml, pcmk__action_result_t *result)
Definition: st_actions.c:490
int(* disconnect)(stonith_t *st)
Disconnect from the local stonith daemon.
Definition: stonith-ng.h:203
int(* stonith_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition: st_client.c:82
enum stonith_namespace stonith_get_namespace(const char *agent, const char *namespace_s)
Determine namespace of a fence agent.
Definition: st_client.c:151
const char * get_stonith_provider(const char *agent, const char *provider)
Definition: st_client.c:2714
#define STONITH_OP_DEVICE_DEL
Definition: internal.h:118
#define ECOMM
Definition: portability.h:86
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:943
#define PCMK_XA_ID
Definition: xml_names.h:301
Success.
Definition: results.h:251
void crm_ipc_destroy(crm_ipc_t *client)
Definition: ipc_client.c:1006
int pcmk_legacy2rc(int legacy_rc)
Definition: results.c:561
G_GNUC_INTERNAL bool stonith__agent_is_rhcs(const char *agent)
Definition: st_rhcs.c:257
struct stonith_notify_client_s stonith_notify_client_t
const char * stonith__event_exit_reason(const stonith_event_t *event)
Definition: st_client.c:2628
void stonith_api_delete(stonith_t *stonith)
Definition: st_client.c:1727
void free_xml(xmlNode *child)
Definition: xml.c:958
int(* connect)(stonith_t *st, const char *name, int *stonith_fd)
Connect to the local fencer.
Definition: stonith-ng.h:194
int(* metadata)(stonith_t *stonith, int call_options, const char *agent, const char *namespace_s, char **output, int timeout_sec)
Retrieve a fence agent&#39;s metadata.
Definition: stonith-ng.h:283
char * stonith__event_description(const stonith_event_t *event)
Definition: st_client.c:2650
#define api_log(level, fmt, args...)
Definition: st_client.c:1974
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1062
#define pcmk__str_copy(str)
#define PCMK__VALUE_ST_ASYNC_TIMEOUT_VALUE
xmlNode * pcmk__xml_parse(const char *input)
Definition: xml_io.c:245
uint32_t id
Definition: cpg.c:48
#define STONITH_OP_FENCE_HISTORY
Definition: internal.h:119
stonith_history_t * stonith__sort_history(stonith_history_t *history)
Definition: st_client.c:2306
int(* remove_device)(stonith_t *st, int options, const char *name)
Unregister a fence device with the local fencer.
Definition: stonith-ng.h:215
struct stonith_private_s stonith_private_t
Wait for request to be completed before returning.
Definition: stonith-ng.h:80
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc_client.c:1068
#define pcmk__assert(expr)
const char * target
Definition: pcmk_fence.c:29
#define PCMK__XA_ST_DEVICE_ACTION
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:410
#define CRM_XS
Definition: logging.h:56
gboolean stonith__watchdog_fencing_enabled_for_node_api(stonith_t *st, const char *node)
Definition: st_client.c:172
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
Definition: ipc_client.c:1100
char * client_origin
Definition: stonith-ng.h:160
#define PCMK_STONITH_HOST_ARGUMENT
Definition: agents.h:44
xmlXPathObjectPtr xpath_search(const xmlNode *xml_top, const char *path)
Definition: xpath.c:139
G_GNUC_INTERNAL int stonith__list_rhcs_agents(stonith_key_value_t **devices)
Definition: st_rhcs.c:36
#define crm_log_xml_err(xml, text)
Definition: logging.h:407
struct stonith_callback_client_s stonith_callback_client_t
#define PCMK_XE_FENCING_LEVEL
Definition: xml_names.h:117
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:695
pcmk__action_result_t result
Definition: pcmk_fence.c:35
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:331
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
Definition: ipc_internal.h:212
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:949
#define crm_err(fmt, args...)
Definition: logging.h:391
#define G_PRIORITY_MEDIUM
Definition: mainloop.h:192
#define PCMK__XE_ST_HISTORY
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:2466
#define ENOTUNIQ
Definition: portability.h:81
int stonith__event_exit_status(const stonith_event_t *event)
Definition: st_client.c:2588
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:492
stonith_api_operations_t * cmds
Definition: stonith-ng.h:581
stonith_t * stonith_api_new(void)
Definition: st_client.c:1834
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:248
int delay
Definition: pcmk_fence.c:34
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:233
int pcmk__ipc_fd(crm_ipc_t *ipc, int *fd)
Definition: ipc_client.c:1041
#define crm_log_xml_notice(xml, text)
Definition: logging.h:409
Request that server send an update with optimal callback timeout.
Definition: stonith-ng.h:83
Fencing aka. STONITH.
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:58
char * executioner
Definition: stonith-ng.h:155
#define PCMK_ACTION_METADATA
Definition: actions.h:57
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
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 PCMK__XA_ST_DATE
char * operation
Definition: stonith-ng.h:149
char uname[MAX_NAME]
Definition: cpg.c:53
#define PCMK__XA_ST_NOTIFY_DEACTIVATE
#define PCMK__VALUE_ST_NOTIFY_FENCE
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:334
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
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:366
#define pcmk_ok
Definition: results.h:65
#define PCMK__XE_NOTIFY
bool stonith__agent_is_lha(const char *agent)
Definition: st_lha.c:92
bool stonith__event_state_pending(stonith_history_t *history, void *user_data)
Definition: st_client.c:2387
#define PCMK__XA_ST_OP
int(* list)(stonith_t *stonith, int call_options, const char *id, char **list_info, int timeout)
Get the output of a fence device&#39;s list action.
Definition: stonith-ng.h:320
void * st_private
Definition: stonith-ng.h:579
#define PCMK__XA_ST_TARGET
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:978
#define crm_log_xml_trace(xml, text)
Definition: logging.h:412
#define PCMK_ACTION_OFF
Definition: actions.h:63
#define PCMK__XA_T
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
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:384
int(* remove_notification)(stonith_t *stonith, const char *event)
Unregister callbacks for fence notifications.
Definition: stonith-ng.h:434
#define PCMK__XA_ST_STATE
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml.c:770
#define pcmk__assert_alloc(nmemb, size)
Definition: internal.h:297
#define STONITH_WATCHDOG_ID
Definition: internal.h:129
void pcmk__reset_result(pcmk__action_result_t *result)
Definition: results.c:1067
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:39
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.
Definition: ipc_client.c:1300
crm_ipc_flags
Definition: ipc.h:163
#define PCMK__XA_ST_CLIENTID
void crm_ipc_close(crm_ipc_t *client)
Definition: ipc_client.c:993
CRM_TRACE_INIT_DATA(stonith)
int stonith__exit_status(const stonith_callback_data_t *data)
Definition: st_client.c:2537
#define PCMK_XA_TARGET
Definition: xml_names.h:418
unsigned int timeout
Definition: pcmk_fence.c:32
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
Execution failed, may be retried.
Definition: results.h:333
#define crm_info(fmt, args...)
Definition: logging.h:399
int call_id
Definition: stonith-ng.h:577
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
Definition: strings.c:713
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
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source.
Definition: mainloop.h:94
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition: strings.c:993