pacemaker  2.0.5-ba59be712
Scalable High-Availability cluster resource manager
st_client.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2020 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 #include <unistd.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <stdbool.h>
15 #include <string.h>
16 #include <ctype.h>
17 #include <libgen.h>
18 
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <sys/wait.h>
22 
23 #include <glib.h>
24 
25 #include <crm/crm.h>
26 #include <crm/stonith-ng.h>
27 #include <crm/fencing/internal.h>
28 #include <crm/msg_xml.h>
29 #include <crm/common/xml.h>
31 
32 #include <crm/common/mainloop.h>
33 
34 CRM_TRACE_INIT_DATA(stonith);
35 
36 struct stonith_action_s {
38  char *agent;
39  char *action;
40  char *victim;
41  GHashTable *args;
42  int timeout;
43  int async;
44  void *userdata;
45  void (*done_cb) (GPid pid, gint status, const char *output, gpointer user_data);
46  void (*fork_cb) (GPid pid, gpointer user_data);
47 
48  svc_action_t *svc_action;
49 
51  time_t initial_start_time;
52  int tries;
53  int remaining_timeout;
54  int max_retries;
55 
56  /* device output data */
57  GPid pid;
58  int rc;
59  char *output;
60  char *error;
61 };
62 
63 typedef struct stonith_private_s {
64  char *token;
65  crm_ipc_t *ipc;
66  mainloop_io_t *source;
67  GHashTable *stonith_op_callback_table;
68  GList *notify_list;
69  int notify_refcnt;
70  bool notify_deletes;
71 
72  void (*op_callback) (stonith_t * st, stonith_callback_data_t * data);
73 
75 
76 typedef struct stonith_notify_client_s {
77  const char *event;
78  const char *obj_id; /* implement one day */
79  const char *obj_type; /* implement one day */
80  void (*notify) (stonith_t * st, stonith_event_t * e);
81  bool delete;
82 
84 
85 typedef struct stonith_callback_client_s {
86  void (*callback) (stonith_t * st, stonith_callback_data_t * data);
87  const char *id;
88  void *user_data;
89  gboolean only_success;
90  gboolean allow_timeout_updates;
91  struct timer_rec_s *timer;
92 
94 
95 struct notify_blob_s {
96  stonith_t *stonith;
97  xmlNode *xml;
98 };
99 
100 struct timer_rec_s {
101  int call_id;
102  int timeout;
103  guint ref;
105 };
106 
107 typedef int (*stonith_op_t) (const char *, int, const char *, xmlNode *,
108  xmlNode *, xmlNode *, xmlNode **, xmlNode **);
109 
111 xmlNode *stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data,
112  int call_options);
113 static int stonith_send_command(stonith_t *stonith, const char *op,
114  xmlNode *data, xmlNode **output_data,
115  int call_options, int timeout);
116 
117 static void stonith_connection_destroy(gpointer user_data);
118 static void stonith_send_notification(gpointer data, gpointer user_data);
119 static int internal_stonith_action_execute(stonith_action_t * action);
120 static void log_action(stonith_action_t *action, pid_t pid);
121 
130 stonith_text2namespace(const char *namespace_s)
131 {
132  if (pcmk__str_eq(namespace_s, "any", pcmk__str_null_matches)) {
133  return st_namespace_any;
134 
135  } else if (!strcmp(namespace_s, "redhat")
136  || !strcmp(namespace_s, "stonith-ng")) {
137  return st_namespace_rhcs;
138 
139  } else if (!strcmp(namespace_s, "internal")) {
140  return st_namespace_internal;
141 
142  } else if (!strcmp(namespace_s, "heartbeat")) {
143  return st_namespace_lha;
144  }
145  return st_namespace_invalid;
146 }
147 
155 const char *
157 {
158  switch (st_namespace) {
159  case st_namespace_any: return "any";
160  case st_namespace_rhcs: return "stonith-ng";
161  case st_namespace_internal: return "internal";
162  case st_namespace_lha: return "heartbeat";
163  default: break;
164  }
165  return "unsupported";
166 }
167 
177 stonith_get_namespace(const char *agent, const char *namespace_s)
178 {
179  if (pcmk__str_eq(namespace_s, "internal", pcmk__str_casei)) {
180  return st_namespace_internal;
181  }
182 
183  if (stonith__agent_is_rhcs(agent)) {
184  return st_namespace_rhcs;
185  }
186 
187 #if HAVE_STONITH_STONITH_H
188  if (stonith__agent_is_lha(agent)) {
189  return st_namespace_lha;
190  }
191 #endif
192 
193  crm_err("Unknown fence agent: %s", agent);
194  return st_namespace_invalid;
195 }
196 
197 static void
199 {
200  if (action->output) {
201  /* Logging the whole string confuses syslog when the string is xml */
202  char *prefix = crm_strdup_printf("%s[%d] stdout:", action->agent, pid);
203 
204  crm_log_output(LOG_TRACE, prefix, action->output);
205  free(prefix);
206  }
207 
208  if (action->error) {
209  /* Logging the whole string confuses syslog when the string is xml */
210  char *prefix = crm_strdup_printf("%s[%d] stderr:", action->agent, pid);
211 
212  crm_log_output(LOG_WARNING, prefix, action->error);
213  free(prefix);
214  }
215 }
216 
217 /* when cycling through the list we don't want to delete items
218  so just mark them and when we know nobody is using the list
219  loop over it to remove the marked items
220  */
221 static void
222 foreach_notify_entry (stonith_private_t *private,
223  GFunc func,
224  gpointer user_data)
225 {
226  private->notify_refcnt++;
227  g_list_foreach(private->notify_list, func, user_data);
228  private->notify_refcnt--;
229  if ((private->notify_refcnt == 0) &&
230  private->notify_deletes) {
231  GList *list_item = private->notify_list;
232 
233  private->notify_deletes = FALSE;
234  while (list_item != NULL)
235  {
236  stonith_notify_client_t *list_client = list_item->data;
237  GList *next = g_list_next(list_item);
238 
239  if (list_client->delete) {
240  free(list_client);
241  private->notify_list =
242  g_list_delete_link(private->notify_list, list_item);
243  }
244  list_item = next;
245  }
246  }
247 }
248 
249 static void
250 stonith_connection_destroy(gpointer user_data)
251 {
252  stonith_t *stonith = user_data;
253  stonith_private_t *native = NULL;
254  struct notify_blob_s blob;
255 
256  crm_trace("Sending destroyed notification");
257  blob.stonith = stonith;
258  blob.xml = create_xml_node(NULL, "notify");
259 
260  native = stonith->st_private;
261  native->ipc = NULL;
262  native->source = NULL;
263 
264  free(native->token); native->token = NULL;
265  stonith->state = stonith_disconnected;
266  crm_xml_add(blob.xml, F_TYPE, T_STONITH_NOTIFY);
268 
269  foreach_notify_entry(native, stonith_send_notification, &blob);
270  free_xml(blob.xml);
271 }
272 
273 xmlNode *
274 create_device_registration_xml(const char *id, enum stonith_namespace namespace,
275  const char *agent, stonith_key_value_t *params,
276  const char *rsc_provides)
277 {
278  xmlNode *data = create_xml_node(NULL, F_STONITH_DEVICE);
279  xmlNode *args = create_xml_node(data, XML_TAG_ATTRS);
280 
281 #if HAVE_STONITH_STONITH_H
282  if (namespace == st_namespace_any) {
283  namespace = stonith_get_namespace(agent, NULL);
284  }
285  if (namespace == st_namespace_lha) {
286  hash2field((gpointer) "plugin", (gpointer) agent, args);
287  agent = "fence_legacy";
288  }
289 #endif
290 
292  crm_xml_add(data, F_STONITH_ORIGIN, __func__);
293  crm_xml_add(data, "agent", agent);
294  if ((namespace != st_namespace_any) && (namespace != st_namespace_invalid)) {
295  crm_xml_add(data, "namespace", stonith_namespace2text(namespace));
296  }
297  if (rsc_provides) {
298  crm_xml_add(data, "rsc_provides", rsc_provides);
299  }
300 
301  for (; params; params = params->next) {
302  hash2field((gpointer) params->key, (gpointer) params->value, args);
303  }
304 
305  return data;
306 }
307 
308 static int
309 stonith_api_register_device(stonith_t * st, int call_options,
310  const char *id, const char *namespace, const char *agent,
311  stonith_key_value_t * params)
312 {
313  int rc = 0;
314  xmlNode *data = NULL;
315 
317  agent, params, NULL);
318 
319  rc = stonith_send_command(st, STONITH_OP_DEVICE_ADD, data, NULL, call_options, 0);
320  free_xml(data);
321 
322  return rc;
323 }
324 
325 static int
326 stonith_api_remove_device(stonith_t * st, int call_options, const char *name)
327 {
328  int rc = 0;
329  xmlNode *data = NULL;
330 
332  crm_xml_add(data, F_STONITH_ORIGIN, __func__);
334  rc = stonith_send_command(st, STONITH_OP_DEVICE_DEL, data, NULL, call_options, 0);
335  free_xml(data);
336 
337  return rc;
338 }
339 
340 static int
341 stonith_api_remove_level_full(stonith_t *st, int options,
342  const char *node, const char *pattern,
343  const char *attr, const char *value, int level)
344 {
345  int rc = 0;
346  xmlNode *data = NULL;
347 
348  CRM_CHECK(node || pattern || (attr && value), return -EINVAL);
349 
351  crm_xml_add(data, F_STONITH_ORIGIN, __func__);
352 
353  if (node) {
355 
356  } else if (pattern) {
358 
359  } else {
362  }
363 
365  rc = stonith_send_command(st, STONITH_OP_LEVEL_DEL, data, NULL, options, 0);
366  free_xml(data);
367 
368  return rc;
369 }
370 
371 static int
372 stonith_api_remove_level(stonith_t * st, int options, const char *node, int level)
373 {
374  return stonith_api_remove_level_full(st, options, node,
375  NULL, NULL, NULL, level);
376 }
377 
393 xmlNode *
394 create_level_registration_xml(const char *node, const char *pattern,
395  const char *attr, const char *value,
396  int level, stonith_key_value_t *device_list)
397 {
398  size_t len = 0;
399  char *list = NULL;
400  xmlNode *data;
401 
402  CRM_CHECK(node || pattern || (attr && value), return NULL);
403 
405  CRM_CHECK(data, return NULL);
406 
407  crm_xml_add(data, F_STONITH_ORIGIN, __func__);
410 
411  if (node) {
413 
414  } else if (pattern) {
416 
417  } else {
420  }
421 
422  // cppcheck seems not to understand the abort logic behind pcmk__realloc
423  // cppcheck-suppress memleak
424  for (; device_list; device_list = device_list->next) {
425  pcmk__add_separated_word(&list, &len, device_list->value, ",");
426  }
427 
429 
430  free(list);
431  return data;
432 }
433 
434 static int
435 stonith_api_register_level_full(stonith_t * st, int options, const char *node,
436  const char *pattern,
437  const char *attr, const char *value,
438  int level, stonith_key_value_t *device_list)
439 {
440  int rc = 0;
441  xmlNode *data = create_level_registration_xml(node, pattern, attr, value,
442  level, device_list);
443  CRM_CHECK(data != NULL, return -EINVAL);
444 
445  rc = stonith_send_command(st, STONITH_OP_LEVEL_ADD, data, NULL, options, 0);
446  free_xml(data);
447 
448  return rc;
449 }
450 
451 static int
452 stonith_api_register_level(stonith_t * st, int options, const char *node, int level,
453  stonith_key_value_t * device_list)
454 {
455  return stonith_api_register_level_full(st, options, node, NULL, NULL, NULL,
456  level, device_list);
457 }
458 
459 static void
460 append_arg(const char *key, const char *value, GHashTable **args)
461 {
462  CRM_CHECK(key != NULL, return);
463  CRM_CHECK(value != NULL, return);
464  CRM_CHECK(args != NULL, return);
465 
466  if (strstr(key, "pcmk_")) {
467  return;
468  } else if (strstr(key, CRM_META)) {
469  return;
470  } else if (pcmk__str_eq(key, "crm_feature_set", pcmk__str_casei)) {
471  return;
472  }
473 
474  if (!*args) {
475  *args = crm_str_table_new();
476  }
477 
478  CRM_CHECK(*args != NULL, return);
479  crm_trace("Appending: %s=%s", key, value);
480  g_hash_table_replace(*args, strdup(key), strdup(value));
481 }
482 
483 static void
484 append_config_arg(gpointer key, gpointer value, gpointer user_data)
485 {
486  /* The fencer will filter action out when it registers the device,
487  * but ignore it here just in case any other library callers
488  * fail to do so.
489  */
490  if (!pcmk__str_eq(key, STONITH_ATTR_ACTION_OP, pcmk__str_casei)) {
491  append_arg(key, value, user_data);
492  return;
493  }
494 }
495 
496 static GHashTable *
497 make_args(const char *agent, const char *action, const char *victim,
498  uint32_t victim_nodeid, GHashTable * device_args,
499  GHashTable * port_map, const char *host_arg)
500 {
501  char buffer[512];
502  GHashTable *arg_list = NULL;
503  const char *value = NULL;
504 
505  CRM_CHECK(action != NULL, return NULL);
506 
507  snprintf(buffer, sizeof(buffer), "pcmk_%s_action", action);
508  if (device_args) {
509  value = g_hash_table_lookup(device_args, buffer);
510  }
511  if (value) {
512  crm_debug("Substituting action '%s' for requested operation '%s'", value, action);
513  action = value;
514  }
515 
516  append_arg(STONITH_ATTR_ACTION_OP, action, &arg_list);
517  if (victim && device_args) {
518  const char *alias = victim;
519  const char *param = g_hash_table_lookup(device_args, STONITH_ATTR_HOSTARG);
520 
521  if (port_map && g_hash_table_lookup(port_map, victim)) {
522  alias = g_hash_table_lookup(port_map, victim);
523  }
524 
525  /* Always supply the node's name, too:
526  * https://github.com/ClusterLabs/fence-agents/blob/master/doc/FenceAgentAPI.md
527  */
528  append_arg("nodename", victim, &arg_list);
529  if (victim_nodeid) {
530  char nodeid_str[33] = { 0, };
531  if (snprintf(nodeid_str, 33, "%u", (unsigned int)victim_nodeid)) {
532  crm_info("For stonith action (%s) for victim %s, adding nodeid (%s) to parameters",
533  action, victim, nodeid_str);
534  append_arg("nodeid", nodeid_str, &arg_list);
535  }
536  }
537 
538  /* Check if we need to supply the victim in any other form */
539  if(pcmk__str_eq(agent, "fence_legacy", pcmk__str_casei)) {
540  value = agent;
541 
542  } else if (param == NULL) {
543  // By default, `port` is added
544  if (host_arg == NULL) {
545  param = "port";
546 
547  } else {
548  param = host_arg;
549  }
550 
551  value = g_hash_table_lookup(device_args, param);
552 
553  } else if (pcmk__str_eq(param, "none", pcmk__str_casei)) {
554  value = param; /* Nothing more to do */
555 
556  } else {
557  value = g_hash_table_lookup(device_args, param);
558  }
559 
560  /* Don't overwrite explictly set values for $param */
561  if (pcmk__str_eq(value, "dynamic", pcmk__str_null_matches | pcmk__str_casei)) {
562  crm_debug("Performing '%s' action targeting '%s' as '%s=%s'", action, victim, param,
563  alias);
564  append_arg(param, alias, &arg_list);
565  }
566  }
567 
568  if (device_args) {
569  g_hash_table_foreach(device_args, append_config_arg, &arg_list);
570  }
571 
572  return arg_list;
573 }
574 
581 void
583 {
584  if (action) {
585  free(action->agent);
586  if (action->args) {
587  g_hash_table_destroy(action->args);
588  }
589  free(action->action);
590  free(action->victim);
591  if (action->svc_action) {
592  services_action_free(action->svc_action);
593  }
594  free(action->output);
595  free(action->error);
596  free(action);
597  }
598 }
599 
612 void
614  char **error_output)
615 {
616  if (rc) {
617  *rc = pcmk_ok;
618  }
619  if (output) {
620  *output = NULL;
621  }
622  if (error_output) {
623  *error_output = NULL;
624  }
625  if (action != NULL) {
626  if (rc) {
627  *rc = action->rc;
628  }
629  if (output && action->output) {
630  *output = action->output;
631  action->output = NULL; // hand off memory management to caller
632  }
633  if (error_output && action->error) {
634  *error_output = action->error;
635  action->error = NULL; // hand off memory management to caller
636  }
637  }
638 }
639 
640 #define FAILURE_MAX_RETRIES 2
642 stonith_action_create(const char *agent,
643  const char *_action,
644  const char *victim,
645  uint32_t victim_nodeid,
646  int timeout, GHashTable * device_args,
647  GHashTable * port_map, const char *host_arg)
648 {
650 
651  action = calloc(1, sizeof(stonith_action_t));
652  action->args = make_args(agent, _action, victim, victim_nodeid,
653  device_args, port_map, host_arg);
654  crm_debug("Preparing '%s' action for %s using agent %s",
655  _action, (victim? victim : "no target"), agent);
656  action->agent = strdup(agent);
657  action->action = strdup(_action);
658  if (victim) {
659  action->victim = strdup(victim);
660  }
661  action->timeout = action->remaining_timeout = timeout;
662  action->max_retries = FAILURE_MAX_RETRIES;
663 
664  if (device_args) {
665  char buffer[512];
666  const char *value = NULL;
667 
668  snprintf(buffer, sizeof(buffer), "pcmk_%s_retries", _action);
669  value = g_hash_table_lookup(device_args, buffer);
670 
671  if (value) {
672  action->max_retries = atoi(value);
673  }
674  }
675 
676  return action;
677 }
678 
679 static gboolean
680 update_remaining_timeout(stonith_action_t * action)
681 {
682  int diff = time(NULL) - action->initial_start_time;
683 
684  if (action->tries >= action->max_retries) {
685  crm_info("Attempted to execute agent %s (%s) the maximum number of times (%d) allowed",
686  action->agent, action->action, action->max_retries);
687  action->remaining_timeout = 0;
688  } else if ((action->rc != -ETIME) && diff < (action->timeout * 0.7)) {
689  /* only set remaining timeout period if there is 30%
690  * or greater of the original timeout period left */
691  action->remaining_timeout = action->timeout - diff;
692  } else {
693  action->remaining_timeout = 0;
694  }
695  return action->remaining_timeout ? TRUE : FALSE;
696 }
697 
698 static int
699 svc_action_to_errno(svc_action_t *svc_action) {
700  int rv = pcmk_ok;
701 
702  if (svc_action->rc > 0) {
703  /* Try to provide a useful error code based on the fence agent's
704  * error output.
705  */
706  if (svc_action->rc == PCMK_OCF_TIMEOUT) {
707  rv = -ETIME;
708 
709  } else if (svc_action->stderr_data == NULL) {
710  rv = -ENODATA;
711 
712  } else if (strstr(svc_action->stderr_data, "imed out")) {
713  /* Some agents have their own internal timeouts */
714  rv = -ETIME;
715 
716  } else if (strstr(svc_action->stderr_data, "Unrecognised action")) {
717  rv = -EOPNOTSUPP;
718 
719  } else {
720  rv = -pcmk_err_generic;
721  }
722  }
723  return rv;
724 }
725 
726 static void
727 stonith_action_async_done(svc_action_t *svc_action)
728 {
729  stonith_action_t *action = (stonith_action_t *) svc_action->cb_data;
730 
731  action->rc = svc_action_to_errno(svc_action);
732  action->output = svc_action->stdout_data;
733  svc_action->stdout_data = NULL;
734  action->error = svc_action->stderr_data;
735  svc_action->stderr_data = NULL;
736 
737  svc_action->params = NULL;
738 
739  crm_debug("Child process %d performing action '%s' exited with rc %d",
740  action->pid, action->action, svc_action->rc);
741 
742  log_action(action, action->pid);
743 
744  if (action->rc != pcmk_ok && update_remaining_timeout(action)) {
745  int rc = internal_stonith_action_execute(action);
746  if (rc == pcmk_ok) {
747  return;
748  }
749  }
750 
751  if (action->done_cb) {
752  action->done_cb(action->pid, action->rc, action->output, action->userdata);
753  }
754 
755  action->svc_action = NULL; // don't remove our caller
757 }
758 
759 static void
760 stonith_action_async_forked(svc_action_t *svc_action)
761 {
762  stonith_action_t *action = (stonith_action_t *) svc_action->cb_data;
763 
764  action->pid = svc_action->pid;
765  action->svc_action = svc_action;
766 
767  if (action->fork_cb) {
768  (action->fork_cb) (svc_action->pid, action->userdata);
769  }
770 
771  crm_trace("Child process %d performing action '%s' successfully forked",
772  action->pid, action->action);
773 }
774 
775 static int
776 internal_stonith_action_execute(stonith_action_t * action)
777 {
778  int rc = -EPROTO;
779  int is_retry = 0;
780  svc_action_t *svc_action = NULL;
781  static int stonith_sequence = 0;
782  char *buffer = NULL;
783 
784  if (!action->tries) {
785  action->initial_start_time = time(NULL);
786  }
787  action->tries++;
788 
789  if (action->tries > 1) {
790  crm_info("Attempt %d to execute %s (%s). remaining timeout is %d",
791  action->tries, action->agent, action->action, action->remaining_timeout);
792  is_retry = 1;
793  }
794 
795  if (action->args == NULL || action->agent == NULL)
796  goto fail;
797 
798  buffer = crm_strdup_printf(PCMK__FENCE_BINDIR "/%s",
799  basename(action->agent));
800  svc_action = services_action_create_generic(buffer, NULL);
801  free(buffer);
802  svc_action->timeout = 1000 * action->remaining_timeout;
803  svc_action->standard = strdup(PCMK_RESOURCE_CLASS_STONITH);
804  svc_action->id = crm_strdup_printf("%s_%s_%d", basename(action->agent),
805  action->action, action->tries);
806  svc_action->agent = strdup(action->agent);
807  svc_action->sequence = stonith_sequence++;
808  svc_action->params = action->args;
809  svc_action->cb_data = (void *) action;
810  svc_action->flags = pcmk__set_flags_as(__func__, __LINE__,
811  LOG_TRACE, "Action",
812  svc_action->id, svc_action->flags,
814  "SVC_ACTION_NON_BLOCKED");
815 
816  /* keep retries from executing out of control and free previous results */
817  if (is_retry) {
818  free(action->output);
819  action->output = NULL;
820  free(action->error);
821  action->error = NULL;
822  sleep(1);
823  }
824 
825  if (action->async) {
826  /* async */
827  if(services_action_async_fork_notify(svc_action,
828  &stonith_action_async_done,
829  &stonith_action_async_forked) == FALSE) {
830  services_action_free(svc_action);
831  svc_action = NULL;
832  } else {
833  rc = 0;
834  }
835 
836  } else {
837  /* sync */
838  if (services_action_sync(svc_action)) {
839  rc = 0;
840  action->rc = svc_action_to_errno(svc_action);
841  action->output = svc_action->stdout_data;
842  svc_action->stdout_data = NULL;
843  action->error = svc_action->stderr_data;
844  svc_action->stderr_data = NULL;
845  } else {
846  action->rc = -ECONNABORTED;
847  rc = action->rc;
848  }
849 
850  svc_action->params = NULL;
851  services_action_free(svc_action);
852  }
853 
854  fail:
855  return rc;
856 }
857 
869 int
871  void *userdata,
872  void (*done) (GPid pid, int rc, const char *output,
873  gpointer user_data),
874  void (*fork_cb) (GPid pid, gpointer user_data))
875 {
876  if (!action) {
877  return -EINVAL;
878  }
879 
880  action->userdata = userdata;
881  action->done_cb = done;
882  action->fork_cb = fork_cb;
883  action->async = 1;
884 
885  return internal_stonith_action_execute(action);
886 }
887 
896 int
898 {
899  int rc = pcmk_ok;
900 
901  CRM_CHECK(action != NULL, return -EINVAL);
902 
903  // Keep trying until success, max retries, or timeout
904  do {
905  rc = internal_stonith_action_execute(action);
906  } while ((rc != pcmk_ok) && update_remaining_timeout(action));
907 
908  return rc;
909 }
910 
911 static int
912 stonith_api_device_list(stonith_t * stonith, int call_options, const char *namespace,
913  stonith_key_value_t ** devices, int timeout)
914 {
915  int count = 0;
916  enum stonith_namespace ns = stonith_text2namespace(namespace);
917 
918  if (devices == NULL) {
919  crm_err("Parameter error: stonith_api_device_list");
920  return -EFAULT;
921  }
922 
923 #if HAVE_STONITH_STONITH_H
924  // Include Linux-HA agents if requested
925  if ((ns == st_namespace_any) || (ns == st_namespace_lha)) {
926  count += stonith__list_lha_agents(devices);
927  }
928 #endif
929 
930  // Include Red Hat agents if requested
931  if ((ns == st_namespace_any) || (ns == st_namespace_rhcs)) {
932  count += stonith__list_rhcs_agents(devices);
933  }
934 
935  return count;
936 }
937 
938 static int
939 stonith_api_device_metadata(stonith_t * stonith, int call_options, const char *agent,
940  const char *namespace, char **output, int timeout)
941 {
942  /* By executing meta-data directly, we can get it from stonith_admin when
943  * the cluster is not running, which is important for higher-level tools.
944  */
945 
946  enum stonith_namespace ns = stonith_get_namespace(agent, namespace);
947 
948  crm_trace("Looking up metadata for %s agent %s",
949  stonith_namespace2text(ns), agent);
950 
951  switch (ns) {
952  case st_namespace_rhcs:
953  return stonith__rhcs_metadata(agent, timeout, output);
954 
955 #if HAVE_STONITH_STONITH_H
956  case st_namespace_lha:
957  return stonith__lha_metadata(agent, timeout, output);
958 #endif
959 
960  default:
961  crm_err("Can't get fence agent '%s' meta-data: No such agent",
962  agent);
963  break;
964  }
965  return -ENODEV;
966 }
967 
968 static int
969 stonith_api_query(stonith_t * stonith, int call_options, const char *target,
970  stonith_key_value_t ** devices, int timeout)
971 {
972  int rc = 0, lpc = 0, max = 0;
973 
974  xmlNode *data = NULL;
975  xmlNode *output = NULL;
976  xmlXPathObjectPtr xpathObj = NULL;
977 
978  CRM_CHECK(devices != NULL, return -EINVAL);
979 
981  crm_xml_add(data, F_STONITH_ORIGIN, __func__);
984  rc = stonith_send_command(stonith, STONITH_OP_QUERY, data, &output, call_options, timeout);
985 
986  if (rc < 0) {
987  return rc;
988  }
989 
990  xpathObj = xpath_search(output, "//@agent");
991  if (xpathObj) {
992  max = numXpathResults(xpathObj);
993 
994  for (lpc = 0; lpc < max; lpc++) {
995  xmlNode *match = getXpathResult(xpathObj, lpc);
996 
997  CRM_LOG_ASSERT(match != NULL);
998  if(match != NULL) {
999  xmlChar *match_path = xmlGetNodePath(match);
1000 
1001  crm_info("%s[%d] = %s", "//@agent", lpc, match_path);
1002  free(match_path);
1003  *devices = stonith_key_value_add(*devices, NULL, crm_element_value(match, XML_ATTR_ID));
1004  }
1005  }
1006 
1007  freeXpathObject(xpathObj);
1008  }
1009 
1010  free_xml(output);
1011  free_xml(data);
1012  return max;
1013 }
1014 
1015 static int
1016 stonith_api_call(stonith_t * stonith,
1017  int call_options,
1018  const char *id,
1019  const char *action, const char *victim, int timeout, xmlNode ** output)
1020 {
1021  int rc = 0;
1022  xmlNode *data = NULL;
1023 
1025  crm_xml_add(data, F_STONITH_ORIGIN, __func__);
1028  crm_xml_add(data, F_STONITH_TARGET, victim);
1029 
1030  rc = stonith_send_command(stonith, STONITH_OP_EXEC, data, output, call_options, timeout);
1031  free_xml(data);
1032 
1033  return rc;
1034 }
1035 
1036 static int
1037 stonith_api_list(stonith_t * stonith, int call_options, const char *id, char **list_info,
1038  int timeout)
1039 {
1040  int rc;
1041  xmlNode *output = NULL;
1042 
1043  rc = stonith_api_call(stonith, call_options, id, "list", NULL, timeout, &output);
1044 
1045  if (output && list_info) {
1046  const char *list_str;
1047 
1048  list_str = crm_element_value(output, "st_output");
1049 
1050  if (list_str) {
1051  *list_info = strdup(list_str);
1052  }
1053  }
1054 
1055  if (output) {
1056  free_xml(output);
1057  }
1058 
1059  return rc;
1060 }
1061 
1062 static int
1063 stonith_api_monitor(stonith_t * stonith, int call_options, const char *id, int timeout)
1064 {
1065  return stonith_api_call(stonith, call_options, id, "monitor", NULL, timeout, NULL);
1066 }
1067 
1068 static int
1069 stonith_api_status(stonith_t * stonith, int call_options, const char *id, const char *port,
1070  int timeout)
1071 {
1072  return stonith_api_call(stonith, call_options, id, "status", port, timeout, NULL);
1073 }
1074 
1075 static int
1076 stonith_api_fence_with_delay(stonith_t * stonith, int call_options, const char *node,
1077  const char *action, int timeout, int tolerance, int delay)
1078 {
1079  int rc = 0;
1080  xmlNode *data = NULL;
1081 
1082  data = create_xml_node(NULL, __func__);
1088 
1089  rc = stonith_send_command(stonith, STONITH_OP_FENCE, data, NULL, call_options, timeout);
1090  free_xml(data);
1091 
1092  return rc;
1093 }
1094 
1095 static int
1096 stonith_api_fence(stonith_t * stonith, int call_options, const char *node, const char *action,
1097  int timeout, int tolerance)
1098 {
1099  return stonith_api_fence_with_delay(stonith, call_options, node, action,
1100  timeout, tolerance, 0);
1101 }
1102 
1103 static int
1104 stonith_api_confirm(stonith_t * stonith, int call_options, const char *target)
1105 {
1107  return stonith_api_fence(stonith, call_options, target, "off", 0, 0);
1108 }
1109 
1110 static int
1111 stonith_api_history(stonith_t * stonith, int call_options, const char *node,
1112  stonith_history_t ** history, int timeout)
1113 {
1114  int rc = 0;
1115  xmlNode *data = NULL;
1116  xmlNode *output = NULL;
1117  stonith_history_t *last = NULL;
1118 
1119  *history = NULL;
1120 
1121  if (node) {
1122  data = create_xml_node(NULL, __func__);
1124  }
1125 
1126  stonith__set_call_options(call_options, node, st_opt_sync_call);
1127  rc = stonith_send_command(stonith, STONITH_OP_FENCE_HISTORY, data, &output,
1128  call_options, timeout);
1129  free_xml(data);
1130 
1131  if (rc == 0) {
1132  xmlNode *op = NULL;
1133  xmlNode *reply = get_xpath_object("//" F_STONITH_HISTORY_LIST, output,
1134  LOG_NEVER);
1135 
1136  for (op = pcmk__xml_first_child(reply); op != NULL;
1137  op = pcmk__xml_next(op)) {
1138  stonith_history_t *kvp;
1139  long long completed;
1140 
1141  kvp = calloc(1, sizeof(stonith_history_t));
1147  crm_element_value_ll(op, F_STONITH_DATE, &completed);
1148  kvp->completed = (time_t) completed;
1150 
1151  if (last) {
1152  last->next = kvp;
1153  } else {
1154  *history = kvp;
1155  }
1156  last = kvp;
1157  }
1158  }
1159 
1160  free_xml(output);
1161 
1162  return rc;
1163 }
1164 
1166 {
1167  stonith_history_t *hp, *hp_old;
1168 
1169  for (hp = history; hp; hp_old = hp, hp = hp->next, free(hp_old)) {
1170  free(hp->target);
1171  free(hp->action);
1172  free(hp->origin);
1173  free(hp->delegate);
1174  free(hp->client);
1175  }
1176 }
1177 
1178 static gint
1179 stonithlib_GCompareFunc(gconstpointer a, gconstpointer b)
1180 {
1181  int rc = 0;
1182  const stonith_notify_client_t *a_client = a;
1183  const stonith_notify_client_t *b_client = b;
1184 
1185  if (a_client->delete || b_client->delete) {
1186  /* make entries marked for deletion not findable */
1187  return -1;
1188  }
1189  CRM_CHECK(a_client->event != NULL && b_client->event != NULL, return 0);
1190  rc = strcmp(a_client->event, b_client->event);
1191  if (rc == 0) {
1192  if (a_client->notify == NULL || b_client->notify == NULL) {
1193  return 0;
1194 
1195  } else if (a_client->notify == b_client->notify) {
1196  return 0;
1197 
1198  } else if (((long)a_client->notify) < ((long)b_client->notify)) {
1199  crm_err("callbacks for %s are not equal: %p vs. %p",
1200  a_client->event, a_client->notify, b_client->notify);
1201  return -1;
1202  }
1203  crm_err("callbacks for %s are not equal: %p vs. %p",
1204  a_client->event, a_client->notify, b_client->notify);
1205  return 1;
1206  }
1207  return rc;
1208 }
1209 
1210 xmlNode *
1211 stonith_create_op(int call_id, const char *token, const char *op, xmlNode * data, int call_options)
1212 {
1213  xmlNode *op_msg = create_xml_node(NULL, "stonith_command");
1214 
1215  CRM_CHECK(op_msg != NULL, return NULL);
1216  CRM_CHECK(token != NULL, return NULL);
1217 
1218  crm_xml_add(op_msg, F_XML_TAGNAME, "stonith_command");
1219 
1220  crm_xml_add(op_msg, F_TYPE, T_STONITH_NG);
1221  crm_xml_add(op_msg, F_STONITH_CALLBACK_TOKEN, token);
1222  crm_xml_add(op_msg, F_STONITH_OPERATION, op);
1223  crm_xml_add_int(op_msg, F_STONITH_CALLID, call_id);
1224  crm_trace("Sending call options: %.8lx, %d", (long)call_options, call_options);
1225  crm_xml_add_int(op_msg, F_STONITH_CALLOPTS, call_options);
1226 
1227  if (data != NULL) {
1229  }
1230 
1231  return op_msg;
1232 }
1233 
1234 static void
1235 stonith_destroy_op_callback(gpointer data)
1236 {
1238 
1239  if (blob->timer && blob->timer->ref > 0) {
1240  g_source_remove(blob->timer->ref);
1241  }
1242  free(blob->timer);
1243  free(blob);
1244 }
1245 
1246 static int
1247 stonith_api_signoff(stonith_t * stonith)
1248 {
1249  stonith_private_t *native = stonith->st_private;
1250 
1251  crm_debug("Disconnecting from the fencer");
1252 
1253  if (native->source != NULL) {
1254  /* Attached to mainloop */
1255  mainloop_del_ipc_client(native->source);
1256  native->source = NULL;
1257  native->ipc = NULL;
1258 
1259  } else if (native->ipc) {
1260  /* Not attached to mainloop */
1261  crm_ipc_t *ipc = native->ipc;
1262 
1263  native->ipc = NULL;
1264  crm_ipc_close(ipc);
1265  crm_ipc_destroy(ipc);
1266  }
1267 
1268  free(native->token); native->token = NULL;
1269  stonith->state = stonith_disconnected;
1270  return pcmk_ok;
1271 }
1272 
1273 static int
1274 stonith_api_del_callback(stonith_t * stonith, int call_id, bool all_callbacks)
1275 {
1276  stonith_private_t *private = stonith->st_private;
1277 
1278  if (all_callbacks) {
1279  private->op_callback = NULL;
1280  g_hash_table_destroy(private->stonith_op_callback_table);
1281  private->stonith_op_callback_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1282  NULL,
1283  stonith_destroy_op_callback);
1284 
1285  } else if (call_id == 0) {
1286  private->op_callback = NULL;
1287 
1288  } else {
1289  g_hash_table_remove(private->stonith_op_callback_table, GINT_TO_POINTER(call_id));
1290  }
1291  return pcmk_ok;
1292 }
1293 
1294 static void
1295 invoke_callback(stonith_t * st, int call_id, int rc, void *userdata,
1296  void (*callback) (stonith_t * st, stonith_callback_data_t * data))
1297 {
1298  stonith_callback_data_t data = { 0, };
1299 
1300  data.call_id = call_id;
1301  data.rc = rc;
1302  data.userdata = userdata;
1303 
1304  callback(st, &data);
1305 }
1306 
1307 static void
1308 stonith_perform_callback(stonith_t * stonith, xmlNode * msg, int call_id, int rc)
1309 {
1310  stonith_private_t *private = NULL;
1311  stonith_callback_client_t *blob = NULL;
1312  stonith_callback_client_t local_blob;
1313 
1314  CRM_CHECK(stonith != NULL, return);
1315  CRM_CHECK(stonith->st_private != NULL, return);
1316 
1317  private = stonith->st_private;
1318 
1319  local_blob.id = NULL;
1320  local_blob.callback = NULL;
1321  local_blob.user_data = NULL;
1322  local_blob.only_success = FALSE;
1323 
1324  if (msg != NULL) {
1326  crm_element_value_int(msg, F_STONITH_CALLID, &call_id);
1327  }
1328 
1329  CRM_CHECK(call_id > 0, crm_log_xml_err(msg, "Bad result"));
1330 
1331  blob = g_hash_table_lookup(private->stonith_op_callback_table, GINT_TO_POINTER(call_id));
1332 
1333  if (blob != NULL) {
1334  local_blob = *blob;
1335  blob = NULL;
1336 
1337  stonith_api_del_callback(stonith, call_id, FALSE);
1338 
1339  } else {
1340  crm_trace("No callback found for call %d", call_id);
1341  local_blob.callback = NULL;
1342  }
1343 
1344  if (local_blob.callback != NULL && (rc == pcmk_ok || local_blob.only_success == FALSE)) {
1345  crm_trace("Invoking callback %s for call %d", crm_str(local_blob.id), call_id);
1346  invoke_callback(stonith, call_id, rc, local_blob.user_data, local_blob.callback);
1347 
1348  } else if (private->op_callback == NULL && rc != pcmk_ok) {
1349  crm_warn("Fencing command failed: %s", pcmk_strerror(rc));
1350  crm_log_xml_debug(msg, "Failed fence update");
1351  }
1352 
1353  if (private->op_callback != NULL) {
1354  crm_trace("Invoking global callback for call %d", call_id);
1355  invoke_callback(stonith, call_id, rc, NULL, private->op_callback);
1356  }
1357  crm_trace("OP callback activated.");
1358 }
1359 
1360 static gboolean
1361 stonith_async_timeout_handler(gpointer data)
1362 {
1363  struct timer_rec_s *timer = data;
1364 
1365  crm_err("Async call %d timed out after %dms", timer->call_id, timer->timeout);
1366  stonith_perform_callback(timer->stonith, NULL, timer->call_id, -ETIME);
1367 
1368  /* Always return TRUE, never remove the handler
1369  * We do that in stonith_del_callback()
1370  */
1371  return TRUE;
1372 }
1373 
1374 static void
1375 set_callback_timeout(stonith_callback_client_t * callback, stonith_t * stonith, int call_id,
1376  int timeout)
1377 {
1378  struct timer_rec_s *async_timer = callback->timer;
1379 
1380  if (timeout <= 0) {
1381  return;
1382  }
1383 
1384  if (!async_timer) {
1385  async_timer = calloc(1, sizeof(struct timer_rec_s));
1386  callback->timer = async_timer;
1387  }
1388 
1389  async_timer->stonith = stonith;
1390  async_timer->call_id = call_id;
1391  /* Allow a fair bit of grace to allow the server to tell us of a timeout
1392  * This is only a fallback
1393  */
1394  async_timer->timeout = (timeout + 60) * 1000;
1395  if (async_timer->ref) {
1396  g_source_remove(async_timer->ref);
1397  }
1398  async_timer->ref =
1399  g_timeout_add(async_timer->timeout, stonith_async_timeout_handler, async_timer);
1400 }
1401 
1402 static void
1403 update_callback_timeout(int call_id, int timeout, stonith_t * st)
1404 {
1405  stonith_callback_client_t *callback = NULL;
1406  stonith_private_t *private = st->st_private;
1407 
1408  callback = g_hash_table_lookup(private->stonith_op_callback_table, GINT_TO_POINTER(call_id));
1409  if (!callback || !callback->allow_timeout_updates) {
1410  return;
1411  }
1412 
1413  set_callback_timeout(callback, st, call_id, timeout);
1414 }
1415 
1416 static int
1417 stonith_dispatch_internal(const char *buffer, ssize_t length, gpointer userdata)
1418 {
1419  const char *type = NULL;
1420  struct notify_blob_s blob;
1421 
1422  stonith_t *st = userdata;
1423  stonith_private_t *private = NULL;
1424 
1425  CRM_ASSERT(st != NULL);
1426  private = st->st_private;
1427 
1428  blob.stonith = st;
1429  blob.xml = string2xml(buffer);
1430  if (blob.xml == NULL) {
1431  crm_warn("Received malformed message from fencer: %s", buffer);
1432  return 0;
1433  }
1434 
1435  /* do callbacks */
1436  type = crm_element_value(blob.xml, F_TYPE);
1437  crm_trace("Activating %s callbacks...", type);
1438 
1439  if (pcmk__str_eq(type, T_STONITH_NG, pcmk__str_casei)) {
1440  stonith_perform_callback(st, blob.xml, 0, 0);
1441 
1442  } else if (pcmk__str_eq(type, T_STONITH_NOTIFY, pcmk__str_casei)) {
1443  foreach_notify_entry(private, stonith_send_notification, &blob);
1444  } else if (pcmk__str_eq(type, T_STONITH_TIMEOUT_VALUE, pcmk__str_casei)) {
1445  int call_id = 0;
1446  int timeout = 0;
1447 
1449  crm_element_value_int(blob.xml, F_STONITH_CALLID, &call_id);
1450 
1451  update_callback_timeout(call_id, timeout, st);
1452  } else {
1453  crm_err("Unknown message type: %s", type);
1454  crm_log_xml_warn(blob.xml, "BadReply");
1455  }
1456 
1457  free_xml(blob.xml);
1458  return 1;
1459 }
1460 
1461 static int
1462 stonith_api_signon(stonith_t * stonith, const char *name, int *stonith_fd)
1463 {
1464  int rc = pcmk_ok;
1465  stonith_private_t *native = NULL;
1466  const char *display_name = name? name : "client";
1467 
1468  struct ipc_client_callbacks st_callbacks = {
1469  .dispatch = stonith_dispatch_internal,
1470  .destroy = stonith_connection_destroy
1471  };
1472 
1473  CRM_CHECK(stonith != NULL, return -EINVAL);
1474 
1475  native = stonith->st_private;
1476  CRM_ASSERT(native != NULL);
1477 
1478  crm_debug("Attempting fencer connection by %s with%s mainloop",
1479  display_name, (stonith_fd? "out" : ""));
1480 
1481  stonith->state = stonith_connected_command;
1482  if (stonith_fd) {
1483  /* No mainloop */
1484  native->ipc = crm_ipc_new("stonith-ng", 0);
1485 
1486  if (native->ipc && crm_ipc_connect(native->ipc)) {
1487  *stonith_fd = crm_ipc_get_fd(native->ipc);
1488  } else if (native->ipc) {
1489  crm_ipc_close(native->ipc);
1490  crm_ipc_destroy(native->ipc);
1491  native->ipc = NULL;
1492  }
1493 
1494  } else {
1495  /* With mainloop */
1496  native->source =
1497  mainloop_add_ipc_client("stonith-ng", G_PRIORITY_MEDIUM, 0, stonith, &st_callbacks);
1498  native->ipc = mainloop_get_ipc_client(native->source);
1499  }
1500 
1501  if (native->ipc == NULL) {
1502  rc = -ENOTCONN;
1503  } else {
1504  xmlNode *reply = NULL;
1505  xmlNode *hello = create_xml_node(NULL, "stonith_command");
1506 
1507  crm_xml_add(hello, F_TYPE, T_STONITH_NG);
1510  rc = crm_ipc_send(native->ipc, hello, crm_ipc_client_response, -1, &reply);
1511 
1512  if (rc < 0) {
1513  crm_debug("Couldn't register with the fencer: %s "
1514  CRM_XS " rc=%d", pcmk_strerror(rc), rc);
1515  rc = -ECOMM;
1516 
1517  } else if (reply == NULL) {
1518  crm_debug("Couldn't register with the fencer: no reply");
1519  rc = -EPROTO;
1520 
1521  } else {
1522  const char *msg_type = crm_element_value(reply, F_STONITH_OPERATION);
1523 
1524  native->token = crm_element_value_copy(reply, F_STONITH_CLIENTID);
1525  if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_casei)) {
1526  crm_debug("Couldn't register with the fencer: invalid reply type '%s'",
1527  (msg_type? msg_type : "(missing)"));
1528  crm_log_xml_debug(reply, "Invalid fencer reply");
1529  rc = -EPROTO;
1530 
1531  } else if (native->token == NULL) {
1532  crm_debug("Couldn't register with the fencer: no token in reply");
1533  crm_log_xml_debug(reply, "Invalid fencer reply");
1534  rc = -EPROTO;
1535 
1536  } else {
1537 #if HAVE_MSGFROMIPC_TIMEOUT
1538  stonith->call_timeout = MAX_IPC_DELAY;
1539 #endif
1540  crm_debug("Connection to fencer by %s succeeded (registration token: %s)",
1541  display_name, native->token);
1542  rc = pcmk_ok;
1543  }
1544  }
1545 
1546  free_xml(reply);
1547  free_xml(hello);
1548  }
1549 
1550  if (rc != pcmk_ok) {
1551  crm_debug("Connection attempt to fencer by %s failed: %s "
1552  CRM_XS " rc=%d", display_name, pcmk_strerror(rc), rc);
1553  stonith->cmds->disconnect(stonith);
1554  }
1555  return rc;
1556 }
1557 
1558 static int
1559 stonith_set_notification(stonith_t * stonith, const char *callback, int enabled)
1560 {
1561  int rc = pcmk_ok;
1562  xmlNode *notify_msg = create_xml_node(NULL, __func__);
1563  stonith_private_t *native = stonith->st_private;
1564 
1565  if (stonith->state != stonith_disconnected) {
1566 
1568  if (enabled) {
1569  crm_xml_add(notify_msg, F_STONITH_NOTIFY_ACTIVATE, callback);
1570  } else {
1571  crm_xml_add(notify_msg, F_STONITH_NOTIFY_DEACTIVATE, callback);
1572  }
1573 
1574  rc = crm_ipc_send(native->ipc, notify_msg, crm_ipc_client_response, -1, NULL);
1575  if (rc < 0) {
1576  crm_perror(LOG_DEBUG, "Couldn't register for fencing notifications: %d", rc);
1577  rc = -ECOMM;
1578  } else {
1579  rc = pcmk_ok;
1580  }
1581  }
1582 
1583  free_xml(notify_msg);
1584  return rc;
1585 }
1586 
1587 static int
1588 stonith_api_add_notification(stonith_t * stonith, const char *event,
1589  void (*callback) (stonith_t * stonith, stonith_event_t * e))
1590 {
1591  GList *list_item = NULL;
1592  stonith_notify_client_t *new_client = NULL;
1593  stonith_private_t *private = NULL;
1594 
1595  private = stonith->st_private;
1596  crm_trace("Adding callback for %s events (%d)", event, g_list_length(private->notify_list));
1597 
1598  new_client = calloc(1, sizeof(stonith_notify_client_t));
1599  new_client->event = event;
1600  new_client->notify = callback;
1601 
1602  list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1603 
1604  if (list_item != NULL) {
1605  crm_warn("Callback already present");
1606  free(new_client);
1607  return -ENOTUNIQ;
1608 
1609  } else {
1610  private->notify_list = g_list_append(private->notify_list, new_client);
1611 
1612  stonith_set_notification(stonith, event, 1);
1613 
1614  crm_trace("Callback added (%d)", g_list_length(private->notify_list));
1615  }
1616  return pcmk_ok;
1617 }
1618 
1619 static int
1620 stonith_api_del_notification(stonith_t * stonith, const char *event)
1621 {
1622  GList *list_item = NULL;
1623  stonith_notify_client_t *new_client = NULL;
1624  stonith_private_t *private = NULL;
1625 
1626  crm_debug("Removing callback for %s events", event);
1627 
1628  private = stonith->st_private;
1629  new_client = calloc(1, sizeof(stonith_notify_client_t));
1630  new_client->event = event;
1631  new_client->notify = NULL;
1632 
1633  list_item = g_list_find_custom(private->notify_list, new_client, stonithlib_GCompareFunc);
1634 
1635  stonith_set_notification(stonith, event, 0);
1636 
1637  if (list_item != NULL) {
1638  stonith_notify_client_t *list_client = list_item->data;
1639 
1640  if (private->notify_refcnt) {
1641  list_client->delete = TRUE;
1642  private->notify_deletes = TRUE;
1643  } else {
1644  private->notify_list = g_list_remove(private->notify_list, list_client);
1645  free(list_client);
1646  }
1647 
1648  crm_trace("Removed callback");
1649 
1650  } else {
1651  crm_trace("Callback not present");
1652  }
1653  free(new_client);
1654  return pcmk_ok;
1655 }
1656 
1657 static int
1658 stonith_api_add_callback(stonith_t * stonith, int call_id, int timeout, int options,
1659  void *user_data, const char *callback_name,
1660  void (*callback) (stonith_t * st, stonith_callback_data_t * data))
1661 {
1662  stonith_callback_client_t *blob = NULL;
1663  stonith_private_t *private = NULL;
1664 
1665  CRM_CHECK(stonith != NULL, return -EINVAL);
1666  CRM_CHECK(stonith->st_private != NULL, return -EINVAL);
1667  private = stonith->st_private;
1668 
1669  if (call_id == 0) {
1670  private->op_callback = callback;
1671 
1672  } else if (call_id < 0) {
1673  if (!(options & st_opt_report_only_success)) {
1674  crm_trace("Call failed, calling %s: %s", callback_name, pcmk_strerror(call_id));
1675  invoke_callback(stonith, call_id, call_id, user_data, callback);
1676  } else {
1677  crm_warn("Fencer call failed: %s", pcmk_strerror(call_id));
1678  }
1679  return FALSE;
1680  }
1681 
1682  blob = calloc(1, sizeof(stonith_callback_client_t));
1683  blob->id = callback_name;
1684  blob->only_success = (options & st_opt_report_only_success) ? TRUE : FALSE;
1685  blob->user_data = user_data;
1686  blob->callback = callback;
1687  blob->allow_timeout_updates = (options & st_opt_timeout_updates) ? TRUE : FALSE;
1688 
1689  if (timeout > 0) {
1690  set_callback_timeout(blob, stonith, call_id, timeout);
1691  }
1692 
1693  g_hash_table_insert(private->stonith_op_callback_table, GINT_TO_POINTER(call_id), blob);
1694  crm_trace("Added callback to %s for call %d", callback_name, call_id);
1695 
1696  return TRUE;
1697 }
1698 
1699 static void
1700 stonith_dump_pending_op(gpointer key, gpointer value, gpointer user_data)
1701 {
1702  int call = GPOINTER_TO_INT(key);
1703  stonith_callback_client_t *blob = value;
1704 
1705  crm_debug("Call %d (%s): pending", call, crm_str(blob->id));
1706 }
1707 
1708 void
1710 {
1711  stonith_private_t *private = stonith->st_private;
1712 
1713  if (private->stonith_op_callback_table == NULL) {
1714  return;
1715  }
1716  return g_hash_table_foreach(private->stonith_op_callback_table, stonith_dump_pending_op, NULL);
1717 }
1718 
1719 /*
1720  <notify t="st_notify" subt="st_device_register" st_op="st_device_register" st_rc="0" >
1721  <st_calldata >
1722  <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" >
1723  <st_calldata >
1724  <st_device_id id="test-id" origin="create_device_registration_xml" agent="fence_virsh" namespace="stonith-ng" >
1725  <attributes ipaddr="localhost" pcmk-portmal="some-host=pcmk-1 pcmk-3=3,4" login="root" identity_file="/root/.ssh/id_dsa" />
1726  </st_device_id>
1727  </st_calldata>
1728  </stonith_command>
1729  </st_calldata>
1730  </notify>
1731 
1732  <notify t="st_notify" subt="st_notify_fence" st_op="st_notify_fence" st_rc="0" >
1733  <st_calldata >
1734  <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" />
1735  </st_calldata>
1736  </notify>
1737 */
1738 static stonith_event_t *
1739 xml_to_event(xmlNode * msg)
1740 {
1741  stonith_event_t *event = calloc(1, sizeof(stonith_event_t));
1742  const char *ntype = crm_element_value(msg, F_SUBTYPE);
1743  char *data_addr = crm_strdup_printf("//%s", ntype);
1744  xmlNode *data = get_xpath_object(data_addr, msg, LOG_DEBUG);
1745 
1746  crm_log_xml_trace(msg, "stonith_notify");
1747 
1748  crm_element_value_int(msg, F_STONITH_RC, &(event->result));
1749 
1750  if (pcmk__str_eq(ntype, T_STONITH_NOTIFY_FENCE, pcmk__str_casei)) {
1751  event->operation = crm_element_value_copy(msg, F_STONITH_OPERATION);
1752 
1753  if (data) {
1754  event->origin = crm_element_value_copy(data, F_STONITH_ORIGIN);
1755  event->action = crm_element_value_copy(data, F_STONITH_ACTION);
1756  event->target = crm_element_value_copy(data, F_STONITH_TARGET);
1757  event->executioner = crm_element_value_copy(data, F_STONITH_DELEGATE);
1759  event->client_origin = crm_element_value_copy(data, F_STONITH_CLIENTNAME);
1760  event->device = crm_element_value_copy(data, F_STONITH_DEVICE);
1761 
1762  } else {
1763  crm_err("No data for %s event", ntype);
1764  crm_log_xml_notice(msg, "BadEvent");
1765  }
1766  }
1767 
1768  free(data_addr);
1769  return event;
1770 }
1771 
1772 static void
1773 event_free(stonith_event_t * event)
1774 {
1775  free(event->id);
1776  free(event->type);
1777  free(event->message);
1778  free(event->operation);
1779  free(event->origin);
1780  free(event->action);
1781  free(event->target);
1782  free(event->executioner);
1783  free(event->device);
1784  free(event->client_origin);
1785  free(event);
1786 }
1787 
1788 static void
1789 stonith_send_notification(gpointer data, gpointer user_data)
1790 {
1791  struct notify_blob_s *blob = user_data;
1792  stonith_notify_client_t *entry = data;
1793  stonith_event_t *st_event = NULL;
1794  const char *event = NULL;
1795 
1796  if (blob->xml == NULL) {
1797  crm_warn("Skipping callback - NULL message");
1798  return;
1799  }
1800 
1801  event = crm_element_value(blob->xml, F_SUBTYPE);
1802 
1803  if (entry == NULL) {
1804  crm_warn("Skipping callback - NULL callback client");
1805  return;
1806 
1807  } else if (entry->delete) {
1808  crm_trace("Skipping callback - marked for deletion");
1809  return;
1810 
1811  } else if (entry->notify == NULL) {
1812  crm_warn("Skipping callback - NULL callback");
1813  return;
1814 
1815  } else if (!pcmk__str_eq(entry->event, event, pcmk__str_casei)) {
1816  crm_trace("Skipping callback - event mismatch %p/%s vs. %s", entry, entry->event, event);
1817  return;
1818  }
1819 
1820  st_event = xml_to_event(blob->xml);
1821 
1822  crm_trace("Invoking callback for %p/%s event...", entry, event);
1823  entry->notify(blob->stonith, st_event);
1824  crm_trace("Callback invoked...");
1825 
1826  event_free(st_event);
1827 }
1828 
1843 static int
1844 stonith_send_command(stonith_t * stonith, const char *op, xmlNode * data, xmlNode ** output_data,
1845  int call_options, int timeout)
1846 {
1847  int rc = 0;
1848  int reply_id = -1;
1849 
1850  xmlNode *op_msg = NULL;
1851  xmlNode *op_reply = NULL;
1852  stonith_private_t *native = NULL;
1853 
1854  CRM_ASSERT(stonith && stonith->st_private && op);
1855  native = stonith->st_private;
1856 
1857  if (output_data != NULL) {
1858  *output_data = NULL;
1859  }
1860 
1861  if ((stonith->state == stonith_disconnected) || (native->token == NULL)) {
1862  return -ENOTCONN;
1863  }
1864 
1865  /* Increment the call ID, which must be positive to avoid conflicting with
1866  * error codes. This shouldn't be a problem unless the client mucked with
1867  * it or the counter wrapped around.
1868  */
1869  stonith->call_id++;
1870  if (stonith->call_id < 1) {
1871  stonith->call_id = 1;
1872  }
1873 
1874  op_msg = stonith_create_op(stonith->call_id, native->token, op, data, call_options);
1875  if (op_msg == NULL) {
1876  return -EINVAL;
1877  }
1878 
1880  crm_trace("Sending %s message to fencer with timeout %ds", op, timeout);
1881 
1882  if (data) {
1883  const char *delay_s = crm_element_value(data, F_STONITH_DELAY);
1884 
1885  if (delay_s) {
1886  crm_xml_add(op_msg, F_STONITH_DELAY, delay_s);
1887  }
1888  }
1889 
1890  {
1891  enum crm_ipc_flags ipc_flags = crm_ipc_flags_none;
1892 
1893  if (call_options & st_opt_sync_call) {
1894  pcmk__set_ipc_flags(ipc_flags, "stonith command",
1896  }
1897  rc = crm_ipc_send(native->ipc, op_msg, ipc_flags,
1898  1000 * (timeout + 60), &op_reply);
1899  }
1900  free_xml(op_msg);
1901 
1902  if (rc < 0) {
1903  crm_perror(LOG_ERR, "Couldn't perform %s operation (timeout=%ds): %d", op, timeout, rc);
1904  rc = -ECOMM;
1905  goto done;
1906  }
1907 
1908  crm_log_xml_trace(op_reply, "Reply");
1909 
1910  if (!(call_options & st_opt_sync_call)) {
1911  crm_trace("Async call %d, returning", stonith->call_id);
1912  free_xml(op_reply);
1913  return stonith->call_id;
1914  }
1915 
1916  rc = pcmk_ok;
1917  crm_element_value_int(op_reply, F_STONITH_CALLID, &reply_id);
1918 
1919  if (reply_id == stonith->call_id) {
1920  crm_trace("Synchronous reply %d received", reply_id);
1921 
1922  if (crm_element_value_int(op_reply, F_STONITH_RC, &rc) != 0) {
1923  rc = -ENOMSG;
1924  }
1925 
1926  if ((call_options & st_opt_discard_reply) || output_data == NULL) {
1927  crm_trace("Discarding reply");
1928 
1929  } else {
1930  *output_data = op_reply;
1931  op_reply = NULL; /* Prevent subsequent free */
1932  }
1933 
1934  } else if (reply_id <= 0) {
1935  crm_err("Received bad reply: No id set");
1936  crm_log_xml_err(op_reply, "Bad reply");
1937  free_xml(op_reply);
1938  rc = -ENOMSG;
1939 
1940  } else {
1941  crm_err("Received bad reply: %d (wanted %d)", reply_id, stonith->call_id);
1942  crm_log_xml_err(op_reply, "Old reply");
1943  free_xml(op_reply);
1944  rc = -ENOMSG;
1945  }
1946 
1947  done:
1948  if (crm_ipc_connected(native->ipc) == FALSE) {
1949  crm_err("Fencer disconnected");
1950  free(native->token); native->token = NULL;
1951  stonith->state = stonith_disconnected;
1952  }
1953 
1954  free_xml(op_reply);
1955  return rc;
1956 }
1957 
1958 /* Not used with mainloop */
1959 bool
1961 {
1962  gboolean stay_connected = TRUE;
1963  stonith_private_t *private = NULL;
1964 
1965  CRM_ASSERT(st != NULL);
1966  private = st->st_private;
1967 
1968  while (crm_ipc_ready(private->ipc)) {
1969 
1970  if (crm_ipc_read(private->ipc) > 0) {
1971  const char *msg = crm_ipc_buffer(private->ipc);
1972 
1973  stonith_dispatch_internal(msg, strlen(msg), st);
1974  }
1975 
1976  if (crm_ipc_connected(private->ipc) == FALSE) {
1977  crm_err("Connection closed");
1978  stay_connected = FALSE;
1979  }
1980  }
1981 
1982  return stay_connected;
1983 }
1984 
1985 static int
1986 stonith_api_free(stonith_t * stonith)
1987 {
1988  int rc = pcmk_ok;
1989 
1990  crm_trace("Destroying %p", stonith);
1991 
1992  if (stonith->state != stonith_disconnected) {
1993  crm_trace("Disconnecting %p first", stonith);
1994  rc = stonith->cmds->disconnect(stonith);
1995  }
1996 
1997  if (stonith->state == stonith_disconnected) {
1998  stonith_private_t *private = stonith->st_private;
1999 
2000  crm_trace("Removing %d callbacks", g_hash_table_size(private->stonith_op_callback_table));
2001  g_hash_table_destroy(private->stonith_op_callback_table);
2002 
2003  crm_trace("Destroying %d notification clients", g_list_length(private->notify_list));
2004  g_list_free_full(private->notify_list, free);
2005 
2006  free(stonith->st_private);
2007  free(stonith->cmds);
2008  free(stonith);
2009 
2010  } else {
2011  crm_err("Not free'ing active connection: %s (%d)", pcmk_strerror(rc), rc);
2012  }
2013 
2014  return rc;
2015 }
2016 
2017 void
2019 {
2020  crm_trace("Destroying %p", stonith);
2021  if(stonith) {
2022  stonith->cmds->free(stonith);
2023  }
2024 }
2025 
2026 static int
2027 stonith_api_validate(stonith_t *st, int call_options, const char *rsc_id,
2028  const char *namespace_s, const char *agent,
2029  stonith_key_value_t *params, int timeout, char **output,
2030  char **error_output)
2031 {
2032  /* Validation should be done directly via the agent, so we can get it from
2033  * stonith_admin when the cluster is not running, which is important for
2034  * higher-level tools.
2035  */
2036 
2037  int rc = pcmk_ok;
2038 
2039  /* Use a dummy node name in case the agent requires a target. We assume the
2040  * actual target doesn't matter for validation purposes (if in practice,
2041  * that is incorrect, we will need to allow the caller to pass the target).
2042  */
2043  const char *target = "node1";
2044  const char *host_arg = NULL;
2045 
2046  GHashTable *params_table = crm_str_table_new();
2047 
2048  // Convert parameter list to a hash table
2049  for (; params; params = params->next) {
2050  if (pcmk__str_eq(params->key, STONITH_ATTR_HOSTARG, pcmk__str_casei)) {
2051  host_arg = params->value;
2052  }
2053 
2054  // Strip out Pacemaker-implemented parameters
2055  if (!pcmk__starts_with(params->key, "pcmk_")
2056  && strcmp(params->key, "provides")
2057  && strcmp(params->key, "stonith-timeout")) {
2058  g_hash_table_insert(params_table, strdup(params->key),
2059  strdup(params->value));
2060  }
2061  }
2062 
2063 #if SUPPORT_CIBSECRETS
2064  rc = pcmk__substitute_secrets(rsc_id, params_table);
2065  if (rc != pcmk_rc_ok) {
2066  crm_warn("Could not replace secret parameters for validation of %s: %s",
2067  agent, pcmk_rc_str(rc));
2068  // rc is standard return value, don't return it in this function
2069  }
2070 #endif
2071 
2072  if (output) {
2073  *output = NULL;
2074  }
2075  if (error_output) {
2076  *error_output = NULL;
2077  }
2078 
2079  switch (stonith_get_namespace(agent, namespace_s)) {
2080  case st_namespace_rhcs:
2081  rc = stonith__rhcs_validate(st, call_options, target, agent,
2082  params_table, host_arg, timeout,
2083  output, error_output);
2084  break;
2085 
2086 #if HAVE_STONITH_STONITH_H
2087  case st_namespace_lha:
2088  rc = stonith__lha_validate(st, call_options, target, agent,
2089  params_table, timeout, output,
2090  error_output);
2091  break;
2092 #endif
2093 
2094  default:
2095  rc = -EINVAL;
2096  errno = EINVAL;
2097  crm_perror(LOG_ERR,
2098  "Agent %s not found or does not support validation",
2099  agent);
2100  break;
2101  }
2102  g_hash_table_destroy(params_table);
2103  return rc;
2104 }
2105 
2106 stonith_t *
2108 {
2109  stonith_t *new_stonith = NULL;
2110  stonith_private_t *private = NULL;
2111 
2112  new_stonith = calloc(1, sizeof(stonith_t));
2113  if (new_stonith == NULL) {
2114  return NULL;
2115  }
2116 
2117  private = calloc(1, sizeof(stonith_private_t));
2118  if (private == NULL) {
2119  free(new_stonith);
2120  return NULL;
2121  }
2122  new_stonith->st_private = private;
2123 
2124  private->stonith_op_callback_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
2125  NULL, stonith_destroy_op_callback);
2126  private->notify_list = NULL;
2127  private->notify_refcnt = 0;
2128  private->notify_deletes = FALSE;
2129 
2130  new_stonith->call_id = 1;
2131  new_stonith->state = stonith_disconnected;
2132 
2133  new_stonith->cmds = calloc(1, sizeof(stonith_api_operations_t));
2134  if (new_stonith->cmds == NULL) {
2135  free(new_stonith->st_private);
2136  free(new_stonith);
2137  return NULL;
2138  }
2139 
2140 /* *INDENT-OFF* */
2141  new_stonith->cmds->free = stonith_api_free;
2142  new_stonith->cmds->connect = stonith_api_signon;
2143  new_stonith->cmds->disconnect = stonith_api_signoff;
2144 
2145  new_stonith->cmds->list = stonith_api_list;
2146  new_stonith->cmds->monitor = stonith_api_monitor;
2147  new_stonith->cmds->status = stonith_api_status;
2148  new_stonith->cmds->fence = stonith_api_fence;
2149  new_stonith->cmds->fence_with_delay = stonith_api_fence_with_delay;
2150  new_stonith->cmds->confirm = stonith_api_confirm;
2151  new_stonith->cmds->history = stonith_api_history;
2152 
2153  new_stonith->cmds->list_agents = stonith_api_device_list;
2154  new_stonith->cmds->metadata = stonith_api_device_metadata;
2155 
2156  new_stonith->cmds->query = stonith_api_query;
2157  new_stonith->cmds->remove_device = stonith_api_remove_device;
2158  new_stonith->cmds->register_device = stonith_api_register_device;
2159 
2160  new_stonith->cmds->remove_level = stonith_api_remove_level;
2161  new_stonith->cmds->remove_level_full = stonith_api_remove_level_full;
2162  new_stonith->cmds->register_level = stonith_api_register_level;
2163  new_stonith->cmds->register_level_full = stonith_api_register_level_full;
2164 
2165  new_stonith->cmds->remove_callback = stonith_api_del_callback;
2166  new_stonith->cmds->register_callback = stonith_api_add_callback;
2167  new_stonith->cmds->remove_notification = stonith_api_del_notification;
2168  new_stonith->cmds->register_notification = stonith_api_add_notification;
2169 
2170  new_stonith->cmds->validate = stonith_api_validate;
2171 /* *INDENT-ON* */
2172 
2173  return new_stonith;
2174 }
2175 
2185 int
2186 stonith_api_connect_retry(stonith_t *st, const char *name, int max_attempts)
2187 {
2188  int rc = -EINVAL; // if max_attempts is not positive
2189 
2190  for (int attempt = 1; attempt <= max_attempts; attempt++) {
2191  rc = st->cmds->connect(st, name, NULL);
2192  if (rc == pcmk_ok) {
2193  return pcmk_ok;
2194  } else if (attempt < max_attempts) {
2195  crm_notice("Fencer connection attempt %d of %d failed (retrying in 2s): %s "
2196  CRM_XS " rc=%d",
2197  attempt, max_attempts, pcmk_strerror(rc), rc);
2198  sleep(2);
2199  }
2200  }
2201  crm_notice("Could not connect to fencer: %s " CRM_XS " rc=%d",
2202  pcmk_strerror(rc), rc);
2203  return rc;
2204 }
2205 
2207 stonith_key_value_add(stonith_key_value_t * head, const char *key, const char *value)
2208 {
2209  stonith_key_value_t *p, *end;
2210 
2211  p = calloc(1, sizeof(stonith_key_value_t));
2212  if (key) {
2213  p->key = strdup(key);
2214  }
2215  if (value) {
2216  p->value = strdup(value);
2217  }
2218 
2219  end = head;
2220  while (end && end->next) {
2221  end = end->next;
2222  }
2223 
2224  if (end) {
2225  end->next = p;
2226  } else {
2227  head = p;
2228  }
2229 
2230  return head;
2231 }
2232 
2233 void
2234 stonith_key_value_freeall(stonith_key_value_t * head, int keys, int values)
2235 {
2237 
2238  while (head) {
2239  p = head->next;
2240  if (keys) {
2241  free(head->key);
2242  }
2243  if (values) {
2244  free(head->value);
2245  }
2246  free(head);
2247  head = p;
2248  }
2249 }
2250 
2251 #define api_log_open() openlog("stonith-api", LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON)
2252 #define api_log(level, fmt, args...) syslog(level, "%s: "fmt, __func__, args)
2253 
2254 int
2255 stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
2256 {
2257  int rc = pcmk_ok;
2259  const char *action = off? "off" : "reboot";
2260 
2261  api_log_open();
2262  if (st == NULL) {
2263  api_log(LOG_ERR, "API initialization failed, could not kick (%s) node %u/%s",
2264  action, nodeid, uname);
2265  return -EPROTO;
2266  }
2267 
2268  rc = st->cmds->connect(st, "stonith-api", NULL);
2269  if (rc != pcmk_ok) {
2270  api_log(LOG_ERR, "Connection failed, could not kick (%s) node %u/%s : %s (%d)",
2271  action, nodeid, uname, pcmk_strerror(rc), rc);
2272  } else {
2273  char *name = (uname == NULL)? crm_itoa(nodeid) : strdup(uname);
2274  int opts = 0;
2275 
2278  if ((uname == NULL) && (nodeid > 0)) {
2280  }
2281  rc = st->cmds->fence(st, opts, name, action, timeout, 0);
2282  free(name);
2283 
2284  if (rc != pcmk_ok) {
2285  api_log(LOG_ERR, "Could not kick (%s) node %u/%s : %s (%d)",
2286  action, nodeid, uname, pcmk_strerror(rc), rc);
2287  } else {
2288  api_log(LOG_NOTICE, "Node %u/%s kicked: %s", nodeid, uname, action);
2289  }
2290  }
2291 
2293  return rc;
2294 }
2295 
2296 time_t
2297 stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
2298 {
2299  int rc = pcmk_ok;
2300  time_t when = 0;
2302  stonith_history_t *history = NULL, *hp = NULL;
2303 
2304  if (st == NULL) {
2305  api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: "
2306  "API initialization failed", nodeid, uname);
2307  return when;
2308  }
2309 
2310  rc = st->cmds->connect(st, "stonith-api", NULL);
2311  if (rc != pcmk_ok) {
2312  api_log(LOG_NOTICE, "Connection failed: %s (%d)", pcmk_strerror(rc), rc);
2313  } else {
2314  int entries = 0;
2315  int progress = 0;
2316  int completed = 0;
2317  int opts = 0;
2318  char *name = (uname == NULL)? crm_itoa(nodeid) : strdup(uname);
2319 
2321  if ((uname == NULL) && (nodeid > 0)) {
2323  }
2324  rc = st->cmds->history(st, opts, name, &history, 120);
2325  free(name);
2326 
2327  for (hp = history; hp; hp = hp->next) {
2328  entries++;
2329  if (in_progress) {
2330  progress++;
2331  if (hp->state != st_done && hp->state != st_failed) {
2332  when = time(NULL);
2333  }
2334 
2335  } else if (hp->state == st_done) {
2336  completed++;
2337  if (hp->completed > when) {
2338  when = hp->completed;
2339  }
2340  }
2341  }
2342 
2343  stonith_history_free(history);
2344 
2345  if(rc == pcmk_ok) {
2346  api_log(LOG_INFO, "Found %d entries for %u/%s: %d in progress, %d completed", entries, nodeid, uname, progress, completed);
2347  } else {
2348  api_log(LOG_ERR, "Could not retrieve fence history for %u/%s: %s (%d)", nodeid, uname, pcmk_strerror(rc), rc);
2349  }
2350  }
2351 
2353 
2354  if(when) {
2355  api_log(LOG_INFO, "Node %u/%s last kicked at: %ld", nodeid, uname, (long int)when);
2356  }
2357  return when;
2358 }
2359 
2360 bool
2361 stonith_agent_exists(const char *agent, int timeout)
2362 {
2363  stonith_t *st = NULL;
2364  stonith_key_value_t *devices = NULL;
2365  stonith_key_value_t *dIter = NULL;
2366  bool rc = FALSE;
2367 
2368  if (agent == NULL) {
2369  return rc;
2370  }
2371 
2372  st = stonith_api_new();
2373  if (st == NULL) {
2374  crm_err("Could not list fence agents: API memory allocation failed");
2375  return FALSE;
2376  }
2377  st->cmds->list_agents(st, st_opt_sync_call, NULL, &devices, timeout == 0 ? 120 : timeout);
2378 
2379  for (dIter = devices; dIter != NULL; dIter = dIter->next) {
2380  if (pcmk__str_eq(dIter->value, agent, pcmk__str_none)) {
2381  rc = TRUE;
2382  break;
2383  }
2384  }
2385 
2386  stonith_key_value_freeall(devices, 1, 1);
2388  return rc;
2389 }
2390 
2391 const char *
2393 {
2394  if (action == NULL) {
2395  return "fencing";
2396  } else if (!strcmp(action, "on")) {
2397  return "unfencing";
2398  } else if (!strcmp(action, "off")) {
2399  return "turning off";
2400  } else {
2401  return action;
2402  }
2403 }
2404 
2413 static void
2414 parse_list_line(const char *line, int len, GList **output)
2415 {
2416  size_t i = 0;
2417  size_t entry_start = 0;
2418 
2419  /* Skip complaints about additional parameters device doesn't understand
2420  *
2421  * @TODO Document or eliminate the implied restriction of target names
2422  */
2423  if (strstr(line, "invalid") || strstr(line, "variable")) {
2424  crm_debug("Skipping list output line: %s", line);
2425  return;
2426  }
2427 
2428  // Process line content, character by character
2429  for (i = 0; i <= len; i++) {
2430 
2431  if (isspace(line[i]) || (line[i] == ',') || (line[i] == ';')
2432  || (line[i] == '\0')) {
2433  // We've found a separator (i.e. the end of an entry)
2434 
2435  int rc = 0;
2436  char *entry = NULL;
2437 
2438  if (i == entry_start) {
2439  // Skip leading and sequential separators
2440  entry_start = i + 1;
2441  continue;
2442  }
2443 
2444  entry = calloc(i - entry_start + 1, sizeof(char));
2445  CRM_ASSERT(entry != NULL);
2446 
2447  /* Read entry, stopping at first separator
2448  *
2449  * @TODO Document or eliminate these character restrictions
2450  */
2451  rc = sscanf(line + entry_start, "%[a-zA-Z0-9_-.]", entry);
2452  if (rc != 1) {
2453  crm_warn("Could not parse list output entry: %s "
2454  CRM_XS " entry_start=%d position=%d",
2455  line + entry_start, entry_start, i);
2456  free(entry);
2457 
2458  } else if (pcmk__strcase_any_of(entry, "on", "off", NULL)) {
2459  /* Some agents print the target status in the list output,
2460  * though none are known now (the separate list-status command
2461  * is used for this, but it can also print "UNKNOWN"). To handle
2462  * this possibility, skip such entries.
2463  *
2464  * @TODO Document or eliminate the implied restriction of target
2465  * names.
2466  */
2467  free(entry);
2468 
2469  } else {
2470  // We have a valid entry
2471  *output = g_list_append(*output, entry);
2472  }
2473  entry_start = i + 1;
2474  }
2475  }
2476 }
2477 
2499 GList *
2500 stonith__parse_targets(const char *target_spec)
2501 {
2502  GList *targets = NULL;
2503 
2504  if (target_spec != NULL) {
2505  size_t out_len = strlen(target_spec);
2506  size_t line_start = 0; // Starting index of line being processed
2507 
2508  for (size_t i = 0; i <= out_len; ++i) {
2509  if ((target_spec[i] == '\n') || (target_spec[i] == '\0')
2510  || ((target_spec[i] == '\\') && (target_spec[i + 1] == 'n'))) {
2511  // We've reached the end of one line of output
2512 
2513  int len = i - line_start;
2514 
2515  if (len > 0) {
2516  char *line = strndup(target_spec + line_start, len);
2517 
2518  line[len] = '\0'; // Because it might be a newline
2519  parse_list_line(line, len, &targets);
2520  free(line);
2521  }
2522  if (target_spec[i] == '\\') {
2523  ++i; // backslash-n takes up two positions
2524  }
2525  line_start = i + 1;
2526  }
2527  }
2528  }
2529  return targets;
2530 }
2531 
2539 gboolean
2541 {
2542  gboolean ret = FALSE;
2543 
2544  for (stonith_history_t *prev_hp = top_history; prev_hp; prev_hp = prev_hp->next) {
2545  if (prev_hp == event) {
2546  break;
2547  }
2548 
2549  if ((prev_hp->state == st_done) &&
2550  pcmk__str_eq(event->target, prev_hp->target, pcmk__str_casei) &&
2551  pcmk__str_eq(event->action, prev_hp->action, pcmk__str_casei) &&
2552  pcmk__str_eq(event->delegate, prev_hp->delegate, pcmk__str_casei) &&
2553  (event->completed < prev_hp->completed)) {
2554  ret = TRUE;
2555  break;
2556  }
2557  }
2558  return ret;
2559 }
2560 
2572 {
2573  stonith_history_t *new = NULL, *pending = NULL, *hp, *np, *tmp;
2574 
2575  for (hp = history; hp; ) {
2576  tmp = hp->next;
2577  if ((hp->state == st_done) || (hp->state == st_failed)) {
2578  /* sort into new */
2579  if ((!new) || (hp->completed > new->completed)) {
2580  hp->next = new;
2581  new = hp;
2582  } else {
2583  np = new;
2584  do {
2585  if ((!np->next) || (hp->completed > np->next->completed)) {
2586  hp->next = np->next;
2587  np->next = hp;
2588  break;
2589  }
2590  np = np->next;
2591  } while (1);
2592  }
2593  } else {
2594  /* put into pending */
2595  hp->next = pending;
2596  pending = hp;
2597  }
2598  hp = tmp;
2599  }
2600 
2601  /* pending actions don't have a completed-stamp so make them go front */
2602  if (pending) {
2603  stonith_history_t *last_pending = pending;
2604 
2605  while (last_pending->next) {
2606  last_pending = last_pending->next;
2607  }
2608 
2609  last_pending->next = new;
2610  new = pending;
2611  }
2612  return new;
2613 }
2614 
2617  bool (*matching_fn)(stonith_history_t *, void *),
2618  void *user_data)
2619 {
2620  for (stonith_history_t *hp = history; hp; hp = hp->next) {
2621  if (matching_fn(hp, user_data)) {
2622  return hp;
2623  }
2624  }
2625 
2626  return NULL;
2627 }
2628 
2629 bool
2631 {
2632  return history->state != st_failed && history->state != st_done;
2633 }
2634 
2635 bool
2636 stonith__event_state_eq(stonith_history_t *history, void *user_data)
2637 {
2638  return history->state == GPOINTER_TO_INT(user_data);
2639 }
2640 
2641 bool
2643 {
2644  return history->state != GPOINTER_TO_INT(user_data);
2645 }
2646 
2647 // Deprecated functions kept only for backward API compatibility
2648 const char *get_stonith_provider(const char *agent, const char *provider);
2649 
2653 const char *
2654 get_stonith_provider(const char *agent, const char *provider)
2655 {
2656  return stonith_namespace2text(stonith_get_namespace(agent, provider));
2657 }
2658 
2659 void
2660 stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name,
2661  xmlNode *metadata)
2662 {
2663  xmlXPathObjectPtr xpath = NULL;
2664  int max = 0;
2665  int lpc = 0;
2666 
2667  CRM_CHECK((device_flags != NULL) && (metadata != NULL), return);
2668 
2669  xpath = xpath_search(metadata, "//parameter");
2670  max = numXpathResults(xpath);
2671 
2672  if (max <= 0) {
2673  freeXpathObject(xpath);
2674  return;
2675  }
2676 
2677  for (lpc = 0; lpc < max; lpc++) {
2678  const char *parameter = NULL;
2679  xmlNode *match = getXpathResult(xpath, lpc);
2680 
2681  CRM_LOG_ASSERT(match != NULL);
2682  if (match == NULL) {
2683  continue;
2684  }
2685 
2686  parameter = crm_element_value(match, "name");
2687 
2688  if (pcmk__str_eq(parameter, "plug", pcmk__str_casei)) {
2689  stonith__set_device_flags(*device_flags, device_name,
2691 
2692  } else if (pcmk__str_eq(parameter, "port", pcmk__str_casei)) {
2693  stonith__set_device_flags(*device_flags, device_name,
2695  }
2696  }
2697 
2698  freeXpathObject(xpath);
2699 }
#define LOG_TRACE
Definition: logging.h:36
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:215
char uname[MAX_NAME]
Definition: internal.h:85
#define XML_ATTR_STONITH_TARGET_ATTRIBUTE
Definition: msg_xml.h:408
struct stonith_action_s stonith_action_t
Definition: internal.h:50
void stonith_history_free(stonith_history_t *history)
Definition: st_client.c:1165
#define F_STONITH_REMOTE_OP_ID
Definition: internal.h:103
struct stonith_history_s * next
Definition: stonith-ng.h:106
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition: ipc_client.c:790
A dumping ground.
#define F_TYPE
Definition: msg_xml.h:30
#define crm_notice(fmt, args...)
Definition: logging.h:349
int(* register_level_full)(stonith_t *st, int options, const char *node, const char *pattern, const char *attr, const char *value, int level, stonith_key_value_t *device_list)
Register fencing level for specific node, node regex or attribute.
Definition: stonith-ng.h:367
#define F_STONITH_CLIENTID
Definition: internal.h:97
const char * pcmk_strerror(int rc)
Definition: results.c:58
#define ETIME
Definition: portability.h:165
void pcmk__add_separated_word(char **list, size_t *len, const char *word, const char *separator)
Definition: strings.c:617
void services_action_free(svc_action_t *op)
Definition: services.c:472
void stonith__device_parameter_flags(uint32_t *device_flags, const char *device_name, xmlNode *metadata)
Definition: st_client.c:2660
stonith_t * stonith
Definition: st_client.c:104
#define api_log_open()
Definition: st_client.c:2251
#define PCMK__FENCE_BINDIR
Definition: config.h:544
void hash2field(gpointer key, gpointer value, gpointer user_data)
Set XML attribute based on hash table entry.
Definition: nvpair.c:785
int stonith__rhcs_metadata(const char *agent, int timeout, char **output)
Execute RHCS-compatible agent's meta-data action.
Definition: st_rhcs.c:207
bool stonith__event_state_neq(stonith_history_t *history, void *user_data)
Definition: st_client.c:2642
char * standard
Definition: services.h:128
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:842
stonith_key_value_t * stonith_key_value_add(stonith_key_value_t *head, const char *key, const char *value)
Definition: st_client.c:2207
void stonith_dump_pending_callbacks(stonith_t *stonith)
Definition: st_client.c:1709
#define crm_log_output(level, prefix, output)
Definition: logging.h:112
int crm_ipc_get_fd(crm_ipc_t *client)
Definition: ipc_client.c:893
char * id
Definition: services.h:123
#define stonith__set_device_flags(device_flags, device_id, flags_to_set)
Definition: internal.h:28
int(* query)(stonith_t *st, int options, const char *node, stonith_key_value_t **devices, int timeout)
Retrieve a list of registered stonith devices.
Definition: stonith-ng.h:260
xmlNode * create_device_registration_xml(const char *id, enum stonith_namespace namespace, const char *agent, stonith_key_value_t *params, const char *rsc_provides)
Definition: st_client.c:274
bool stonith__event_state_eq(stonith_history_t *history, void *user_data)
Definition: st_client.c:2636
#define F_SUBTYPE
Definition: msg_xml.h:26
int stonith_api_kick(uint32_t nodeid, const char *uname, int timeout, bool off)
Definition: st_client.c:2255
#define F_STONITH_CALLBACK_TOKEN
Definition: internal.h:125
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:274
#define F_STONITH_CLIENTNAME
Definition: internal.h:126
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:425
xmlNode * stonith_create_op(int call_id, const char *token, const char *op, xmlNode *data, int call_options)
Definition: st_client.c:1211
int pcmk__substitute_secrets(const char *rsc_id, GHashTable *params)
Definition: cib_secrets.c:96
#define XML_TAG_FENCING_LEVEL
Definition: msg_xml.h:403
#define STONITH_OP_FENCE
Definition: internal.h:168
const char * stonith_action_str(const char *action)
Turn stonith action into a more readable string.
Definition: st_client.c:2392
struct stonith_key_value_s * next
Definition: stonith-ng.h:95
#define XML_TAG_ATTRS
Definition: msg_xml.h:172
struct mainloop_io_s mainloop_io_t
Definition: mainloop.h:32
svc_action_t * services_action_create_generic(const char *exec, const char *args[])
Definition: services.c:311
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:317
gboolean services_action_async_fork_notify(svc_action_t *op, void(*action_callback)(svc_action_t *), void(*action_fork_callback)(svc_action_t *))
Definition: services.c:740
gboolean stonith__later_succeeded(stonith_history_t *event, stonith_history_t *top_history)
Definition: st_client.c:2540
int(* register_level)(stonith_t *st, int options, const char *node, int level, stonith_key_value_t *device_list)
Register a fencing level containing the fencing devices to be used at that level for a specific node.
Definition: stonith-ng.h:200
#define pcmk_err_generic
Definition: results.h:70
void stonith_key_value_freeall(stonith_key_value_t *head, int keys, int values)
Definition: st_client.c:2234
#define F_STONITH_TIMEOUT
Definition: internal.h:107
int stonith__lha_metadata(const char *agent, int timeout, char **output)
Definition: st_lha.c:175
#define MAX_IPC_DELAY
Definition: crm.h:78
void stonith__destroy_action(stonith_action_t *action)
Definition: st_client.c:582
#define T_STONITH_TIMEOUT_VALUE
Definition: internal.h:152
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:199
stonith_namespace
Definition: stonith-ng.h:75
long crm_ipc_read(crm_ipc_t *client)
Definition: ipc_client.c:1003
uint32_t pid
Definition: internal.h:81
int call_id
Definition: internal.h:95
#define F_STONITH_NOTIFY_DEACTIVATE
Definition: internal.h:129
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:420
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:587
void stonith__action_result(stonith_action_t *action, int *rc, char **output, char **error_output)
Definition: st_client.c:613
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:559
int(* remove_callback)(stonith_t *st, int call_id, bool all_callbacks)
Remove a registered callback for a given call id.
Definition: stonith-ng.h:330
#define LOG_NEVER
Definition: logging.h:46
xmlNode * get_xpath_object(const char *xpath, xmlNode *xml_obj, int error_level)
Definition: xpath.c:213
int stonith__execute(stonith_action_t *action)
Definition: st_client.c:897
Wrappers for and extensions to glib mainloop.
#define STONITH_OP_LEVEL_DEL
Definition: internal.h:174
char * strndup(const char *str, size_t len)
#define STONITH_OP_DEVICE_ADD
Definition: internal.h:170
#define STONITH_OP_EXEC
Definition: internal.h:165
#define CRM_OP_REGISTER
Definition: crm.h:142
const char * action
Definition: pcmk_fence.c:30
xmlNode * string2xml(const char *input)
Definition: xml.c:835
const char * crm_ipc_buffer(crm_ipc_t *client)
Definition: ipc_client.c:1046
const char * stonith_namespace2text(enum stonith_namespace st_namespace)
Get agent namespace name.
Definition: st_client.c:156
int stonith__list_lha_agents(stonith_key_value_t **devices)
Definition: st_lha.c:106
uint32_t id
Definition: internal.h:80
#define F_STONITH_ACTION
Definition: internal.h:143
#define T_STONITH_NG
Definition: internal.h:147
time_t stonith_api_time(uint32_t nodeid, const char *uname, bool in_progress)
Definition: st_client.c:2297
int(* free)(stonith_t *st)
Destroy the stonith api structure.
Definition: stonith-ng.h:143
int timeout
Definition: internal.h:96
enum svc_action_flags flags
Definition: services.h:145
#define XML_ATTR_STONITH_TARGET_PATTERN
Definition: msg_xml.h:407
xmlNode * create_level_registration_xml(const char *node, const char *pattern, const char *attr, const char *value, int level, stonith_key_value_t *device_list)
Definition: st_client.c:394
#define crm_warn(fmt, args...)
Definition: logging.h:348
bool stonith__agent_is_rhcs(const char *agent)
Definition: st_rhcs.c:233
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:2186
stonith_t * st
Definition: pcmk_fence.c:28
#define STONITH_ATTR_HOSTARG
Definition: internal.h:155
bool stonith_dispatch(stonith_t *st)
Definition: st_client.c:1960
int rc
Definition: pcmk_fence.c:35
#define F_STONITH_CALLID
Definition: internal.h:99
#define crm_debug(fmt, args...)
Definition: logging.h:352
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:2616
#define STONITH_OP_LEVEL_ADD
Definition: internal.h:173
struct crm_ipc_s crm_ipc_t
Definition: ipc.h:162
enum stonith_state state
Definition: stonith-ng.h:419
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:726
#define XML_ATTR_ID
Definition: msg_xml.h:96
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:523
#define STONITH_OP_QUERY
Definition: internal.h:167
gboolean services_action_sync(svc_action_t *op)
Definition: services.c:877
char * stdout_data
Definition: services.h:148
int(* metadata)(stonith_t *st, int options, const char *device, const char *provider, char **output, int timeout)
Get the metadata documentation for a resource.
Definition: stonith-ng.h:211
#define F_STONITH_DEVICE
Definition: internal.h:142
#define XML_ATTR_STONITH_DEVICES
Definition: msg_xml.h:409
int(* register_device)(stonith_t *st, int options, const char *id, const char *provider, const char *agent, stonith_key_value_t *params)
Register a stonith device with the local stonith daemon.
Definition: stonith-ng.h:180
GList * stonith__parse_targets(const char *target_spec)
Definition: st_client.c:2500
int(* status)(stonith_t *st, int options, const char *id, const char *port, int timeout)
Check to see if a local stonith device's port is reachable.
Definition: stonith-ng.h:249
GHashTable * params
Definition: services.h:133
enum stonith_namespace stonith_text2namespace(const char *namespace_s)
Get agent namespace by name.
Definition: st_client.c:130
guint ref
Definition: internal.h:97
#define crm_trace(fmt, args...)
Definition: logging.h:353
#define XML_ATTR_STONITH_INDEX
Definition: msg_xml.h:404
int(* fence)(stonith_t *st, int options, const char *node, const char *action, int timeout, int tolerance)
Issue a fencing action against a node.
Definition: stonith-ng.h:278
int(* register_callback)(stonith_t *st, int call_id, int timeout, int options, void *userdata, const char *callback_name, void(*callback)(stonith_t *st, stonith_callback_data_t *data))
Register a callback to receive the result of an asynchronous call.
Definition: stonith-ng.h:319
#define stonith__set_call_options(st_call_opts, call_for, flags_to_set)
Definition: internal.h:35
#define crm_log_xml_debug(xml, text)
Definition: logging.h:360
#define F_STONITH_RC
Definition: internal.h:105
bool stonith_agent_exists(const char *agent, int timeout)
Definition: st_client.c:2361
char * agent
Definition: services.h:130
#define XML_ATTR_STONITH_TARGET
Definition: msg_xml.h:405
Wrappers for and extensions to libxml2.
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:663
#define F_STONITH_STATE
Definition: internal.h:138
#define crm_log_xml_warn(xml, text)
Definition: logging.h:357
int(* disconnect)(stonith_t *st)
Disconnect from the local stonith daemon.
Definition: stonith-ng.h:159
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:244
int(* stonith_op_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **)
Definition: st_client.c:107
enum stonith_namespace stonith_get_namespace(const char *agent, const char *namespace_s)
Determine namespace of a fence agent.
Definition: st_client.c:177
#define T_STONITH_NOTIFY_DISCONNECT
Definition: stonith-ng.h:29
const char * get_stonith_provider(const char *agent, const char *provider)
Deprecated (use stonith_get_namespace() instead)
Definition: st_client.c:2654
#define STONITH_OP_DEVICE_DEL
Definition: internal.h:171
int(* list)(stonith_t *st, int options, const char *id, char **list_output, int timeout)
Retrieve string listing hosts and port assignments from a local stonith device.
Definition: stonith-ng.h:233
#define ECOMM
Definition: portability.h:141
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:900
void crm_ipc_destroy(crm_ipc_t *client)
Definition: ipc_client.c:870
#define XML_ATTR_STONITH_TARGET_VALUE
Definition: msg_xml.h:406
#define F_STONITH_TARGET
Definition: internal.h:102
struct stonith_notify_client_s stonith_notify_client_t
int(* list_agents)(stonith_t *stonith, int call_options, const char *provider, stonith_key_value_t **devices, int timeout)
Retrieve a list of installed stonith agents.
Definition: stonith-ng.h:224
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition: messages.c:162
void stonith_api_delete(stonith_t *stonith)
Definition: st_client.c:2018
int(* fence_with_delay)(stonith_t *st, int options, const char *node, const char *action, int timeout, int tolerance, int delay)
Issue a fencing action against a node with requested fencing delay.
Definition: stonith-ng.h:412
void free_xml(xmlNode *child)
Definition: xml.c:790
int(* connect)(stonith_t *st, const char *name, int *stonith_fd)
Connect to the local stonith daemon.
Definition: stonith-ng.h:151
#define api_log(level, fmt, args...)
Definition: st_client.c:2252
int sequence
Definition: services.h:142
#define STONITH_ATTR_ACTION_OP
Definition: internal.h:163
#define STONITH_OP_FENCE_HISTORY
Definition: internal.h:172
#define F_STONITH_CALLOPTS
Definition: internal.h:98
stonith_history_t * stonith__sort_history(stonith_history_t *history)
Definition: st_client.c:2571
int call_timeout
Definition: stonith-ng.h:422
int(* remove_device)(stonith_t *st, int options, const char *name)
Remove a registered stonith device with the local stonith daemon.
Definition: stonith-ng.h:169
struct stonith_private_s stonith_private_t
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc_client.c:907
stonith_action_t * stonith_action_create(const char *agent, const char *_action, const char *victim, uint32_t victim_nodeid, int timeout, GHashTable *device_args, GHashTable *port_map, const char *host_arg)
Definition: st_client.c:642
const char * target
Definition: pcmk_fence.c:29
#define PCMK_RESOURCE_CLASS_STONITH
Definition: services.h:52
#define CRM_XS
Definition: logging.h:54
int(* register_notification)(stonith_t *st, const char *event, void(*notify)(stonith_t *st, stonith_event_t *e))
Definition: stonith-ng.h:297
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
Definition: ipc_client.c:939
int(* monitor)(stonith_t *st, int options, const char *id, int timeout)
Check to see if a local stonith device is reachable.
Definition: stonith-ng.h:241
char * client_origin
Definition: stonith-ng.h:127
#define F_STONITH_DATE
Definition: internal.h:137
#define ENODATA
Definition: portability.h:161
int(* remove_notification)(stonith_t *st, const char *event)
Definition: stonith-ng.h:300
void log_action(unsigned int log_level, const char *pre_text, pe_action_t *action, gboolean details)
#define crm_log_xml_err(xml, text)
Definition: logging.h:356
struct stonith_callback_client_s stonith_callback_client_t
int(* validate)(stonith_t *st, int call_options, const char *rsc_id, const char *namespace_s, const char *agent, stonith_key_value_t *params, int timeout, char **output, char **error_output)
Validate an arbitrary stonith device configuration.
Definition: stonith-ng.h:390
int stonith__list_rhcs_agents(stonith_key_value_t **devices)
Definition: st_rhcs.c:33
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:298
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
Definition: ipc_internal.h:176
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:906
#define CRM_META
Definition: crm.h:71
#define F_STONITH_DELAY
Definition: internal.h:109
#define crm_err(fmt, args...)
Definition: logging.h:347
#define G_PRIORITY_MEDIUM
Definition: mainloop.h:153
#define CRM_ASSERT(expr)
Definition: results.h:42
xmlXPathObjectPtr xpath_search(xmlNode *xml_top, const char *path)
Definition: xpath.c:138
#define ENOTUNIQ
Definition: portability.h:137
int(* remove_level_full)(stonith_t *st, int options, const char *node, const char *pattern, const char *attr, const char *value, int level)
Remove fencing level for specific node, node regex or attribute.
Definition: stonith-ng.h:347
stonith_api_operations_t * cmds
Definition: stonith-ng.h:425
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
Definition: ipc_client.c:1139
stonith_t * stonith_api_new(void)
Definition: st_client.c:2107
int(* remove_level)(stonith_t *st, int options, const char *node, int level)
Remove a fencing level for a specific node.
Definition: stonith-ng.h:190
int delay
Definition: pcmk_fence.c:34
#define FAILURE_MAX_RETRIES
Definition: st_client.c:640
#define crm_log_xml_notice(xml, text)
Definition: logging.h:358
Fencing aka. STONITH.
xmlNode * getXpathResult(xmlXPathObjectPtr xpathObj, int index)
Definition: xpath.c:57
char * executioner
Definition: stonith-ng.h:122
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:745
char * operation
Definition: stonith-ng.h:116
char data[0]
Definition: internal.h:90
#define crm_str(x)
Definition: logging.h:373
#define F_STONITH_ORIGIN
Definition: internal.h:135
#define pcmk_ok
Definition: results.h:67
bool stonith__agent_is_lha(const char *agent)
Determine namespace of a fence agent.
Definition: st_lha.c:79
bool stonith__event_state_pending(stonith_history_t *history, void *user_data)
Definition: st_client.c:2630
#define T_STONITH_NOTIFY_FENCE
Definition: stonith-ng.h:30
int(* confirm)(stonith_t *st, int options, const char *node)
Manually confirm that a node is down.
Definition: stonith-ng.h:287
void * st_private
Definition: stonith-ng.h:423
void * cb_data
Definition: services.h:156
#define T_STONITH_NOTIFY
Definition: internal.h:153
#define crm_log_xml_trace(xml, text)
Definition: logging.h:361
bool pcmk__starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:452
#define F_STONITH_OPERATION
Definition: internal.h:101
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:880
#define F_STONITH_NOTIFY_ACTIVATE
Definition: internal.h:128
#define F_XML_TAGNAME
Definition: msg_xml.h:38
char * name
Definition: pcmk_fence.c:31
void freeXpathObject(xmlXPathObjectPtr xpathObj)
Definition: xpath.c:38
crm_ipc_flags
Definition: ipc.h:143
void crm_ipc_close(crm_ipc_t *client)
Definition: ipc_client.c:857
#define F_STONITH_CALLDATA
Definition: internal.h:100
CRM_TRACE_INIT_DATA(stonith)
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
unsigned int timeout
Definition: pcmk_fence.c:32
#define F_STONITH_DELEGATE
Definition: internal.h:130
#define crm_info(fmt, args...)
Definition: logging.h:350
int call_id
Definition: stonith-ng.h:421
int(* history)(stonith_t *st, int options, const char *node, stonith_history_t **output, int timeout)
Retrieve a list of fencing operations that have occurred for a specific node.
Definition: stonith-ng.h:295
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Definition: mainloop.h:74
#define F_STONITH_HISTORY_LIST
Definition: internal.h:136
int stonith_action_execute_async(stonith_action_t *action, void *userdata, void(*done)(GPid pid, int rc, const char *output, gpointer user_data), void(*fork_cb)(GPid pid, gpointer user_data))
Definition: st_client.c:870
enum crm_ais_msg_types type
Definition: internal.h:83
#define F_STONITH_TOLERANCE
Definition: internal.h:108
char * stderr_data
Definition: services.h:147