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