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