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 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 (is_not_set(op->flags, SVC_ACTION_NON_BLOCKED)
754  && op->rsc && is_op_blocked(op->rsc)) {
755  blocked_ops = g_list_append(blocked_ops, op);
756  return TRUE;
757  }
758 
759  return action_exec_helper(op);
760 }
761 
762 gboolean
764  void (*action_callback) (svc_action_t *))
765 {
766  return services_action_async_fork_notify(op, action_callback, NULL);
767 }
768 
769 static gboolean processing_blocked_ops = FALSE;
770 
771 gboolean
772 is_op_blocked(const char *rsc)
773 {
774  GList *gIter = NULL;
775  svc_action_t *op = NULL;
776 
777  for (gIter = inflight_ops; gIter != NULL; gIter = gIter->next) {
778  op = gIter->data;
779  if (safe_str_eq(op->rsc, rsc)) {
780  return TRUE;
781  }
782  }
783 
784  return FALSE;
785 }
786 
787 static void
788 handle_blocked_ops(void)
789 {
790  GList *executed_ops = NULL;
791  GList *gIter = NULL;
792  svc_action_t *op = NULL;
793  gboolean res = FALSE;
794 
795  if (processing_blocked_ops) {
796  /* avoid nested calling of this function */
797  return;
798  }
799 
800  processing_blocked_ops = TRUE;
801 
802  /* n^2 operation here, but blocked ops are incredibly rare. this list
803  * will be empty 99% of the time. */
804  for (gIter = blocked_ops; gIter != NULL; gIter = gIter->next) {
805  op = gIter->data;
806  if (is_op_blocked(op->rsc)) {
807  continue;
808  }
809  executed_ops = g_list_append(executed_ops, op);
810  res = action_exec_helper(op);
811  if (res == FALSE) {
813  /* this can cause this function to be called recursively
814  * which is why we have processing_blocked_ops static variable */
815  operation_finalize(op);
816  }
817  }
818 
819  for (gIter = executed_ops; gIter != NULL; gIter = gIter->next) {
820  op = gIter->data;
821  blocked_ops = g_list_remove(blocked_ops, op);
822  }
823  g_list_free(executed_ops);
824 
825  processing_blocked_ops = FALSE;
826 }
827 
828 #if SUPPORT_NAGIOS
829 static int
830 nagios_get_metadata(const char *type, char **output)
831 {
832  int rc = pcmk_ok;
833  FILE *file_strm = NULL;
834  int start = 0, length = 0, read_len = 0;
835  char *metadata_file = crm_strdup_printf("%s/%s.xml",
837 
838  file_strm = fopen(metadata_file, "r");
839  if (file_strm == NULL) {
840  crm_err("Metadata file %s does not exist", metadata_file);
841  free(metadata_file);
842  return -EIO;
843  }
844 
845  /* see how big the file is */
846  start = ftell(file_strm);
847  fseek(file_strm, 0L, SEEK_END);
848  length = ftell(file_strm);
849  fseek(file_strm, 0L, start);
850 
851  CRM_ASSERT(length >= 0);
852  CRM_ASSERT(start == ftell(file_strm));
853 
854  if (length <= 0) {
855  crm_info("%s was not valid", metadata_file);
856  free(*output);
857  *output = NULL;
858  rc = -EIO;
859 
860  } else {
861  crm_trace("Reading %d bytes from file", length);
862  *output = calloc(1, (length + 1));
863  read_len = fread(*output, 1, length, file_strm);
864  if (read_len != length) {
865  crm_err("Calculated and read bytes differ: %d vs. %d",
866  length, read_len);
867  free(*output);
868  *output = NULL;
869  rc = -EIO;
870  }
871  }
872 
873  fclose(file_strm);
874  free(metadata_file);
875  return rc;
876 }
877 #endif
878 
879 static gboolean
880 action_get_metadata(svc_action_t *op)
881 {
882  const char *class = op->standard;
883 
884  if (op->agent == NULL) {
885  crm_err("meta-data requested without specifying agent");
886  return FALSE;
887  }
888 
889  if (class == NULL) {
890  crm_err("meta-data requested for agent %s without specifying class",
891  op->agent);
892  return FALSE;
893  }
894 
895  if (!strcmp(class, PCMK_RESOURCE_CLASS_SERVICE)) {
896  class = resources_find_service_class(op->agent);
897  }
898 
899  if (class == NULL) {
900  crm_err("meta-data requested for %s, but could not determine class",
901  op->agent);
902  return FALSE;
903  }
904 
905  if (safe_str_eq(class, PCMK_RESOURCE_CLASS_LSB)) {
906  return (services__get_lsb_metadata(op->agent, &op->stdout_data) >= 0);
907  }
908 
909 #if SUPPORT_NAGIOS
911  return (nagios_get_metadata(op->agent, &op->stdout_data) >= 0);
912  }
913 #endif
914 
915  return action_exec_helper(op);
916 }
917 
918 gboolean
920 {
921  gboolean rc = TRUE;
922 
923  if (op == NULL) {
924  crm_trace("No operation to execute");
925  return FALSE;
926  }
927 
928  op->synchronous = true;
929 
930  if (safe_str_eq(op->action, "meta-data")) {
931  /* Synchronous meta-data operations are handled specially. Since most
932  * resource classes don't provide any meta-data, it has to be
933  * synthesized from available information about the agent.
934  *
935  * services_action_async() doesn't treat meta-data actions specially, so
936  * it will result in an error for classes that don't support the action.
937  */
938  rc = action_get_metadata(op);
939  } else {
940  rc = action_exec_helper(op);
941  }
942  crm_trace(" > " CRM_OP_FMT ": %s = %d",
943  op->rsc, op->action, op->interval_ms, op->opaque->exec, op->rc);
944  if (op->stdout_data) {
945  crm_trace(" > stdout: %s", op->stdout_data);
946  }
947  if (op->stderr_data) {
948  crm_trace(" > stderr: %s", op->stderr_data);
949  }
950  return rc;
951 }
952 
953 GList *
954 get_directory_list(const char *root, gboolean files, gboolean executable)
955 {
956  return services_os_get_directory_list(root, files, executable);
957 }
958 
959 GList *
961 {
962  GList *standards = NULL;
963  GList *agents = NULL;
964 
965  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_OCF));
966  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_LSB));
967  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_SERVICE));
968 
969 #if SUPPORT_SYSTEMD
970  agents = systemd_unit_listall();
971  if (agents) {
972  standards = g_list_append(standards,
974  g_list_free_full(agents, free);
975  }
976 #endif
977 
978 #if SUPPORT_UPSTART
979  agents = upstart_job_listall();
980  if (agents) {
981  standards = g_list_append(standards,
983  g_list_free_full(agents, free);
984  }
985 #endif
986 
987 #if SUPPORT_NAGIOS
989  if (agents) {
990  standards = g_list_append(standards,
992  g_list_free_full(agents, free);
993  }
994 #endif
995 
996  return standards;
997 }
998 
999 GList *
1000 resources_list_providers(const char *standard)
1001 {
1002  if (is_set(pcmk_get_ra_caps(standard), pcmk_ra_cap_provider)) {
1004  }
1005 
1006  return NULL;
1007 }
1008 
1009 GList *
1010 resources_list_agents(const char *standard, const char *provider)
1011 {
1012  if ((standard == NULL)
1013  || (strcasecmp(standard, PCMK_RESOURCE_CLASS_SERVICE) == 0)) {
1014 
1015  GList *tmp1;
1016  GList *tmp2;
1017  GList *result = services__list_lsb_agents();
1018 
1019  if (standard == NULL) {
1020  tmp1 = result;
1021  tmp2 = resources_os_list_ocf_agents(NULL);
1022  if (tmp2) {
1023  result = g_list_concat(tmp1, tmp2);
1024  }
1025  }
1026 #if SUPPORT_SYSTEMD
1027  tmp1 = result;
1028  tmp2 = systemd_unit_listall();
1029  if (tmp2) {
1030  result = g_list_concat(tmp1, tmp2);
1031  }
1032 #endif
1033 
1034 #if SUPPORT_UPSTART
1035  tmp1 = result;
1036  tmp2 = upstart_job_listall();
1037  if (tmp2) {
1038  result = g_list_concat(tmp1, tmp2);
1039  }
1040 #endif
1041 
1042  return result;
1043 
1044  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_OCF) == 0) {
1045  return resources_os_list_ocf_agents(provider);
1046  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_LSB) == 0) {
1047  return services__list_lsb_agents();
1048 #if SUPPORT_SYSTEMD
1049  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_SYSTEMD) == 0) {
1050  return systemd_unit_listall();
1051 #endif
1052 #if SUPPORT_UPSTART
1053  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_UPSTART) == 0) {
1054  return upstart_job_listall();
1055 #endif
1056 #if SUPPORT_NAGIOS
1057  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_NAGIOS) == 0) {
1059 #endif
1060  }
1061 
1062  return NULL;
1063 }
1064 
1065 gboolean
1066 resources_agent_exists(const char *standard, const char *provider, const char *agent)
1067 {
1068  GList *standards = NULL;
1069  GList *providers = NULL;
1070  GListPtr iter = NULL;
1071  gboolean rc = FALSE;
1072  gboolean has_providers = FALSE;
1073 
1074  standards = resources_list_standards();
1075  for (iter = standards; iter != NULL; iter = iter->next) {
1076  if (crm_str_eq(iter->data, standard, TRUE)) {
1077  rc = TRUE;
1078  break;
1079  }
1080  }
1081 
1082  if (rc == FALSE) {
1083  goto done;
1084  }
1085 
1086  rc = FALSE;
1087 
1088  has_providers = is_set(pcmk_get_ra_caps(standard), pcmk_ra_cap_provider);
1089  if (has_providers == TRUE && provider != NULL) {
1090  providers = resources_list_providers(standard);
1091  for (iter = providers; iter != NULL; iter = iter->next) {
1092  if (crm_str_eq(iter->data, provider, TRUE)) {
1093  rc = TRUE;
1094  break;
1095  }
1096  }
1097  } else if (has_providers == FALSE && provider == NULL) {
1098  rc = TRUE;
1099  }
1100 
1101  if (rc == FALSE) {
1102  goto done;
1103  }
1104 
1105  if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_SERVICE)) {
1106  if (services__lsb_agent_exists(agent)) {
1107  rc = TRUE;
1108 #if SUPPORT_SYSTEMD
1109  } else if (systemd_unit_exists(agent)) {
1110  rc = TRUE;
1111 #endif
1112 
1113 #if SUPPORT_UPSTART
1114  } else if (upstart_job_exists(agent)) {
1115  rc = TRUE;
1116 #endif
1117  } else {
1118  rc = FALSE;
1119  }
1120 
1121  } else if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_OCF)) {
1122  rc = services__ocf_agent_exists(provider, agent);
1123 
1124  } else if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_LSB)) {
1125  rc = services__lsb_agent_exists(agent);
1126 
1127 #if SUPPORT_SYSTEMD
1128  } else if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_SYSTEMD)) {
1129  rc = systemd_unit_exists(agent);
1130 #endif
1131 
1132 #if SUPPORT_UPSTART
1133  } else if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_UPSTART)) {
1134  rc = upstart_job_exists(agent);
1135 #endif
1136 
1137 #if SUPPORT_NAGIOS
1138  } else if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_NAGIOS)) {
1139  rc = services__nagios_agent_exists(agent);
1140 #endif
1141 
1142  } else {
1143  rc = FALSE;
1144  }
1145 
1146 done:
1147  g_list_free(standards);
1148  g_list_free(providers);
1149  return rc;
1150 }
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:1000
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:1010
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:302
resources_agent_exists
gboolean resources_agent_exists(const char *standard, const char *provider, const char *agent)
Definition: services.c:1066
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:1038
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:1011
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:388
services_os_get_directory_list
GList * services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
Definition: services_linux.c:950
services_action_kick
gboolean services_action_kick(const char *name, const char *action, guint interval_ms)
Definition: services.c:608
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:159
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:772
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:340
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:693
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:370
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:731
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:63
resources_os_list_ocf_providers
GList * resources_os_list_ocf_providers(void)
Definition: services_linux.c:1005
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:960
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:515
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:463
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:763
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:424
services_add_inflight_op
void services_add_inflight_op(svc_action_t *op)
Definition: services.c:699
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:919
services_untrack_op
void services_untrack_op(svc_action_t *op)
Definition: services.c:720
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:541
recurring_action_timer
gboolean recurring_action_timer(gpointer data)
Definition: services_linux.c:260
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:279
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:954
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