pacemaker  2.0.3-4b1f869f0f
Scalable High-Availability cluster resource manager
services.c
Go to the documentation of this file.
1 /*
2  * Copyright 2010-2019 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 
12 #ifndef _GNU_SOURCE
13 # define _GNU_SOURCE
14 #endif
15 
16 #include <sys/types.h>
17 #include <stdio.h>
18 #include <errno.h>
19 #include <unistd.h>
20 #include <dirent.h>
21 #include <fcntl.h>
22 
23 #include <crm/crm.h>
24 #include <crm/common/mainloop.h>
25 #include <crm/services.h>
26 #include <crm/stonith-ng.h>
27 #include <crm/msg_xml.h>
28 #include "services_private.h"
29 #include "services_lsb.h"
30 
31 #if SUPPORT_UPSTART
32 # include <upstart.h>
33 #endif
34 
35 #if SUPPORT_SYSTEMD
36 # include <systemd.h>
37 #endif
38 
39 /* TODO: Develop a rollover strategy */
40 
41 static int operations = 0;
42 static GHashTable *recurring_actions = NULL;
43 
44 /* ops waiting to run async because of conflicting active
45  * pending ops */
46 static GList *blocked_ops = NULL;
47 
48 /* ops currently active (in-flight) */
49 static GList *inflight_ops = NULL;
50 
51 static void handle_blocked_ops(void);
52 
64 const char *
65 resources_find_service_class(const char *agent)
66 {
67  if (services__lsb_agent_exists(agent)) {
69  }
70 
71 #if SUPPORT_SYSTEMD
72  if (systemd_unit_exists(agent)) {
74  }
75 #endif
76 
77 #if SUPPORT_UPSTART
78  if (upstart_job_exists(agent)) {
80  }
81 #endif
82  return NULL;
83 }
84 
85 static inline void
86 init_recurring_actions(void)
87 {
88  if (recurring_actions == NULL) {
89  recurring_actions = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
90  NULL);
91  }
92 }
93 
102 static inline gboolean
103 inflight_systemd_or_upstart(svc_action_t *op)
104 {
107  && (g_list_find(inflight_ops, op) != NULL);
108 }
109 
122 static char *
123 expand_resource_class(const char *rsc, const char *standard, const char *agent)
124 {
125  char *expanded_class = NULL;
126 
127  if (strcasecmp(standard, PCMK_RESOURCE_CLASS_SERVICE) == 0) {
128  const char *found_class = resources_find_service_class(agent);
129 
130  if (found_class) {
131  crm_debug("Found %s agent %s for %s", found_class, agent, rsc);
132  expanded_class = strdup(found_class);
133  } else {
134  crm_info("Assuming resource class lsb for agent %s for %s",
135  agent, rsc);
136  expanded_class = strdup(PCMK_RESOURCE_CLASS_LSB);
137  }
138  } else {
139  expanded_class = strdup(standard);
140  }
141  CRM_ASSERT(expanded_class);
142  return expanded_class;
143 }
144 
153 static char *
154 dup_file_path(const char *filename, const char *dirname)
155 {
156  return (*filename == '/')? strdup(filename)
157  : crm_strdup_printf("%s/%s", dirname, filename);
158 }
159 
160 svc_action_t *
161 resources_action_create(const char *name, const char *standard,
162  const char *provider, const char *agent,
163  const char *action, guint interval_ms, int timeout,
164  GHashTable *params, enum svc_action_flags flags)
165 {
166  svc_action_t *op = NULL;
167  uint32_t ra_caps = 0;
168 
169  /*
170  * Do some up front sanity checks before we go off and
171  * build the svc_action_t instance.
172  */
173 
174  if (crm_strlen_zero(name)) {
175  crm_err("Cannot create operation without resource name");
176  goto return_error;
177  }
178 
179  if (crm_strlen_zero(standard)) {
180  crm_err("Cannot create operation for %s without resource class", name);
181  goto return_error;
182  }
183  ra_caps = pcmk_get_ra_caps(standard);
184 
185  if (is_set(ra_caps, pcmk_ra_cap_provider) && crm_strlen_zero(provider)) {
186  crm_err("Cannot create operation for %s without provider", name);
187  goto return_error;
188  }
189 
190  if (crm_strlen_zero(agent)) {
191  crm_err("Cannot create operation for %s without agent name", name);
192  goto return_error;
193  }
194 
195  if (crm_strlen_zero(action)) {
196  crm_err("Cannot create operation for %s without operation name", name);
197  goto return_error;
198  }
199 
200  /*
201  * Sanity checks passed, proceed!
202  */
203 
204  op = calloc(1, sizeof(svc_action_t));
205  op->opaque = calloc(1, sizeof(svc_action_private_t));
206  op->rsc = strdup(name);
207  op->interval_ms = interval_ms;
208  op->timeout = timeout;
209  op->standard = expand_resource_class(name, standard, agent);
210  op->agent = strdup(agent);
211  op->sequence = ++operations;
212  op->flags = flags;
213  op->id = generate_op_key(name, action, interval_ms);
214 
215  if (is_set(ra_caps, pcmk_ra_cap_status) && safe_str_eq(action, "monitor")) {
216  op->action = strdup("status");
217  } else {
218  op->action = strdup(action);
219  }
220 
221  if (is_set(ra_caps, pcmk_ra_cap_provider)) {
222  op->provider = strdup(provider);
223  }
224 
225  if (is_set(ra_caps, pcmk_ra_cap_params)) {
226  op->params = params;
227  params = NULL; // so we don't free them in this function
228  }
229 
230  if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_OCF) == 0) {
231  op->opaque->exec = crm_strdup_printf("%s/resource.d/%s/%s",
232  OCF_ROOT_DIR, provider, agent);
233  op->opaque->args[0] = strdup(op->opaque->exec);
234  op->opaque->args[1] = strdup(op->action);
235 
236  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_LSB) == 0) {
238  op->opaque->args[0] = strdup(op->opaque->exec);
239  op->opaque->args[1] = strdup(op->action);
240 
241 #if SUPPORT_SYSTEMD
242  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_SYSTEMD) == 0) {
243  op->opaque->exec = strdup("systemd-dbus");
244 #endif
245 #if SUPPORT_UPSTART
246  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_UPSTART) == 0) {
247  op->opaque->exec = strdup("upstart-dbus");
248 #endif
249 #if SUPPORT_NAGIOS
250  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_NAGIOS) == 0) {
251  op->opaque->exec = dup_file_path(op->agent, NAGIOS_PLUGIN_DIR);
252  op->opaque->args[0] = strdup(op->opaque->exec);
253 
254  if (safe_str_eq(op->action, "monitor") && (op->interval_ms == 0)) {
255  /* Invoke --version for a nagios probe */
256  op->opaque->args[1] = strdup("--version");
257 
258  } else if (op->params) {
259  GHashTableIter iter;
260  char *key = NULL;
261  char *value = NULL;
262  int index = 1;
263  static int args_size = sizeof(op->opaque->args) / sizeof(char *);
264 
265  g_hash_table_iter_init(&iter, op->params);
266 
267  while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value) &&
268  index <= args_size - 3) {
269 
270  if (safe_str_eq(key, XML_ATTR_CRM_VERSION) || strstr(key, CRM_META "_")) {
271  continue;
272  }
273  op->opaque->args[index++] = crm_strdup_printf("--%s", key);
274  op->opaque->args[index++] = strdup(value);
275  }
276  }
277 
278  // Nagios actions don't need to keep the parameters
279  if (op->params != NULL) {
280  g_hash_table_destroy(op->params);
281  op->params = NULL;
282  }
283 #endif
284  } else {
285  crm_err("Unknown resource standard: %s", op->standard);
286  goto return_error;
287  }
288 
289  if(params) {
290  g_hash_table_destroy(params);
291  }
292  return op;
293 
294  return_error:
295  if(params) {
296  g_hash_table_destroy(params);
297  }
299 
300  return NULL;
301 }
302 
303 svc_action_t *
304 services_action_create_generic(const char *exec, const char *args[])
305 {
306  svc_action_t *op;
307  unsigned int cur_arg;
308 
309  op = calloc(1, sizeof(*op));
310  op->opaque = calloc(1, sizeof(svc_action_private_t));
311 
312  op->opaque->exec = strdup(exec);
313  op->opaque->args[0] = strdup(exec);
314 
315  for (cur_arg = 1; args && args[cur_arg - 1]; cur_arg++) {
316  op->opaque->args[cur_arg] = strdup(args[cur_arg - 1]);
317 
318  if (cur_arg == DIMOF(op->opaque->args) - 1) {
319  crm_err("svc_action_t args list not long enough for '%s' execution request.", exec);
320  break;
321  }
322  }
323 
324  return op;
325 }
326 
341 svc_action_t *
342 services_alert_create(const char *id, const char *exec, int timeout,
343  GHashTable *params, int sequence, void *cb_data)
344 {
345  svc_action_t *action = services_action_create_generic(exec, NULL);
346 
347  CRM_ASSERT(action);
348  action->timeout = timeout;
349  action->id = strdup(id);
350  action->params = params;
351  action->sequence = sequence;
352  action->cb_data = cb_data;
353  return action;
354 }
355 
371 int
372 services_action_user(svc_action_t *op, const char *user)
373 {
374  CRM_CHECK((op != NULL) && (user != NULL), return -EINVAL);
375  return crm_user_lookup(user, &(op->opaque->uid), &(op->opaque->gid));
376 }
377 
389 gboolean
391 {
392  action->synchronous = false;
393  action->opaque->callback = cb;
394  return services_os_action_execute(action);
395 }
396 
397 #if SUPPORT_DBUS
398 
405 void
406 services_set_op_pending(svc_action_t *op, DBusPendingCall *pending)
407 {
408  if (op->opaque->pending && (op->opaque->pending != pending)) {
409  if (pending) {
410  crm_info("Lost pending %s DBus call (%p)", op->id, op->opaque->pending);
411  } else {
412  crm_trace("Done with pending %s DBus call (%p)", op->id, op->opaque->pending);
413  }
414  dbus_pending_call_unref(op->opaque->pending);
415  }
416  op->opaque->pending = pending;
417  if (pending) {
418  crm_trace("Updated pending %s DBus call (%p)", op->id, pending);
419  } else {
420  crm_trace("Cleared pending %s DBus call", op->id);
421  }
422 }
423 #endif
424 
425 void
427 {
428  if ((op == NULL) || (op->opaque == NULL)) {
429  return;
430  }
431 
432 #if SUPPORT_DBUS
433  if(op->opaque->timerid != 0) {
434  crm_trace("Removing timer for call %s to %s", op->action, op->rsc);
435  g_source_remove(op->opaque->timerid);
436  op->opaque->timerid = 0;
437  }
438 
439  if(op->opaque->pending) {
440  if (dbus_pending_call_get_completed(op->opaque->pending)) {
441  // This should never be the case
442  crm_warn("Result of %s op %s was unhandled",
443  op->standard, op->id);
444  } else {
445  crm_debug("Will ignore any result of canceled %s op %s",
446  op->standard, op->id);
447  }
448  dbus_pending_call_cancel(op->opaque->pending);
449  services_set_op_pending(op, NULL);
450  }
451 #endif
452 
453  if (op->opaque->stderr_gsource) {
455  op->opaque->stderr_gsource = NULL;
456  }
457 
458  if (op->opaque->stdout_gsource) {
460  op->opaque->stdout_gsource = NULL;
461  }
462 }
463 
464 void
466 {
467  unsigned int i;
468 
469  if (op == NULL) {
470  return;
471  }
472 
473  /* The operation should be removed from all tracking lists by this point.
474  * If it's not, we have a bug somewhere, so bail. That may lead to a
475  * memory leak, but it's better than a use-after-free segmentation fault.
476  */
477  CRM_CHECK(g_list_find(inflight_ops, op) == NULL, return);
478  CRM_CHECK(g_list_find(blocked_ops, op) == NULL, return);
479  CRM_CHECK((recurring_actions == NULL)
480  || (g_hash_table_lookup(recurring_actions, op->id) == NULL),
481  return);
482 
484 
485  if (op->opaque->repeat_timer) {
486  g_source_remove(op->opaque->repeat_timer);
487  op->opaque->repeat_timer = 0;
488  }
489 
490  free(op->id);
491  free(op->opaque->exec);
492 
493  for (i = 0; i < DIMOF(op->opaque->args); i++) {
494  free(op->opaque->args[i]);
495  }
496 
497  free(op->opaque);
498  free(op->rsc);
499  free(op->action);
500 
501  free(op->standard);
502  free(op->agent);
503  free(op->provider);
504 
505  free(op->stdout_data);
506  free(op->stderr_data);
507 
508  if (op->params) {
509  g_hash_table_destroy(op->params);
510  op->params = NULL;
511  }
512 
513  free(op);
514 }
515 
516 gboolean
518 {
519  crm_info("Cancelling %s operation %s", op->standard, op->id);
520 
521  if (recurring_actions) {
522  g_hash_table_remove(recurring_actions, op->id);
523  }
524 
525  if (op->opaque->repeat_timer) {
526  g_source_remove(op->opaque->repeat_timer);
527  op->opaque->repeat_timer = 0;
528  }
529 
530  return TRUE;
531 }
532 
542 gboolean
543 services_action_cancel(const char *name, const char *action, guint interval_ms)
544 {
545  gboolean cancelled = FALSE;
546  char *id = generate_op_key(name, action, interval_ms);
547  svc_action_t *op = NULL;
548 
549  /* We can only cancel a recurring action */
550  init_recurring_actions();
551  op = g_hash_table_lookup(recurring_actions, id);
552  if (op == NULL) {
553  goto done;
554  }
555 
556  /* Tell operation_finalize() not to reschedule the operation */
557  op->cancel = TRUE;
558 
559  /* Stop tracking it as a recurring operation, and stop its repeat timer */
561 
562  /* If the op has a PID, it's an in-flight child process, so kill it.
563  *
564  * Whether the kill succeeds or fails, the main loop will send the op to
565  * operation_finished() (and thus operation_finalize()) when the process
566  * goes away.
567  */
568  if (op->pid != 0) {
569  crm_info("Terminating in-flight op %s[%d] early because it was cancelled",
570  id, op->pid);
571  cancelled = mainloop_child_kill(op->pid);
572  if (cancelled == FALSE) {
573  crm_err("Termination of %s[%d] failed", id, op->pid);
574  }
575  goto done;
576  }
577 
578 #if SUPPORT_DBUS
579  // In-flight systemd and upstart ops don't have a pid
580  if (inflight_systemd_or_upstart(op)) {
581  inflight_ops = g_list_remove(inflight_ops, op);
582 
583  /* This will cause any result that comes in later to be discarded, so we
584  * don't call the callback and free the operation twice.
585  */
587  }
588 #endif
589 
590  // The rest of this is essentially equivalent to operation_finalize(),
591  // except without calling handle_blocked_ops()
592 
593  // Report operation as cancelled
595  if (op->opaque->callback) {
596  op->opaque->callback(op);
597  }
598 
599  blocked_ops = g_list_remove(blocked_ops, op);
601  cancelled = TRUE;
602  // @TODO Initiate handle_blocked_ops() asynchronously
603 
604 done:
605  free(id);
606  return cancelled;
607 }
608 
609 gboolean
610 services_action_kick(const char *name, const char *action, guint interval_ms)
611 {
612  svc_action_t * op = NULL;
613  char *id = generate_op_key(name, action, interval_ms);
614 
615  init_recurring_actions();
616  op = g_hash_table_lookup(recurring_actions, id);
617  free(id);
618 
619  if (op == NULL) {
620  return FALSE;
621  }
622 
623 
624  if (op->pid || inflight_systemd_or_upstart(op)) {
625  return TRUE;
626  } else {
627  if (op->opaque->repeat_timer) {
628  g_source_remove(op->opaque->repeat_timer);
629  op->opaque->repeat_timer = 0;
630  }
632  return TRUE;
633  }
634 
635 }
636 
645 static gboolean
646 handle_duplicate_recurring(svc_action_t * op)
647 {
648  svc_action_t * dup = NULL;
649 
650  /* check for duplicates */
651  dup = g_hash_table_lookup(recurring_actions, op->id);
652 
653  if (dup && (dup != op)) {
654  /* update user data */
655  if (op->opaque->callback) {
656  dup->opaque->callback = op->opaque->callback;
657  dup->cb_data = op->cb_data;
658  op->cb_data = NULL;
659  }
660  /* immediately execute the next interval */
661  if (dup->pid != 0) {
662  if (op->opaque->repeat_timer) {
663  g_source_remove(op->opaque->repeat_timer);
664  op->opaque->repeat_timer = 0;
665  }
667  }
668  /* free the duplicate */
670  return TRUE;
671  }
672 
673  return FALSE;
674 }
675 
676 inline static gboolean
677 action_exec_helper(svc_action_t * op)
678 {
679  /* Whether a/synchronous must be decided (op->synchronous) beforehand. */
680  if (op->standard
681  && (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_UPSTART) == 0)) {
682 #if SUPPORT_UPSTART
683  return upstart_job_exec(op);
684 #endif
685  } else if (op->standard && strcasecmp(op->standard,
687 #if SUPPORT_SYSTEMD
688  return systemd_unit_exec(op);
689 #endif
690  } else {
691  return services_os_action_execute(op);
692  }
693  /* The 'op' has probably been freed if the execution functions return TRUE
694  for the asynchronous 'op'. */
695  /* Avoid using the 'op' in here. */
696 
697  return FALSE;
698 }
699 
700 void
702 {
703  if (op == NULL) {
704  return;
705  }
706 
707  CRM_ASSERT(op->synchronous == FALSE);
708 
709  /* keep track of ops that are in-flight to avoid collisions in the same namespace */
710  if (op->rsc) {
711  inflight_ops = g_list_append(inflight_ops, op);
712  }
713 }
714 
721 void
723 {
724  /* Op is no longer in-flight or blocked */
725  inflight_ops = g_list_remove(inflight_ops, op);
726  blocked_ops = g_list_remove(blocked_ops, op);
727 
728  /* Op is no longer blocking other ops, so check if any need to run */
729  handle_blocked_ops();
730 }
731 
732 gboolean
734  void (*action_callback) (svc_action_t *),
735  void (*action_fork_callback) (svc_action_t *))
736 {
737  op->synchronous = false;
738  if (action_callback) {
739  op->opaque->callback = action_callback;
740  }
741  if (action_fork_callback) {
742  op->opaque->fork_callback = action_fork_callback;
743  }
744 
745  if (op->interval_ms > 0) {
746  init_recurring_actions();
747  if (handle_duplicate_recurring(op) == TRUE) {
748  /* entry rescheduled, dup freed */
749  /* exit early */
750  return TRUE;
751  }
752  g_hash_table_replace(recurring_actions, op->id, op);
753  }
754 
755  if (is_not_set(op->flags, SVC_ACTION_NON_BLOCKED)
756  && op->rsc && is_op_blocked(op->rsc)) {
757  blocked_ops = g_list_append(blocked_ops, op);
758  return TRUE;
759  }
760 
761  return action_exec_helper(op);
762 }
763 
764 gboolean
766  void (*action_callback) (svc_action_t *))
767 {
768  return services_action_async_fork_notify(op, action_callback, NULL);
769 }
770 
771 static gboolean processing_blocked_ops = FALSE;
772 
773 gboolean
774 is_op_blocked(const char *rsc)
775 {
776  GList *gIter = NULL;
777  svc_action_t *op = NULL;
778 
779  for (gIter = inflight_ops; gIter != NULL; gIter = gIter->next) {
780  op = gIter->data;
781  if (safe_str_eq(op->rsc, rsc)) {
782  return TRUE;
783  }
784  }
785 
786  return FALSE;
787 }
788 
789 static void
790 handle_blocked_ops(void)
791 {
792  GList *executed_ops = NULL;
793  GList *gIter = NULL;
794  svc_action_t *op = NULL;
795  gboolean res = FALSE;
796 
797  if (processing_blocked_ops) {
798  /* avoid nested calling of this function */
799  return;
800  }
801 
802  processing_blocked_ops = TRUE;
803 
804  /* n^2 operation here, but blocked ops are incredibly rare. this list
805  * will be empty 99% of the time. */
806  for (gIter = blocked_ops; gIter != NULL; gIter = gIter->next) {
807  op = gIter->data;
808  if (is_op_blocked(op->rsc)) {
809  continue;
810  }
811  executed_ops = g_list_append(executed_ops, op);
812  res = action_exec_helper(op);
813  if (res == FALSE) {
815  /* this can cause this function to be called recursively
816  * which is why we have processing_blocked_ops static variable */
817  operation_finalize(op);
818  }
819  }
820 
821  for (gIter = executed_ops; gIter != NULL; gIter = gIter->next) {
822  op = gIter->data;
823  blocked_ops = g_list_remove(blocked_ops, op);
824  }
825  g_list_free(executed_ops);
826 
827  processing_blocked_ops = FALSE;
828 }
829 
830 #if SUPPORT_NAGIOS
831 static int
832 nagios_get_metadata(const char *type, char **output)
833 {
834  int rc = pcmk_ok;
835  FILE *file_strm = NULL;
836  int start = 0, length = 0, read_len = 0;
837  char *metadata_file = crm_strdup_printf("%s/%s.xml",
839 
840  file_strm = fopen(metadata_file, "r");
841  if (file_strm == NULL) {
842  crm_err("Metadata file %s does not exist", metadata_file);
843  free(metadata_file);
844  return -EIO;
845  }
846 
847  /* see how big the file is */
848  start = ftell(file_strm);
849  fseek(file_strm, 0L, SEEK_END);
850  length = ftell(file_strm);
851  fseek(file_strm, 0L, start);
852 
853  CRM_ASSERT(length >= 0);
854  CRM_ASSERT(start == ftell(file_strm));
855 
856  if (length <= 0) {
857  crm_info("%s was not valid", metadata_file);
858  free(*output);
859  *output = NULL;
860  rc = -EIO;
861 
862  } else {
863  crm_trace("Reading %d bytes from file", length);
864  *output = calloc(1, (length + 1));
865  read_len = fread(*output, 1, length, file_strm);
866  if (read_len != length) {
867  crm_err("Calculated and read bytes differ: %d vs. %d",
868  length, read_len);
869  free(*output);
870  *output = NULL;
871  rc = -EIO;
872  }
873  }
874 
875  fclose(file_strm);
876  free(metadata_file);
877  return rc;
878 }
879 #endif
880 
881 static gboolean
882 action_get_metadata(svc_action_t *op)
883 {
884  const char *class = op->standard;
885 
886  if (op->agent == NULL) {
887  crm_err("meta-data requested without specifying agent");
888  return FALSE;
889  }
890 
891  if (class == NULL) {
892  crm_err("meta-data requested for agent %s without specifying class",
893  op->agent);
894  return FALSE;
895  }
896 
897  if (!strcmp(class, PCMK_RESOURCE_CLASS_SERVICE)) {
898  class = resources_find_service_class(op->agent);
899  }
900 
901  if (class == NULL) {
902  crm_err("meta-data requested for %s, but could not determine class",
903  op->agent);
904  return FALSE;
905  }
906 
907  if (safe_str_eq(class, PCMK_RESOURCE_CLASS_LSB)) {
908  return (services__get_lsb_metadata(op->agent, &op->stdout_data) >= 0);
909  }
910 
911 #if SUPPORT_NAGIOS
913  return (nagios_get_metadata(op->agent, &op->stdout_data) >= 0);
914  }
915 #endif
916 
917  return action_exec_helper(op);
918 }
919 
920 gboolean
922 {
923  gboolean rc = TRUE;
924 
925  if (op == NULL) {
926  crm_trace("No operation to execute");
927  return FALSE;
928  }
929 
930  op->synchronous = true;
931 
932  if (safe_str_eq(op->action, "meta-data")) {
933  /* Synchronous meta-data operations are handled specially. Since most
934  * resource classes don't provide any meta-data, it has to be
935  * synthesized from available information about the agent.
936  *
937  * services_action_async() doesn't treat meta-data actions specially, so
938  * it will result in an error for classes that don't support the action.
939  */
940  rc = action_get_metadata(op);
941  } else {
942  rc = action_exec_helper(op);
943  }
944  crm_trace(" > " CRM_OP_FMT ": %s = %d",
945  op->rsc, op->action, op->interval_ms, op->opaque->exec, op->rc);
946  if (op->stdout_data) {
947  crm_trace(" > stdout: %s", op->stdout_data);
948  }
949  if (op->stderr_data) {
950  crm_trace(" > stderr: %s", op->stderr_data);
951  }
952  return rc;
953 }
954 
955 GList *
956 get_directory_list(const char *root, gboolean files, gboolean executable)
957 {
958  return services_os_get_directory_list(root, files, executable);
959 }
960 
961 GList *
963 {
964  GList *standards = NULL;
965  GList *agents = NULL;
966 
967  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_OCF));
968  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_LSB));
969  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_SERVICE));
970 
971 #if SUPPORT_SYSTEMD
972  agents = systemd_unit_listall();
973  if (agents) {
974  standards = g_list_append(standards,
976  g_list_free_full(agents, free);
977  }
978 #endif
979 
980 #if SUPPORT_UPSTART
981  agents = upstart_job_listall();
982  if (agents) {
983  standards = g_list_append(standards,
985  g_list_free_full(agents, free);
986  }
987 #endif
988 
989 #if SUPPORT_NAGIOS
991  if (agents) {
992  standards = g_list_append(standards,
994  g_list_free_full(agents, free);
995  }
996 #endif
997 
998  return standards;
999 }
1000 
1001 GList *
1002 resources_list_providers(const char *standard)
1003 {
1004  if (is_set(pcmk_get_ra_caps(standard), pcmk_ra_cap_provider)) {
1006  }
1007 
1008  return NULL;
1009 }
1010 
1011 GList *
1012 resources_list_agents(const char *standard, const char *provider)
1013 {
1014  if ((standard == NULL)
1015  || (strcasecmp(standard, PCMK_RESOURCE_CLASS_SERVICE) == 0)) {
1016 
1017  GList *tmp1;
1018  GList *tmp2;
1019  GList *result = services__list_lsb_agents();
1020 
1021  if (standard == NULL) {
1022  tmp1 = result;
1023  tmp2 = resources_os_list_ocf_agents(NULL);
1024  if (tmp2) {
1025  result = g_list_concat(tmp1, tmp2);
1026  }
1027  }
1028 #if SUPPORT_SYSTEMD
1029  tmp1 = result;
1030  tmp2 = systemd_unit_listall();
1031  if (tmp2) {
1032  result = g_list_concat(tmp1, tmp2);
1033  }
1034 #endif
1035 
1036 #if SUPPORT_UPSTART
1037  tmp1 = result;
1038  tmp2 = upstart_job_listall();
1039  if (tmp2) {
1040  result = g_list_concat(tmp1, tmp2);
1041  }
1042 #endif
1043 
1044  return result;
1045 
1046  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_OCF) == 0) {
1047  return resources_os_list_ocf_agents(provider);
1048  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_LSB) == 0) {
1049  return services__list_lsb_agents();
1050 #if SUPPORT_SYSTEMD
1051  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_SYSTEMD) == 0) {
1052  return systemd_unit_listall();
1053 #endif
1054 #if SUPPORT_UPSTART
1055  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_UPSTART) == 0) {
1056  return upstart_job_listall();
1057 #endif
1058 #if SUPPORT_NAGIOS
1059  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_NAGIOS) == 0) {
1061 #endif
1062  }
1063 
1064  return NULL;
1065 }
1066 
1067 gboolean
1068 resources_agent_exists(const char *standard, const char *provider, const char *agent)
1069 {
1070  GList *standards = NULL;
1071  GList *providers = NULL;
1072  GListPtr iter = NULL;
1073  gboolean rc = FALSE;
1074  gboolean has_providers = FALSE;
1075 
1076  standards = resources_list_standards();
1077  for (iter = standards; iter != NULL; iter = iter->next) {
1078  if (crm_str_eq(iter->data, standard, TRUE)) {
1079  rc = TRUE;
1080  break;
1081  }
1082  }
1083 
1084  if (rc == FALSE) {
1085  goto done;
1086  }
1087 
1088  rc = FALSE;
1089 
1090  has_providers = is_set(pcmk_get_ra_caps(standard), pcmk_ra_cap_provider);
1091  if (has_providers == TRUE && provider != NULL) {
1092  providers = resources_list_providers(standard);
1093  for (iter = providers; iter != NULL; iter = iter->next) {
1094  if (crm_str_eq(iter->data, provider, TRUE)) {
1095  rc = TRUE;
1096  break;
1097  }
1098  }
1099  } else if (has_providers == FALSE && provider == NULL) {
1100  rc = TRUE;
1101  }
1102 
1103  if (rc == FALSE) {
1104  goto done;
1105  }
1106 
1107  if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_SERVICE)) {
1108  if (services__lsb_agent_exists(agent)) {
1109  rc = TRUE;
1110 #if SUPPORT_SYSTEMD
1111  } else if (systemd_unit_exists(agent)) {
1112  rc = TRUE;
1113 #endif
1114 
1115 #if SUPPORT_UPSTART
1116  } else if (upstart_job_exists(agent)) {
1117  rc = TRUE;
1118 #endif
1119  } else {
1120  rc = FALSE;
1121  }
1122 
1123  } else if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_OCF)) {
1124  rc = services__ocf_agent_exists(provider, agent);
1125 
1126  } else if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_LSB)) {
1127  rc = services__lsb_agent_exists(agent);
1128 
1129 #if SUPPORT_SYSTEMD
1130  } else if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_SYSTEMD)) {
1131  rc = systemd_unit_exists(agent);
1132 #endif
1133 
1134 #if SUPPORT_UPSTART
1135  } else if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_UPSTART)) {
1136  rc = upstart_job_exists(agent);
1137 #endif
1138 
1139 #if SUPPORT_NAGIOS
1140  } else if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_NAGIOS)) {
1141  rc = services__nagios_agent_exists(agent);
1142 #endif
1143 
1144  } else {
1145  rc = FALSE;
1146  }
1147 
1148 done:
1149  g_list_free(standards);
1150  g_list_free(providers);
1151  return rc;
1152 }
mainloop_child_kill
gboolean mainloop_child_kill(pid_t pid)
Definition: mainloop.c:1181
GListPtr
GList * GListPtr
Definition: crm.h:214
resources_list_providers
GList * resources_list_providers(const char *standard)
Get a list of providers.
Definition: services.c:1002
svc_action_s::opaque
svc_action_private_t * opaque
Definition: services.h:187
crm_str_eq
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:224
upstart_job_exists
gboolean upstart_job_exists(const char *name)
Definition: upstart.c:230
PCMK_RESOURCE_CLASS_SYSTEMD
#define PCMK_RESOURCE_CLASS_SYSTEMD
Definition: services.h:46
resources_list_agents
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
Definition: services.c:1012
svc_action_private_s::gid
gid_t gid
Definition: services_private.h:24
svc_action_private_s::uid
uid_t uid
Definition: services_private.h:23
flags
uint64_t flags
Definition: remote.c:5
msg_xml.h
svc_action_s::provider
char * provider
Definition: services.h:158
PCMK_LRM_OP_ERROR
@ PCMK_LRM_OP_ERROR
Definition: services.h:125
services_action_create_generic
svc_action_t * services_action_create_generic(const char *exec, const char *args[])
Definition: services.c:304
resources_agent_exists
gboolean resources_agent_exists(const char *standard, const char *provider, const char *agent)
Definition: services.c:1068
svc_action_private_s
Definition: services_private.h:19
svc_action_s::flags
enum svc_action_flags flags
Definition: services.h:174
svc_action_s::action
char * action
Definition: services.h:154
services__nagios_agent_exists
G_GNUC_INTERNAL gboolean services__nagios_agent_exists(const char *agent)
PCMK_LRM_OP_CANCELLED
@ PCMK_LRM_OP_CANCELLED
Definition: services.h:122
services__lsb_agent_path
char * services__lsb_agent_path(const char *agent)
Definition: services_lsb.c:249
services_private.h
PCMK_RESOURCE_CLASS_OCF
#define PCMK_RESOURCE_CLASS_OCF
Definition: services.h:43
services__ocf_agent_exists
gboolean services__ocf_agent_exists(const char *provider, const char *agent)
Definition: services_linux.c:1173
svc_action_private_s::args
char * args[MAX_ARGC]
Definition: services_private.h:21
pcmk_ra_cap_provider
@ pcmk_ra_cap_provider
Definition: util.h:145
CRM_CHECK
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:157
SVC_ACTION_NON_BLOCKED
@ SVC_ACTION_NON_BLOCKED
Definition: services.h:147
OCF_ROOT_DIR
#define OCF_ROOT_DIR
Definition: services.h:30
type
enum crm_ais_msg_types type
Definition: internal.h:5
crm_err
#define crm_err(fmt, args...)
Definition: logging.h:241
crm_trace
#define crm_trace(fmt, args...)
Definition: logging.h:247
safe_str_eq
#define safe_str_eq(a, b)
Definition: util.h:61
resources_os_list_ocf_agents
GList * resources_os_list_ocf_agents(const char *provider)
Definition: services_linux.c:1146
crm_warn
#define crm_warn(fmt, args...)
Definition: logging.h:242
services_alert_async
gboolean services_alert_async(svc_action_t *action, void(*cb)(svc_action_t *op))
Execute an alert agent action.
Definition: services.c:390
services_os_get_directory_list
GList * services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
Definition: services_linux.c:1085
services_action_kick
gboolean services_action_kick(const char *name, const char *action, guint interval_ms)
Definition: services.c:610
XML_ATTR_CRM_VERSION
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:79
resources_action_create
svc_action_t * resources_action_create(const char *name, const char *standard, const char *provider, const char *agent, const char *action, guint interval_ms, int timeout, GHashTable *params, enum svc_action_flags flags)
Create a new resource action.
Definition: services.c:161
svc_action_private_s::exec
char * exec
Definition: services_private.h:20
svc_action_s::id
char * id
Definition: services.h:152
PCMK_RESOURCE_CLASS_SERVICE
#define PCMK_RESOURCE_CLASS_SERVICE
Definition: services.h:44
is_op_blocked
gboolean is_op_blocked(const char *rsc)
Definition: services.c:774
svc_action_s::stderr_data
char * stderr_data
Definition: services.h:176
services_alert_create
svc_action_t * services_alert_create(const char *id, const char *exec, int timeout, GHashTable *params, int sequence, void *cb_data)
Create an alert agent action.
Definition: services.c:342
svc_action_s::cb_data
void * cb_data
Definition: services.h:185
upstart_job_listall
GList * upstart_job_listall(void)
Definition: upstart.c:149
mainloop.h
Wrappers for and extensions to glib mainloop.
upstart_job_exec
gboolean upstart_job_exec(svc_action_t *op)
Definition: upstart.c:417
NAGIOS_PLUGIN_DIR
#define NAGIOS_PLUGIN_DIR
Definition: config.h:493
svc_action_s::params
GHashTable * params
Definition: services.h:162
services_os_action_execute
gboolean services_os_action_execute(svc_action_t *op)
Definition: services_linux.c:884
PCMK_RESOURCE_CLASS_NAGIOS
#define PCMK_RESOURCE_CLASS_NAGIOS
Definition: services.h:48
pcmk_ra_cap_params
@ pcmk_ra_cap_params
Definition: util.h:147
systemd.h
services__list_lsb_agents
GList * services__list_lsb_agents(void)
Definition: services_lsb.c:243
CRM_META
#define CRM_META
Definition: crm.h:71
svc_action_s
Definition: services.h:151
services_action_user
int services_action_user(svc_action_t *op, const char *user)
Set the user and group that an action will execute as.
Definition: services.c:372
crm_info
#define crm_info(fmt, args...)
Definition: logging.h:244
services_action_async_fork_notify
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:733
svc_action_s::timeout
int timeout
Definition: services.h:161
PCMK_RESOURCE_CLASS_UPSTART
#define PCMK_RESOURCE_CLASS_UPSTART
Definition: services.h:47
resources_find_service_class
const char * resources_find_service_class(const char *agent)
Find first service class that can provide a specified agent.
Definition: services.c:65
resources_os_list_ocf_providers
GList * resources_os_list_ocf_providers(void)
Definition: services_linux.c:1140
CRM_OP_FMT
#define CRM_OP_FMT
Definition: crm_internal.h:133
svc_action_private_s::stdout_gsource
mainloop_io_t * stdout_gsource
Definition: services_private.h:34
resources_list_standards
GList * resources_list_standards(void)
Definition: services.c:962
crm_strdup_printf
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
services__get_lsb_metadata
int services__get_lsb_metadata(const char *type, char **output)
Definition: services_lsb.c:100
svc_action_s::stdout_data
char * stdout_data
Definition: services.h:177
DIMOF
#define DIMOF(a)
Definition: crm.h:57
crm_debug
#define crm_debug(fmt, args...)
Definition: logging.h:246
systemd_unit_exists
gboolean systemd_unit_exists(const char *name)
Definition: systemd.c:461
resources_os_list_nagios_agents
G_GNUC_INTERNAL GList * resources_os_list_nagios_agents(void)
svc_action_s::pid
int pid
Definition: services.h:168
cancel_recurring_action
gboolean cancel_recurring_action(svc_action_t *op)
Definition: services.c:517
svc_action_private_s::fork_callback
void(* fork_callback)(svc_action_t *op)
Definition: services_private.h:28
svc_action_private_s::repeat_timer
guint repeat_timer
Definition: services_private.h:26
pcmk_ra_cap_status
@ pcmk_ra_cap_status
Definition: util.h:146
upstart.h
NAGIOS_METADATA_DIR
#define NAGIOS_METADATA_DIR
Definition: config.h:490
services_action_free
void services_action_free(svc_action_t *op)
Definition: services.c:465
crm_user_lookup
int crm_user_lookup(const char *name, uid_t *uid, gid_t *gid)
Definition: utils.c:402
services_action_async
gboolean services_action_async(svc_action_t *op, void(*action_callback)(svc_action_t *))
Definition: services.c:765
svc_action_private_s::callback
void(* callback)(svc_action_t *op)
Definition: services_private.h:27
services_lsb.h
systemd_unit_listall
GList * systemd_unit_listall(void)
Definition: systemd.c:364
mainloop_del_fd
void mainloop_del_fd(mainloop_io_t *client)
Definition: mainloop.c:985
services_action_cleanup
void services_action_cleanup(svc_action_t *op)
Definition: services.c:426
services_add_inflight_op
void services_add_inflight_op(svc_action_t *op)
Definition: services.c:701
stonith-ng.h
Fencing aka. STONITH.
svc_action_s::interval_ms
guint interval_ms
Definition: services.h:155
services.h
Services API.
svc_action_s::cancel
int cancel
Definition: services.h:169
services_action_sync
gboolean services_action_sync(svc_action_t *op)
Definition: services.c:921
services_untrack_op
void services_untrack_op(svc_action_t *op)
Definition: services.c:722
svc_action_flags
svc_action_flags
Definition: services.h:144
CRM_ASSERT
#define CRM_ASSERT(expr)
Definition: results.h:42
svc_action_s::sequence
int sequence
Definition: services.h:171
services_action_cancel
gboolean services_action_cancel(const char *name, const char *action, guint interval_ms)
Cancel a recurring action.
Definition: services.c:543
recurring_action_timer
gboolean recurring_action_timer(gpointer data)
Definition: services_linux.c:480
svc_action_s::status
int status
Definition: services.h:170
systemd_unit_exec
gboolean systemd_unit_exec(svc_action_t *op)
Definition: systemd.c:800
svc_action_s::agent
char * agent
Definition: services.h:159
generate_op_key
char * generate_op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key.
Definition: operations.c:39
svc_action_private_s::stderr_gsource
mainloop_io_t * stderr_gsource
Definition: services_private.h:31
svc_action_s::synchronous
int synchronous
Definition: services.h:173
pcmk_get_ra_caps
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
Definition: agents.c:29
svc_action_s::rc
int rc
Definition: services.h:167
operation_finalize
gboolean operation_finalize(svc_action_t *op)
Definition: services_linux.c:499
PCMK_RESOURCE_CLASS_LSB
#define PCMK_RESOURCE_CLASS_LSB
Definition: services.h:45
get_directory_list
GList * get_directory_list(const char *root, gboolean files, gboolean executable)
Get a list of files or directories in a given path.
Definition: services.c:956
svc_action_s::standard
char * standard
Definition: services.h:157
crm_internal.h
services__lsb_agent_exists
bool services__lsb_agent_exists(const char *agent)
Definition: services_lsb.c:256
crm.h
A dumping ground.
pcmk_ok
#define pcmk_ok
Definition: results.h:57
svc_action_s::rsc
char * rsc
Definition: services.h:153