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 
375 static void
376 set_alert_env(gpointer key, gpointer value, gpointer user_data)
377 {
378  int rc;
379 
380  if (value) {
381  rc = setenv(key, value, 1);
382  } else {
383  rc = unsetenv(key);
384  }
385 
386  if (rc < 0) {
387  crm_perror(LOG_ERR, "setenv %s=%s",
388  (char*)key, (value? (char*)value : ""));
389  } else {
390  crm_trace("setenv %s=%s", (char*)key, (value? (char*)value : ""));
391  }
392 }
393 
394 static void
395 unset_alert_env(gpointer key, gpointer value, gpointer user_data)
396 {
397  if (unsetenv(key) < 0) {
398  crm_perror(LOG_ERR, "unset %s", (char*)key);
399  } else {
400  crm_trace("unset %s", (char*)key);
401  }
402 }
403 
415 gboolean
417 {
418  gboolean responsible;
419 
420  action->synchronous = false;
421  action->opaque->callback = cb;
422  if (action->params) {
423  g_hash_table_foreach(action->params, set_alert_env, NULL);
424  }
425  responsible = services_os_action_execute(action);
426  if (action->params) {
427  g_hash_table_foreach(action->params, unset_alert_env, NULL);
428  }
429  return responsible;
430 }
431 
432 #if SUPPORT_DBUS
433 
440 void
441 services_set_op_pending(svc_action_t *op, DBusPendingCall *pending)
442 {
443  if (op->opaque->pending && (op->opaque->pending != pending)) {
444  if (pending) {
445  crm_info("Lost pending %s DBus call (%p)", op->id, op->opaque->pending);
446  } else {
447  crm_trace("Done with pending %s DBus call (%p)", op->id, op->opaque->pending);
448  }
449  dbus_pending_call_unref(op->opaque->pending);
450  }
451  op->opaque->pending = pending;
452  if (pending) {
453  crm_trace("Updated pending %s DBus call (%p)", op->id, pending);
454  } else {
455  crm_trace("Cleared pending %s DBus call", op->id);
456  }
457 }
458 #endif
459 
460 void
462 {
463  if ((op == NULL) || (op->opaque == NULL)) {
464  return;
465  }
466 
467 #if SUPPORT_DBUS
468  if(op->opaque->timerid != 0) {
469  crm_trace("Removing timer for call %s to %s", op->action, op->rsc);
470  g_source_remove(op->opaque->timerid);
471  op->opaque->timerid = 0;
472  }
473 
474  if(op->opaque->pending) {
475  if (dbus_pending_call_get_completed(op->opaque->pending)) {
476  // This should never be the case
477  crm_warn("Result of %s op %s was unhandled",
478  op->standard, op->id);
479  } else {
480  crm_debug("Will ignore any result of canceled %s op %s",
481  op->standard, op->id);
482  }
483  dbus_pending_call_cancel(op->opaque->pending);
484  services_set_op_pending(op, NULL);
485  }
486 #endif
487 
488  if (op->opaque->stderr_gsource) {
490  op->opaque->stderr_gsource = NULL;
491  }
492 
493  if (op->opaque->stdout_gsource) {
495  op->opaque->stdout_gsource = NULL;
496  }
497 }
498 
499 void
501 {
502  unsigned int i;
503 
504  if (op == NULL) {
505  return;
506  }
507 
508  /* The operation should be removed from all tracking lists by this point.
509  * If it's not, we have a bug somewhere, so bail. That may lead to a
510  * memory leak, but it's better than a use-after-free segmentation fault.
511  */
512  CRM_CHECK(g_list_find(inflight_ops, op) == NULL, return);
513  CRM_CHECK(g_list_find(blocked_ops, op) == NULL, return);
514  CRM_CHECK((recurring_actions == NULL)
515  || (g_hash_table_lookup(recurring_actions, op->id) == NULL),
516  return);
517 
519 
520  if (op->opaque->repeat_timer) {
521  g_source_remove(op->opaque->repeat_timer);
522  op->opaque->repeat_timer = 0;
523  }
524 
525  free(op->id);
526  free(op->opaque->exec);
527 
528  for (i = 0; i < DIMOF(op->opaque->args); i++) {
529  free(op->opaque->args[i]);
530  }
531 
532  free(op->opaque);
533  free(op->rsc);
534  free(op->action);
535 
536  free(op->standard);
537  free(op->agent);
538  free(op->provider);
539 
540  free(op->stdout_data);
541  free(op->stderr_data);
542 
543  if (op->params) {
544  g_hash_table_destroy(op->params);
545  op->params = NULL;
546  }
547 
548  free(op);
549 }
550 
551 gboolean
553 {
554  crm_info("Cancelling %s operation %s", op->standard, op->id);
555 
556  if (recurring_actions) {
557  g_hash_table_remove(recurring_actions, op->id);
558  }
559 
560  if (op->opaque->repeat_timer) {
561  g_source_remove(op->opaque->repeat_timer);
562  op->opaque->repeat_timer = 0;
563  }
564 
565  return TRUE;
566 }
567 
577 gboolean
578 services_action_cancel(const char *name, const char *action, guint interval_ms)
579 {
580  gboolean cancelled = FALSE;
581  char *id = generate_op_key(name, action, interval_ms);
582  svc_action_t *op = NULL;
583 
584  /* We can only cancel a recurring action */
585  init_recurring_actions();
586  op = g_hash_table_lookup(recurring_actions, id);
587  if (op == NULL) {
588  goto done;
589  }
590 
591  /* Tell operation_finalize() not to reschedule the operation */
592  op->cancel = TRUE;
593 
594  /* Stop tracking it as a recurring operation, and stop its repeat timer */
596 
597  /* If the op has a PID, it's an in-flight child process, so kill it.
598  *
599  * Whether the kill succeeds or fails, the main loop will send the op to
600  * operation_finished() (and thus operation_finalize()) when the process
601  * goes away.
602  */
603  if (op->pid != 0) {
604  crm_info("Terminating in-flight op %s (pid %d) early because it was cancelled",
605  id, op->pid);
606  cancelled = mainloop_child_kill(op->pid);
607  if (cancelled == FALSE) {
608  crm_err("Termination of %s (pid %d) failed", id, op->pid);
609  }
610  goto done;
611  }
612 
613 #if SUPPORT_DBUS
614  // In-flight systemd and upstart ops don't have a pid
615  if (inflight_systemd_or_upstart(op)) {
616  inflight_ops = g_list_remove(inflight_ops, op);
617 
618  /* This will cause any result that comes in later to be discarded, so we
619  * don't call the callback and free the operation twice.
620  */
622  }
623 #endif
624 
625  // The rest of this is essentially equivalent to operation_finalize(),
626  // except without calling handle_blocked_ops()
627 
628  // Report operation as cancelled
630  if (op->opaque->callback) {
631  op->opaque->callback(op);
632  }
633 
634  blocked_ops = g_list_remove(blocked_ops, op);
636  cancelled = TRUE;
637  // @TODO Initiate handle_blocked_ops() asynchronously
638 
639 done:
640  free(id);
641  return cancelled;
642 }
643 
644 gboolean
645 services_action_kick(const char *name, const char *action, guint interval_ms)
646 {
647  svc_action_t * op = NULL;
648  char *id = generate_op_key(name, action, interval_ms);
649 
650  init_recurring_actions();
651  op = g_hash_table_lookup(recurring_actions, id);
652  free(id);
653 
654  if (op == NULL) {
655  return FALSE;
656  }
657 
658 
659  if (op->pid || inflight_systemd_or_upstart(op)) {
660  return TRUE;
661  } else {
662  if (op->opaque->repeat_timer) {
663  g_source_remove(op->opaque->repeat_timer);
664  op->opaque->repeat_timer = 0;
665  }
667  return TRUE;
668  }
669 
670 }
671 
680 static gboolean
681 handle_duplicate_recurring(svc_action_t * op)
682 {
683  svc_action_t * dup = NULL;
684 
685  /* check for duplicates */
686  dup = g_hash_table_lookup(recurring_actions, op->id);
687 
688  if (dup && (dup != op)) {
689  /* update user data */
690  if (op->opaque->callback) {
691  dup->opaque->callback = op->opaque->callback;
692  dup->cb_data = op->cb_data;
693  op->cb_data = NULL;
694  }
695  /* immediately execute the next interval */
696  if (dup->pid != 0) {
697  if (op->opaque->repeat_timer) {
698  g_source_remove(op->opaque->repeat_timer);
699  op->opaque->repeat_timer = 0;
700  }
702  }
703  /* free the duplicate */
705  return TRUE;
706  }
707 
708  return FALSE;
709 }
710 
711 inline static gboolean
712 action_exec_helper(svc_action_t * op)
713 {
714  /* Whether a/synchronous must be decided (op->synchronous) beforehand. */
715  if (op->standard
716  && (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_UPSTART) == 0)) {
717 #if SUPPORT_UPSTART
718  return upstart_job_exec(op);
719 #endif
720  } else if (op->standard && strcasecmp(op->standard,
722 #if SUPPORT_SYSTEMD
723  return systemd_unit_exec(op);
724 #endif
725  } else {
726  return services_os_action_execute(op);
727  }
728  /* The 'op' has probably been freed if the execution functions return TRUE
729  for the asynchronous 'op'. */
730  /* Avoid using the 'op' in here. */
731 
732  return FALSE;
733 }
734 
735 void
737 {
738  if (op == NULL) {
739  return;
740  }
741 
742  CRM_ASSERT(op->synchronous == FALSE);
743 
744  /* keep track of ops that are in-flight to avoid collisions in the same namespace */
745  if (op->rsc) {
746  inflight_ops = g_list_append(inflight_ops, op);
747  }
748 }
749 
756 void
758 {
759  /* Op is no longer in-flight or blocked */
760  inflight_ops = g_list_remove(inflight_ops, op);
761  blocked_ops = g_list_remove(blocked_ops, op);
762 
763  /* Op is no longer blocking other ops, so check if any need to run */
764  handle_blocked_ops();
765 }
766 
767 gboolean
768 services_action_async(svc_action_t * op, void (*action_callback) (svc_action_t *))
769 {
770  op->synchronous = false;
771  if (action_callback) {
772  op->opaque->callback = action_callback;
773  }
774 
775  if (op->interval_ms > 0) {
776  init_recurring_actions();
777  if (handle_duplicate_recurring(op) == TRUE) {
778  /* entry rescheduled, dup freed */
779  /* exit early */
780  return TRUE;
781  }
782  g_hash_table_replace(recurring_actions, op->id, op);
783  }
784 
785  if (op->rsc && is_op_blocked(op->rsc)) {
786  blocked_ops = g_list_append(blocked_ops, op);
787  return TRUE;
788  }
789 
790  return action_exec_helper(op);
791 }
792 
793 
794 static gboolean processing_blocked_ops = FALSE;
795 
796 gboolean
797 is_op_blocked(const char *rsc)
798 {
799  GList *gIter = NULL;
800  svc_action_t *op = NULL;
801 
802  for (gIter = inflight_ops; gIter != NULL; gIter = gIter->next) {
803  op = gIter->data;
804  if (safe_str_eq(op->rsc, rsc)) {
805  return TRUE;
806  }
807  }
808 
809  return FALSE;
810 }
811 
812 static void
813 handle_blocked_ops(void)
814 {
815  GList *executed_ops = NULL;
816  GList *gIter = NULL;
817  svc_action_t *op = NULL;
818  gboolean res = FALSE;
819 
820  if (processing_blocked_ops) {
821  /* avoid nested calling of this function */
822  return;
823  }
824 
825  processing_blocked_ops = TRUE;
826 
827  /* n^2 operation here, but blocked ops are incredibly rare. this list
828  * will be empty 99% of the time. */
829  for (gIter = blocked_ops; gIter != NULL; gIter = gIter->next) {
830  op = gIter->data;
831  if (is_op_blocked(op->rsc)) {
832  continue;
833  }
834  executed_ops = g_list_append(executed_ops, op);
835  res = action_exec_helper(op);
836  if (res == FALSE) {
838  /* this can cause this function to be called recursively
839  * which is why we have processing_blocked_ops static variable */
840  operation_finalize(op);
841  }
842  }
843 
844  for (gIter = executed_ops; gIter != NULL; gIter = gIter->next) {
845  op = gIter->data;
846  blocked_ops = g_list_remove(blocked_ops, op);
847  }
848  g_list_free(executed_ops);
849 
850  processing_blocked_ops = FALSE;
851 }
852 
853 #if SUPPORT_NAGIOS
854 static int
855 nagios_get_metadata(const char *type, char **output)
856 {
857  int rc = pcmk_ok;
858  FILE *file_strm = NULL;
859  int start = 0, length = 0, read_len = 0;
860  char *metadata_file = crm_strdup_printf("%s/%s.xml",
861  NAGIOS_METADATA_DIR, type);
862 
863  file_strm = fopen(metadata_file, "r");
864  if (file_strm == NULL) {
865  crm_err("Metadata file %s does not exist", metadata_file);
866  free(metadata_file);
867  return -EIO;
868  }
869 
870  /* see how big the file is */
871  start = ftell(file_strm);
872  fseek(file_strm, 0L, SEEK_END);
873  length = ftell(file_strm);
874  fseek(file_strm, 0L, start);
875 
876  CRM_ASSERT(length >= 0);
877  CRM_ASSERT(start == ftell(file_strm));
878 
879  if (length <= 0) {
880  crm_info("%s was not valid", metadata_file);
881  free(*output);
882  *output = NULL;
883  rc = -EIO;
884 
885  } else {
886  crm_trace("Reading %d bytes from file", length);
887  *output = calloc(1, (length + 1));
888  read_len = fread(*output, 1, length, file_strm);
889  if (read_len != length) {
890  crm_err("Calculated and read bytes differ: %d vs. %d",
891  length, read_len);
892  free(*output);
893  *output = NULL;
894  rc = -EIO;
895  }
896  }
897 
898  fclose(file_strm);
899  free(metadata_file);
900  return rc;
901 }
902 #endif
903 
904 static gboolean
905 action_get_metadata(svc_action_t *op)
906 {
907  const char *class = op->standard;
908 
909  if (op->agent == NULL) {
910  crm_err("meta-data requested without specifying agent");
911  return FALSE;
912  }
913 
914  if (class == NULL) {
915  crm_err("meta-data requested for agent %s without specifying class",
916  op->agent);
917  return FALSE;
918  }
919 
920  if (!strcmp(class, PCMK_RESOURCE_CLASS_SERVICE)) {
921  class = resources_find_service_class(op->agent);
922  }
923 
924  if (class == NULL) {
925  crm_err("meta-data requested for %s, but could not determine class",
926  op->agent);
927  return FALSE;
928  }
929 
930  if (safe_str_eq(class, PCMK_RESOURCE_CLASS_LSB)) {
931  return (services__get_lsb_metadata(op->agent, &op->stdout_data) >= 0);
932  }
933 
934 #if SUPPORT_NAGIOS
936  return (nagios_get_metadata(op->agent, &op->stdout_data) >= 0);
937  }
938 #endif
939 
940  return action_exec_helper(op);
941 }
942 
943 gboolean
945 {
946  gboolean rc = TRUE;
947 
948  if (op == NULL) {
949  crm_trace("No operation to execute");
950  return FALSE;
951  }
952 
953  op->synchronous = true;
954 
955  if (safe_str_eq(op->action, "meta-data")) {
956  /* Synchronous meta-data operations are handled specially. Since most
957  * resource classes don't provide any meta-data, it has to be
958  * synthesized from available information about the agent.
959  *
960  * services_action_async() doesn't treat meta-data actions specially, so
961  * it will result in an error for classes that don't support the action.
962  */
963  rc = action_get_metadata(op);
964  } else {
965  rc = action_exec_helper(op);
966  }
967  crm_trace(" > " CRM_OP_FMT ": %s = %d",
968  op->rsc, op->action, op->interval_ms, op->opaque->exec, op->rc);
969  if (op->stdout_data) {
970  crm_trace(" > stdout: %s", op->stdout_data);
971  }
972  if (op->stderr_data) {
973  crm_trace(" > stderr: %s", op->stderr_data);
974  }
975  return rc;
976 }
977 
978 GList *
979 get_directory_list(const char *root, gboolean files, gboolean executable)
980 {
981  return services_os_get_directory_list(root, files, executable);
982 }
983 
984 GList *
986 {
987  GList *standards = NULL;
988  GList *agents = NULL;
989 
990  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_OCF));
991  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_LSB));
992  standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_SERVICE));
993 
994 #if SUPPORT_SYSTEMD
995  agents = systemd_unit_listall();
996  if (agents) {
997  standards = g_list_append(standards,
999  g_list_free_full(agents, free);
1000  }
1001 #endif
1002 
1003 #if SUPPORT_UPSTART
1004  agents = upstart_job_listall();
1005  if (agents) {
1006  standards = g_list_append(standards,
1007  strdup(PCMK_RESOURCE_CLASS_UPSTART));
1008  g_list_free_full(agents, free);
1009  }
1010 #endif
1011 
1012 #if SUPPORT_NAGIOS
1014  if (agents) {
1015  standards = g_list_append(standards,
1016  strdup(PCMK_RESOURCE_CLASS_NAGIOS));
1017  g_list_free_full(agents, free);
1018  }
1019 #endif
1020 
1021  return standards;
1022 }
1023 
1024 GList *
1025 resources_list_providers(const char *standard)
1026 {
1027  if (is_set(pcmk_get_ra_caps(standard), pcmk_ra_cap_provider)) {
1029  }
1030 
1031  return NULL;
1032 }
1033 
1034 GList *
1035 resources_list_agents(const char *standard, const char *provider)
1036 {
1037  if ((standard == NULL)
1038  || (strcasecmp(standard, PCMK_RESOURCE_CLASS_SERVICE) == 0)) {
1039 
1040  GList *tmp1;
1041  GList *tmp2;
1042  GList *result = services__list_lsb_agents();
1043 
1044  if (standard == NULL) {
1045  tmp1 = result;
1046  tmp2 = resources_os_list_ocf_agents(NULL);
1047  if (tmp2) {
1048  result = g_list_concat(tmp1, tmp2);
1049  }
1050  }
1051 #if SUPPORT_SYSTEMD
1052  tmp1 = result;
1053  tmp2 = systemd_unit_listall();
1054  if (tmp2) {
1055  result = g_list_concat(tmp1, tmp2);
1056  }
1057 #endif
1058 
1059 #if SUPPORT_UPSTART
1060  tmp1 = result;
1061  tmp2 = upstart_job_listall();
1062  if (tmp2) {
1063  result = g_list_concat(tmp1, tmp2);
1064  }
1065 #endif
1066 
1067  return result;
1068 
1069  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_OCF) == 0) {
1070  return resources_os_list_ocf_agents(provider);
1071  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_LSB) == 0) {
1072  return services__list_lsb_agents();
1073 #if SUPPORT_SYSTEMD
1074  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_SYSTEMD) == 0) {
1075  return systemd_unit_listall();
1076 #endif
1077 #if SUPPORT_UPSTART
1078  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_UPSTART) == 0) {
1079  return upstart_job_listall();
1080 #endif
1081 #if SUPPORT_NAGIOS
1082  } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_NAGIOS) == 0) {
1084 #endif
1085  }
1086 
1087  return NULL;
1088 }
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:1025
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:768
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:797
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:552
#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
int setenv(const char *name, const char *value, int why)
gboolean services_alert_async(svc_action_t *action, void(*cb)(svc_action_t *op))
Execute an alert agent action.
Definition: services.c:416
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:944
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:1035
char * args[MAX_ARGC]
void services_add_inflight_op(svc_action_t *op)
Definition: services.c:736
GList * resources_list_standards(void)
Definition: services.c:985
void services_untrack_op(svc_action_t *op)
Definition: services.c:757
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:979
#define PCMK_RESOURCE_CLASS_NAGIOS
Definition: services.h:46
#define PCMK_RESOURCE_CLASS_LSB
Definition: services.h:43
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:227
#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:461
#define safe_str_eq(a, b)
Definition: util.h:54
void services_action_free(svc_action_t *op)
Definition: services.c:500
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:578
gboolean services_action_kick(const char *name, const char *action, guint interval_ms)
Definition: services.c:645
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