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