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