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