pacemaker  1.1.17-b36b869ca8
Scalable High-Availability cluster resource manager
services.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2010-2016 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 <sys/stat.h>
16 #include <stdio.h>
17 
18 #include <errno.h>
19 #include <unistd.h>
20 #include <dirent.h>
21 #include <fcntl.h>
22 
23 #include <crm/crm.h>
24 #include <crm/common/mainloop.h>
25 #include <crm/services.h>
26 #include <crm/msg_xml.h>
27 #include "services_private.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 
52 services_action_create(const char *name, const char *action, int interval, int timeout)
53 {
54  return resources_action_create(name, PCMK_RESOURCE_CLASS_LSB, NULL, name,
55  action, interval, timeout, NULL, 0);
56 }
57 
58 const char *
59 resources_find_service_class(const char *agent)
60 {
61  /* Priority is:
62  * - lsb
63  * - systemd
64  * - upstart
65  */
66  int rc = 0;
67  struct stat st;
68  char *path = NULL;
69 
70 #ifdef LSB_ROOT_DIR
71  rc = asprintf(&path, "%s/%s", LSB_ROOT_DIR, agent);
72  if (rc > 0 && stat(path, &st) == 0) {
73  free(path);
75  }
76  free(path);
77 #endif
78 
79 #if SUPPORT_SYSTEMD
80  if (systemd_unit_exists(agent)) {
82  }
83 #endif
84 
85 #if SUPPORT_UPSTART
86  if (upstart_job_exists(agent)) {
88  }
89 #endif
90  return NULL;
91 }
92 
93 static inline void
94 init_recurring_actions(void)
95 {
96  if (recurring_actions == NULL) {
97  recurring_actions = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
98  NULL);
99  }
100 }
101 
110 static inline gboolean
111 inflight_systemd_or_upstart(svc_action_t *op)
112 {
115  && (g_list_find(inflight_ops, op) != NULL);
116 }
117 
130 static char *
131 expand_resource_class(const char *rsc, const char *standard, const char *agent)
132 {
133  char *expanded_class = NULL;
134 
135  if (strcasecmp(standard, PCMK_RESOURCE_CLASS_SERVICE) == 0) {
136  const char *found_class = resources_find_service_class(agent);
137 
138  if (found_class) {
139  crm_debug("Found %s agent %s for %s", found_class, agent, rsc);
140  expanded_class = strdup(found_class);
141  } else {
142  crm_info("Assuming resource class lsb for agent %s for %s",
143  agent, rsc);
144  expanded_class = strdup(PCMK_RESOURCE_CLASS_LSB);
145  }
146  } else {
147  expanded_class = strdup(standard);
148  }
149  CRM_ASSERT(expanded_class);
150  return expanded_class;
151 }
152 
153 svc_action_t *
154 resources_action_create(const char *name, const char *standard, const char *provider,
155  const char *agent, const char *action, int interval, int timeout,
156  GHashTable * params, enum svc_action_flags flags)
157 {
158  svc_action_t *op = NULL;
159 
160  /*
161  * Do some up front sanity checks before we go off and
162  * build the svc_action_t instance.
163  */
164 
165  if (crm_strlen_zero(name)) {
166  crm_err("Cannot create operation without resource name");
167  goto return_error;
168  }
169 
170  if (crm_strlen_zero(standard)) {
171  crm_err("Cannot create operation for %s without resource class", name);
172  goto return_error;
173  }
174 
175  if (!strcasecmp(standard, PCMK_RESOURCE_CLASS_OCF)
176  && crm_strlen_zero(provider)) {
177  crm_err("Cannot create OCF operation for %s without provider", name);
178  goto return_error;
179  }
180 
181  if (crm_strlen_zero(agent)) {
182  crm_err("Cannot create operation for %s without agent name", name);
183  goto return_error;
184  }
185 
186  if (crm_strlen_zero(action)) {
187  crm_err("Cannot create operation for %s without operation name", name);
188  goto return_error;
189  }
190 
191  /*
192  * Sanity checks passed, proceed!
193  */
194 
195  op = calloc(1, sizeof(svc_action_t));
196  op->opaque = calloc(1, sizeof(svc_action_private_t));
197  op->rsc = strdup(name);
198  op->interval = interval;
199  op->timeout = timeout;
200  op->standard = expand_resource_class(name, standard, agent);
201  op->agent = strdup(agent);
202  op->sequence = ++operations;
203  op->flags = flags;
204  op->id = generate_op_key(name, action, interval);
205 
206  if (safe_str_eq(action, "monitor") && (
209 #endif
211  action = "status";
212  }
213  op->action = strdup(action);
214 
215  if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_OCF) == 0) {
216  op->provider = strdup(provider);
217  op->params = params;
218  params = NULL;
219 
220  if (asprintf(&op->opaque->exec, "%s/resource.d/%s/%s", OCF_ROOT_DIR, provider, agent) == -1) {
221  crm_err("Internal error: cannot create agent path");
222  goto return_error;
223  }
224  op->opaque->args[0] = strdup(op->opaque->exec);
225  op->opaque->args[1] = strdup(action);
226 
227  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_LSB) == 0) {
228  if (op->agent[0] == '/') {
229  /* if given an absolute path, use that instead
230  * of tacking on the LSB_ROOT_DIR path to the front */
231  op->opaque->exec = strdup(op->agent);
232  } else if (asprintf(&op->opaque->exec, "%s/%s", LSB_ROOT_DIR, op->agent) == -1) {
233  crm_err("Internal error: cannot create agent path");
234  goto return_error;
235  }
236  op->opaque->args[0] = strdup(op->opaque->exec);
237  op->opaque->args[1] = strdup(op->action);
238  op->opaque->args[2] = NULL;
239 #if SUPPORT_HEARTBEAT
240  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_HB) == 0) {
241  int index;
242  int param_num;
243  char buf_tmp[20];
244  void *value_tmp;
245 
246  if (op->agent[0] == '/') {
247  /* if given an absolute path, use that instead
248  * of tacking on the HB_RA_DIR path to the front */
249  op->opaque->exec = strdup(op->agent);
250  } else if (asprintf(&op->opaque->exec, "%s/%s", HB_RA_DIR, op->agent) == -1) {
251  crm_err("Internal error: cannot create agent path");
252  goto return_error;
253  }
254  op->opaque->args[0] = strdup(op->opaque->exec);
255 
256  /* The "heartbeat" agent class only has positional arguments,
257  * which we keyed by their decimal position number. */
258  param_num = 1;
259  for (index = 1; index <= MAX_ARGC - 3; index++ ) {
260  snprintf(buf_tmp, sizeof(buf_tmp), "%d", index);
261  value_tmp = g_hash_table_lookup(params, buf_tmp);
262  if (value_tmp == NULL) {
263  /* maybe: strdup("") ??
264  * But the old lrmd did simply continue as well. */
265  continue;
266  }
267  op->opaque->args[param_num++] = strdup(value_tmp);
268  }
269 
270  /* Add operation code as the last argument, */
271  /* and the teminating NULL pointer */
272  op->opaque->args[param_num++] = strdup(op->action);
273  op->opaque->args[param_num] = NULL;
274 #endif
275 #if SUPPORT_SYSTEMD
276  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_SYSTEMD) == 0) {
277  op->opaque->exec = strdup("systemd-dbus");
278 #endif
279 #if SUPPORT_UPSTART
280  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_UPSTART) == 0) {
281  op->opaque->exec = strdup("upstart-dbus");
282 #endif
283 #if SUPPORT_NAGIOS
284  } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_NAGIOS) == 0) {
285  int index = 0;
286 
287  if (op->agent[0] == '/') {
288  /* if given an absolute path, use that instead
289  * of tacking on the NAGIOS_PLUGIN_DIR path to the front */
290  op->opaque->exec = strdup(op->agent);
291 
292  } else if (asprintf(&op->opaque->exec, "%s/%s", NAGIOS_PLUGIN_DIR, op->agent) == -1) {
293  crm_err("Internal error: cannot create agent path");
294  goto return_error;
295  }
296 
297  op->opaque->args[0] = strdup(op->opaque->exec);
298  index = 1;
299 
300  if (safe_str_eq(op->action, "monitor") && op->interval == 0) {
301  /* Invoke --version for a nagios probe */
302  op->opaque->args[index] = strdup("--version");
303  index++;
304 
305  } else if (params) {
306  GHashTableIter iter;
307  char *key = NULL;
308  char *value = NULL;
309  static int args_size = sizeof(op->opaque->args) / sizeof(char *);
310 
311  g_hash_table_iter_init(&iter, params);
312 
313  while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value) &&
314  index <= args_size - 3) {
315  int len = 3;
316  char *long_opt = NULL;
317 
318  if (safe_str_eq(key, XML_ATTR_CRM_VERSION) || strstr(key, CRM_META "_")) {
319  continue;
320  }
321 
322  len += strlen(key);
323  long_opt = calloc(1, len);
324  sprintf(long_opt, "--%s", key);
325  long_opt[len - 1] = 0;
326 
327  op->opaque->args[index] = long_opt;
328  op->opaque->args[index + 1] = strdup(value);
329  index += 2;
330  }
331  }
332  op->opaque->args[index] = NULL;
333 #endif
334  } else {
335  crm_err("Unknown resource standard: %s", op->standard);
337  op = NULL;
338  }
339 
340  if(params) {
341  g_hash_table_destroy(params);
342  }
343  return op;
344 
345  return_error:
346  if(params) {
347  g_hash_table_destroy(params);
348  }
350 
351  return NULL;
352 }
353 
354 svc_action_t *
355 services_action_create_generic(const char *exec, const char *args[])
356 {
357  svc_action_t *op;
358  unsigned int cur_arg;
359 
360  op = calloc(1, sizeof(*op));
361  op->opaque = calloc(1, sizeof(svc_action_private_t));
362 
363  op->opaque->exec = strdup(exec);
364  op->opaque->args[0] = strdup(exec);
365 
366  for (cur_arg = 1; args && args[cur_arg - 1]; cur_arg++) {
367  op->opaque->args[cur_arg] = strdup(args[cur_arg - 1]);
368 
369  if (cur_arg == DIMOF(op->opaque->args) - 1) {
370  crm_err("svc_action_t args list not long enough for '%s' execution request.", exec);
371  break;
372  }
373  }
374 
375  return op;
376 }
377 
378 #if SUPPORT_DBUS
379 
386 void
387 services_set_op_pending(svc_action_t *op, DBusPendingCall *pending)
388 {
389  if (op->opaque->pending && (op->opaque->pending != pending)) {
390  if (pending) {
391  crm_info("Lost pending %s DBus call (%p)", op->id, op->opaque->pending);
392  } else {
393  crm_trace("Done with pending %s DBus call (%p)", op->id, op->opaque->pending);
394  }
395  dbus_pending_call_unref(op->opaque->pending);
396  }
397  op->opaque->pending = pending;
398  if (pending) {
399  crm_trace("Updated pending %s DBus call (%p)", op->id, pending);
400  } else {
401  crm_trace("Cleared pending %s DBus call", op->id);
402  }
403 }
404 #endif
405 
406 void
408 {
409  if(op->opaque == NULL) {
410  return;
411  }
412 
413 #if SUPPORT_DBUS
414  if(op->opaque->timerid != 0) {
415  crm_trace("Removing timer for call %s to %s", op->action, op->rsc);
416  g_source_remove(op->opaque->timerid);
417  op->opaque->timerid = 0;
418  }
419 
420  if(op->opaque->pending) {
421  crm_trace("Cleaning up pending dbus call %p %s for %s", op->opaque->pending, op->action, op->rsc);
422  if(dbus_pending_call_get_completed(op->opaque->pending)) {
423  crm_warn("Pending dbus call %s for %s did not complete", op->action, op->rsc);
424  }
425  dbus_pending_call_cancel(op->opaque->pending);
426  dbus_pending_call_unref(op->opaque->pending);
427  op->opaque->pending = NULL;
428  }
429 #endif
430 
431  if (op->opaque->stderr_gsource) {
433  op->opaque->stderr_gsource = NULL;
434  }
435 
436  if (op->opaque->stdout_gsource) {
438  op->opaque->stdout_gsource = NULL;
439  }
440 }
441 
442 void
444 {
445  unsigned int i;
446 
447  if (op == NULL) {
448  return;
449  }
450 
451  /* The operation should be removed from all tracking lists by this point.
452  * If it's not, we have a bug somewhere, so bail. That may lead to a
453  * memory leak, but it's better than a use-after-free segmentation fault.
454  */
455  CRM_CHECK(g_list_find(inflight_ops, op) == NULL, return);
456  CRM_CHECK(g_list_find(blocked_ops, op) == NULL, return);
457  CRM_CHECK((recurring_actions == NULL)
458  || (g_hash_table_lookup(recurring_actions, op->id) == NULL),
459  return);
460 
462 
463  if (op->opaque->repeat_timer) {
464  g_source_remove(op->opaque->repeat_timer);
465  op->opaque->repeat_timer = 0;
466  }
467 
468  free(op->id);
469  free(op->opaque->exec);
470 
471  for (i = 0; i < DIMOF(op->opaque->args); i++) {
472  free(op->opaque->args[i]);
473  }
474 
475  free(op->opaque);
476  free(op->rsc);
477  free(op->action);
478 
479  free(op->standard);
480  free(op->agent);
481  free(op->provider);
482 
483  free(op->stdout_data);
484  free(op->stderr_data);
485 
486  if (op->params) {
487  g_hash_table_destroy(op->params);
488  op->params = NULL;
489  }
490 
491  free(op);
492 }
493 
494 gboolean
496 {
497  crm_info("Cancelling %s operation %s", op->standard, op->id);
498 
499  if (recurring_actions) {
500  g_hash_table_remove(recurring_actions, op->id);
501  }
502 
503  if (op->opaque->repeat_timer) {
504  g_source_remove(op->opaque->repeat_timer);
505  op->opaque->repeat_timer = 0;
506  }
507 
508  return TRUE;
509 }
510 
520 gboolean
521 services_action_cancel(const char *name, const char *action, int interval)
522 {
523  gboolean cancelled = FALSE;
524  char *id = generate_op_key(name, action, interval);
525  svc_action_t *op = NULL;
526 
527  /* We can only cancel a recurring action */
528  init_recurring_actions();
529  op = g_hash_table_lookup(recurring_actions, id);
530  if (op == NULL) {
531  goto done;
532  }
533 
534  /* Tell operation_finalize() not to reschedule the operation */
535  op->cancel = TRUE;
536 
537  /* Stop tracking it as a recurring operation, and stop its timer */
539 
540  /* If the op has a PID, it's an in-flight child process, so kill it.
541  *
542  * Whether the kill succeeds or fails, the main loop will send the op to
543  * operation_finished() (and thus operation_finalize()) when the process
544  * goes away.
545  */
546  if (op->pid != 0) {
547  crm_info("Terminating in-flight op %s (pid %d) early because it was cancelled",
548  id, op->pid);
549  cancelled = mainloop_child_kill(op->pid);
550  if (cancelled == FALSE) {
551  crm_err("Termination of %s (pid %d) failed", id, op->pid);
552  }
553  goto done;
554  }
555 
556  /* In-flight systemd and upstart ops don't have a pid. The relevant handlers
557  * will call operation_finalize() when the operation completes.
558  * @TODO: Can we request early termination, maybe using
559  * dbus_pending_call_cancel()?
560  */
561  if (inflight_systemd_or_upstart(op)) {
562  crm_info("Will cancel %s op %s when in-flight instance completes",
563  op->standard, op->id);
564  cancelled = FALSE;
565  goto done;
566  }
567 
568  /* Otherwise, operation is not in-flight, just report as cancelled */
570  if (op->opaque->callback) {
571  op->opaque->callback(op);
572  }
573 
574  blocked_ops = g_list_remove(blocked_ops, op);
576  cancelled = TRUE;
577 
578 done:
579  free(id);
580  return cancelled;
581 }
582 
583 gboolean
584 services_action_kick(const char *name, const char *action, int interval /* ms */)
585 {
586  svc_action_t * op = NULL;
587  char *id = generate_op_key(name, action, interval);
588 
589  init_recurring_actions();
590  op = g_hash_table_lookup(recurring_actions, id);
591  free(id);
592 
593  if (op == NULL) {
594  return FALSE;
595  }
596 
597 
598  if (op->pid || inflight_systemd_or_upstart(op)) {
599  return TRUE;
600  } else {
601  if (op->opaque->repeat_timer) {
602  g_source_remove(op->opaque->repeat_timer);
603  op->opaque->repeat_timer = 0;
604  }
606  return TRUE;
607  }
608 
609 }
610 
619 static gboolean
620 handle_duplicate_recurring(svc_action_t * op)
621 {
622  svc_action_t * dup = NULL;
623 
624  /* check for duplicates */
625  dup = g_hash_table_lookup(recurring_actions, op->id);
626 
627  if (dup && (dup != op)) {
628  /* update user data */
629  if (op->opaque->callback) {
630  dup->opaque->callback = op->opaque->callback;
631  dup->cb_data = op->cb_data;
632  op->cb_data = NULL;
633  }
634  /* immediately execute the next interval */
635  if (dup->pid != 0) {
636  if (op->opaque->repeat_timer) {
637  g_source_remove(op->opaque->repeat_timer);
638  op->opaque->repeat_timer = 0;
639  }
641  }
642  /* free the duplicate */
644  return TRUE;
645  }
646 
647  return FALSE;
648 }
649 
650 inline static gboolean
651 action_exec_helper(svc_action_t * op)
652 {
653  /* Whether a/synchronous must be decided (op->synchronous) beforehand. */
654  if (op->standard
655  && (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_UPSTART) == 0)) {
656 #if SUPPORT_UPSTART
657  return upstart_job_exec(op);
658 #endif
659  } else if (op->standard && strcasecmp(op->standard,
661 #if SUPPORT_SYSTEMD
662  return systemd_unit_exec(op);
663 #endif
664  } else {
665  return services_os_action_execute(op);
666  }
667  /* The 'op' has probably been freed if the execution functions return TRUE
668  for the asynchronous 'op'. */
669  /* Avoid using the 'op' in here. */
670 
671  return FALSE;
672 }
673 
674 void
676 {
677  if (op == NULL) {
678  return;
679  }
680 
681  CRM_ASSERT(op->synchronous == FALSE);
682 
683  /* keep track of ops that are in-flight to avoid collisions in the same namespace */
684  if (op->rsc) {
685  inflight_ops = g_list_append(inflight_ops, op);
686  }
687 }
688 
695 void
697 {
698  /* Op is no longer in-flight or blocked */
699  inflight_ops = g_list_remove(inflight_ops, op);
700  blocked_ops = g_list_remove(blocked_ops, op);
701 
702  /* Op is no longer blocking other ops, so check if any need to run */
703  handle_blocked_ops();
704 }
705 
706 gboolean
707 services_action_async(svc_action_t * op, void (*action_callback) (svc_action_t *))
708 {
709  op->synchronous = false;
710  if (action_callback) {
711  op->opaque->callback = action_callback;
712  }
713 
714  if (op->interval > 0) {
715  init_recurring_actions();
716  if (handle_duplicate_recurring(op) == TRUE) {
717  /* entry rescheduled, dup freed */
718  /* exit early */
719  return TRUE;
720  }
721  g_hash_table_replace(recurring_actions, op->id, op);
722  }
723 
724  if (op->rsc && is_op_blocked(op->rsc)) {
725  blocked_ops = g_list_append(blocked_ops, op);
726  return TRUE;
727  }
728 
729  return action_exec_helper(op);
730 }
731 
732 
733 static gboolean processing_blocked_ops = FALSE;
734 
735 gboolean
736 is_op_blocked(const char *rsc)
737 {
738  GList *gIter = NULL;
739  svc_action_t *op = NULL;
740 
741  for (gIter = inflight_ops; gIter != NULL; gIter = gIter->next) {
742  op = gIter->data;
743  if (safe_str_eq(op->rsc, rsc)) {
744  return TRUE;
745  }
746  }
747 
748  return FALSE;
749 }
750 
751 static void
752 handle_blocked_ops(void)
753 {
754  GList *executed_ops = NULL;
755  GList *gIter = NULL;
756  svc_action_t *op = NULL;
757  gboolean res = FALSE;
758 
759  if (processing_blocked_ops) {
760  /* avoid nested calling of this function */
761  return;
762  }
763 
764  processing_blocked_ops = TRUE;
765 
766  /* n^2 operation here, but blocked ops are incredibly rare. this list
767  * will be empty 99% of the time. */
768  for (gIter = blocked_ops; gIter != NULL; gIter = gIter->next) {
769  op = gIter->data;
770  if (is_op_blocked(op->rsc)) {
771  continue;
772  }
773  executed_ops = g_list_append(executed_ops, op);
774  res = action_exec_helper(op);
775  if (res == FALSE) {
777  /* this can cause this function to be called recursively
778  * which is why we have processing_blocked_ops static variable */
779  operation_finalize(op);
780  }
781  }
782 
783  for (gIter = executed_ops; gIter != NULL; gIter = gIter->next) {
784  op = gIter->data;
785  blocked_ops = g_list_remove(blocked_ops, op);
786  }
787  g_list_free(executed_ops);
788 
789  processing_blocked_ops = FALSE;
790 }
791 
792 gboolean
794 {
795  gboolean rc = TRUE;
796 
797  if (op == NULL) {
798  crm_trace("No operation to execute");
799  return FALSE;
800  }
801 
802  op->synchronous = true;
803  rc = action_exec_helper(op);
804  crm_trace(" > %s_%s_%d: %s = %d", op->rsc, op->action, op->interval, op->opaque->exec, op->rc);
805  if (op->stdout_data) {
806  crm_trace(" > stdout: %s", op->stdout_data);
807  }
808  if (op->stderr_data) {
809  crm_trace(" > stderr: %s", op->stderr_data);
810  }
811  return rc;
812 }
813 
814 GList *
815 get_directory_list(const char *root, gboolean files, gboolean executable)
816 {
817  return services_os_get_directory_list(root, files, executable);
818 }
819 
820 GList *
822 {
824 }
825 
826 #if SUPPORT_HEARTBEAT
827 static GList *
828 resources_os_list_hb_agents(void)
829 {
830  return services_os_get_directory_list(HB_RA_DIR, TRUE, TRUE);
831 }
832 #endif
833 
834 GList *
836 {
837  GList *standards = NULL;
838  GList *agents = NULL;
839 
840  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_OCF));
841  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_LSB));
842  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_SERVICE));
843 
844 #if SUPPORT_SYSTEMD
845  agents = systemd_unit_listall();
846  if (agents) {
847  standards = g_list_append(standards,
849  g_list_free_full(agents, free);
850  }
851 #endif
852 
853 #if SUPPORT_UPSTART
854  agents = upstart_job_listall();
855  if (agents) {
856  standards = g_list_append(standards,
858  g_list_free_full(agents, free);
859  }
860 #endif
861 
862 #if SUPPORT_NAGIOS
864  if (agents) {
865  standards = g_list_append(standards,
867  g_list_free_full(agents, free);
868  }
869 #endif
870 
871 #if SUPPORT_HEARTBEAT
872  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_HB));
873 #endif
874 
875  return standards;
876 }
877 
878 GList *
879 resources_list_providers(const char *standard)
880 {
881  if (strcasecmp(standard, PCMK_RESOURCE_CLASS_OCF) == 0) {
883  }
884 
885  return NULL;
886 }
887 
888 GList *
889 resources_list_agents(const char *standard, const char *provider)
890 {
891  if ((standard == NULL)
892  || (strcasecmp(standard, PCMK_RESOURCE_CLASS_SERVICE) == 0)) {
893 
894  GList *tmp1;
895  GList *tmp2;
896  GList *result = resources_os_list_lsb_agents();
897 
898  if (standard == NULL) {
899  tmp1 = result;
900  tmp2 = resources_os_list_ocf_agents(NULL);
901  if (tmp2) {
902  result = g_list_concat(tmp1, tmp2);
903  }
904  }
905 #if SUPPORT_SYSTEMD
906  tmp1 = result;
907  tmp2 = systemd_unit_listall();
908  if (tmp2) {
909  result = g_list_concat(tmp1, tmp2);
910  }
911 #endif
912 
913 #if SUPPORT_UPSTART
914  tmp1 = result;
915  tmp2 = upstart_job_listall();
916  if (tmp2) {
917  result = g_list_concat(tmp1, tmp2);
918  }
919 #endif
920 
921  return result;
922 
923  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_OCF) == 0) {
924  return resources_os_list_ocf_agents(provider);
925  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_LSB) == 0) {
927 #if SUPPORT_HEARTBEAT
928  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_HB) == 0) {
929  return resources_os_list_hb_agents();
930 #endif
931 #if SUPPORT_SYSTEMD
932  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_SYSTEMD) == 0) {
933  return systemd_unit_listall();
934 #endif
935 #if SUPPORT_UPSTART
936  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_UPSTART) == 0) {
937  return upstart_job_listall();
938 #endif
939 #if SUPPORT_NAGIOS
940  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_NAGIOS) == 0) {
942 #endif
943  }
944 
945  return NULL;
946 }
gboolean services_action_cancel(const char *name, const char *action, int interval)
Cancel a recurring action.
Definition: services.c:521
Services API.
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:164
void(* callback)(svc_action_t *op)
A dumping ground.
GList * resources_list_providers(const char *standard)
Get a list of providers.
Definition: services.c:879
char * standard
Definition: services.h:167
gboolean upstart_job_exists(const char *name)
Definition: upstart.c:230
gboolean mainloop_child_kill(pid_t pid)
Definition: mainloop.c:1042
char * id
Definition: services.h:162
svc_action_t * resources_action_create(const char *name, const char *standard, const char *provider, const char *agent, const char *action, int interval, int timeout, GHashTable *params, enum svc_action_flags flags)
Create a new resource action.
Definition: services.c:154
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:59
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:707
char * rsc
Definition: services.h:163
int interval
Definition: services.h:165
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:153
gboolean upstart_job_exec(svc_action_t *op)
Definition: upstart.c:417
gboolean is_op_blocked(const char *rsc)
Definition: services.c:736
Wrappers for and extensions to glib mainloop.
svc_action_t * services_action_create_generic(const char *exec, const char *args[])
Definition: services.c:355
GList * resources_os_list_lsb_agents(void)
enum svc_action_flags flags
Definition: services.h:181
#define crm_warn(fmt, args...)
Definition: logging.h:249
GList * services_list(void)
Definition: services.c:821
#define PCMK_RESOURCE_CLASS_OCF
Definition: services.h:56
gboolean cancel_recurring_action(svc_action_t *op)
Definition: services.c:495
svc_action_private_t * opaque
Definition: services.h:194
GList * upstart_job_listall(void)
Definition: upstart.c:149
#define OCF_ROOT_DIR
Definition: services.h:38
#define crm_debug(fmt, args...)
Definition: logging.h:253
gboolean operation_finalize(svc_action_t *op)
char * stdout_data
Definition: services.h:184
gboolean systemd_unit_exists(const char *name)
Definition: systemd.c:434
#define PCMK_RESOURCE_CLASS_SERVICE
Definition: services.h:57
GHashTable * params
Definition: services.h:172
#define crm_trace(fmt, args...)
Definition: logging.h:254
char * agent
Definition: services.h:169
int synchronous
Definition: services.h:180
gboolean services_action_sync(svc_action_t *op)
Definition: services.c:793
#define SUPPORT_HEARTBEAT
Definition: config.h:729
#define LSB_ROOT_DIR
Definition: services.h:42
int sequence
Definition: services.h:178
gboolean services_action_kick(const char *name, const char *action, int interval)
Definition: services.c:584
GList * systemd_unit_listall(void)
Definition: systemd.c:358
const char * resources_find_service_class(const char *agent)
Definition: services.c:59
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
Definition: services.c:889
#define MAX_ARGC
char * args[MAX_ARGC]
void services_add_inflight_op(svc_action_t *op)
Definition: services.c:675
GList * resources_list_standards(void)
Definition: services.c:835
void services_untrack_op(svc_action_t *op)
Definition: services.c:696
char * action
Definition: services.h:164
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:815
#define PCMK_RESOURCE_CLASS_NAGIOS
Definition: services.h:62
#define PCMK_RESOURCE_CLASS_LSB
Definition: services.h:58
#define NAGIOS_PLUGIN_DIR
Definition: config.h:618
#define CRM_META
Definition: crm.h:53
#define crm_err(fmt, args...)
Definition: logging.h:248
#define PCMK_RESOURCE_CLASS_UPSTART
Definition: services.h:60
#define PCMK_RESOURCE_CLASS_HB
Definition: services.h:61
#define DIMOF(a)
Definition: crm.h:39
mainloop_io_t * stdout_gsource
#define CRM_ASSERT(expr)
Definition: error.h:35
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:84
void mainloop_del_fd(mainloop_io_t *client)
Definition: mainloop.c:854
void * cb_data
Definition: services.h:192
void services_action_cleanup(svc_action_t *op)
Definition: services.c:407
char * generate_op_key(const char *rsc_id, const char *op_type, int interval)
Generate an operation key.
Definition: utils.c:652
#define safe_str_eq(a, b)
Definition: util.h:64
void services_action_free(svc_action_t *op)
Definition: services.c:443
char * provider
Definition: services.h:168
gboolean systemd_unit_exec(svc_action_t *op)
Definition: systemd.c:725
#define crm_info(fmt, args...)
Definition: logging.h:251
uint64_t flags
Definition: remote.c:156
svc_action_t * services_action_create(const char *name, const char *action, int interval, int timeout)
Definition: services.c:52
char * stderr_data
Definition: services.h:183