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