This source file includes following definitions.
- resources_find_service_class
- init_recurring_actions
- inflight_systemd
- expand_resource_class
- new_action
- required_argument_missing
- copy_action_arguments
- services__create_resource_action
- resources_action_create
- services_action_create_generic
- services_alert_create
- services_action_user
- services_alert_async
- services_set_op_pending
- services_action_cleanup
- services_result2ocf
- services_action_free
- cancel_recurring_action
- services_action_cancel
- services_action_kick
- handle_duplicate_recurring
- execute_action
- services_add_inflight_op
- services_untrack_op
- services_action_async_fork_notify
- services_action_async
- is_op_blocked
- handle_blocked_ops
- execute_metadata_action
- services_action_sync
- get_directory_list
- resources_list_standards
- resources_list_providers
- resources_list_agents
- resources_agent_exists
- services__set_result
- services__format_result
- services__set_cancelled
- services__action_kind
- services__exit_reason
- services__grab_stdout
- services__grab_stderr
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <stdio.h>
15 #include <errno.h>
16 #include <unistd.h>
17 #include <dirent.h>
18 #include <fcntl.h>
19
20 #include <crm/crm.h>
21 #include <crm/common/mainloop.h>
22 #include <crm/services.h>
23 #include <crm/services_internal.h>
24 #include <crm/stonith-ng.h>
25 #include <crm/common/xml.h>
26 #include "services_private.h"
27 #include "services_ocf.h"
28
29 #if PCMK__ENABLE_LSB
30 #include "services_lsb.h"
31 #endif
32
33 #if SUPPORT_SYSTEMD
34 # include <systemd.h>
35 #endif
36
37
38
39 static int operations = 0;
40 static GHashTable *recurring_actions = NULL;
41
42
43
44 static GList *blocked_ops = NULL;
45
46
47 static GList *inflight_ops = NULL;
48
49 static void handle_blocked_ops(void);
50
51
52
53
54
55
56
57
58
59
60
61
62 const char *
63 resources_find_service_class(const char *agent)
64 {
65 #if PCMK__ENABLE_LSB
66 if (services__lsb_agent_exists(agent)) {
67 return PCMK_RESOURCE_CLASS_LSB;
68 }
69 #endif
70
71 #if SUPPORT_SYSTEMD
72 if (systemd_unit_exists(agent)) {
73 return PCMK_RESOURCE_CLASS_SYSTEMD;
74 }
75 #endif
76
77 return NULL;
78 }
79
80 static inline void
81 init_recurring_actions(void)
82 {
83 if (recurring_actions == NULL) {
84 recurring_actions = pcmk__strkey_table(NULL, NULL);
85 }
86 }
87
88
89
90
91
92
93
94
95
96 static inline gboolean
97 inflight_systemd(const svc_action_t *op)
98 {
99 return pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_SYSTEMD,
100 pcmk__str_casei)
101 && (g_list_find(inflight_ops, op) != NULL);
102 }
103
104
105
106
107
108
109
110
111
112
113
114
115
116 static char *
117 expand_resource_class(const char *rsc, const char *standard, const char *agent)
118 {
119 char *expanded_class = NULL;
120
121 #if PCMK__ENABLE_SERVICE
122 if (strcasecmp(standard, PCMK_RESOURCE_CLASS_SERVICE) == 0) {
123 const char *found_class = resources_find_service_class(agent);
124
125 if (found_class != NULL) {
126 crm_debug("Found %s agent %s for %s", found_class, agent, rsc);
127 expanded_class = pcmk__str_copy(found_class);
128 } else {
129 const char *default_standard = NULL;
130
131 #if PCMK__ENABLE_LSB
132 default_standard = PCMK_RESOURCE_CLASS_LSB;
133 #elif SUPPORT_SYSTEMD
134 default_standard = PCMK_RESOURCE_CLASS_SYSTEMD;
135 #else
136 #error No standards supported for service alias (configure script bug)
137 #endif
138 crm_info("Assuming resource class %s for agent %s for %s",
139 default_standard, agent, rsc);
140 expanded_class = pcmk__str_copy(default_standard);
141 }
142 }
143 #endif
144
145 if (expanded_class == NULL) {
146 expanded_class = pcmk__str_copy(standard);
147 }
148 return expanded_class;
149 }
150
151
152
153
154
155
156
157 static svc_action_t *
158 new_action(void)
159 {
160 svc_action_t *op = calloc(1, sizeof(svc_action_t));
161
162 if (op == NULL) {
163 return NULL;
164 }
165
166 op->opaque = calloc(1, sizeof(svc_action_private_t));
167 if (op->opaque == NULL) {
168 free(op);
169 return NULL;
170 }
171
172
173 services__set_result(op, PCMK_OCF_UNKNOWN, PCMK_EXEC_UNKNOWN, NULL);
174 return op;
175 }
176
177 static bool
178 required_argument_missing(uint32_t ra_caps, const char *name,
179 const char *standard, const char *provider,
180 const char *agent, const char *action)
181 {
182 if (pcmk__str_empty(name)) {
183 crm_info("Cannot create operation without resource name (bug?)");
184 return true;
185 }
186
187 if (pcmk__str_empty(standard)) {
188 crm_info("Cannot create operation for %s without resource class (bug?)",
189 name);
190 return true;
191 }
192
193 if (pcmk_is_set(ra_caps, pcmk_ra_cap_provider)
194 && pcmk__str_empty(provider)) {
195 crm_info("Cannot create operation for %s resource %s "
196 "without provider (bug?)", standard, name);
197 return true;
198 }
199
200 if (pcmk__str_empty(agent)) {
201 crm_info("Cannot create operation for %s without agent name (bug?)",
202 name);
203 return true;
204 }
205
206 if (pcmk__str_empty(action)) {
207 crm_info("Cannot create operation for %s without action name (bug?)",
208 name);
209 return true;
210 }
211 return false;
212 }
213
214
215 static int
216 copy_action_arguments(svc_action_t *op, uint32_t ra_caps, const char *name,
217 const char *standard, const char *provider,
218 const char *agent, const char *action)
219 {
220 op->rsc = strdup(name);
221 if (op->rsc == NULL) {
222 return ENOMEM;
223 }
224
225 op->agent = strdup(agent);
226 if (op->agent == NULL) {
227 return ENOMEM;
228 }
229
230 op->standard = expand_resource_class(name, standard, agent);
231 if (op->standard == NULL) {
232 return ENOMEM;
233 }
234
235 if (pcmk_is_set(ra_caps, pcmk_ra_cap_status)
236 && pcmk__str_eq(action, PCMK_ACTION_MONITOR, pcmk__str_casei)) {
237 action = PCMK_ACTION_STATUS;
238 }
239 op->action = strdup(action);
240 if (op->action == NULL) {
241 return ENOMEM;
242 }
243
244 if (pcmk_is_set(ra_caps, pcmk_ra_cap_provider)) {
245 op->provider = strdup(provider);
246 if (op->provider == NULL) {
247 return ENOMEM;
248 }
249 }
250 return pcmk_rc_ok;
251 }
252
253 svc_action_t *
254 services__create_resource_action(const char *name, const char *standard,
255 const char *provider, const char *agent,
256 const char *action, guint interval_ms, int timeout,
257 GHashTable *params, enum svc_action_flags flags)
258 {
259 svc_action_t *op = NULL;
260 uint32_t ra_caps = pcmk_get_ra_caps(standard);
261 int rc = pcmk_rc_ok;
262
263 op = new_action();
264 if (op == NULL) {
265 crm_crit("Cannot prepare action: %s", strerror(ENOMEM));
266 if (params != NULL) {
267 g_hash_table_destroy(params);
268 }
269 return NULL;
270 }
271
272 op->interval_ms = interval_ms;
273 op->timeout = timeout;
274 op->flags = flags;
275 op->sequence = ++operations;
276
277
278 if (pcmk_is_set(ra_caps, pcmk_ra_cap_params)) {
279 op->params = params;
280 } else if (params != NULL) {
281 g_hash_table_destroy(params);
282 params = NULL;
283 }
284
285 if (required_argument_missing(ra_caps, name, standard, provider, agent,
286 action)) {
287 services__set_result(op, services__generic_error(op),
288 PCMK_EXEC_ERROR_FATAL,
289 "Required agent or action information missing");
290 return op;
291 }
292
293 op->id = pcmk__op_key(name, action, interval_ms);
294
295 if (copy_action_arguments(op, ra_caps, name, standard, provider, agent,
296 action) != pcmk_rc_ok) {
297 crm_crit("Cannot prepare %s action for %s: %s",
298 action, name, strerror(ENOMEM));
299 services__handle_exec_error(op, ENOMEM);
300 return op;
301 }
302
303 if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_OCF) == 0) {
304 rc = services__ocf_prepare(op);
305
306 #if PCMK__ENABLE_LSB
307 } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_LSB) == 0) {
308 rc = services__lsb_prepare(op);
309 #endif
310 #if SUPPORT_SYSTEMD
311 } else if (strcasecmp(op->standard, PCMK_RESOURCE_CLASS_SYSTEMD) == 0) {
312 rc = services__systemd_prepare(op);
313 #endif
314 } else {
315 crm_info("Unknown resource standard: %s", op->standard);
316 rc = ENOENT;
317 }
318
319 if (rc != pcmk_rc_ok) {
320 crm_info("Cannot prepare %s operation for %s: %s",
321 action, name, strerror(rc));
322 services__handle_exec_error(op, rc);
323 }
324 return op;
325 }
326
327 svc_action_t *
328 resources_action_create(const char *name, const char *standard,
329 const char *provider, const char *agent,
330 const char *action, guint interval_ms, int timeout,
331 GHashTable *params, enum svc_action_flags flags)
332 {
333 svc_action_t *op = services__create_resource_action(name, standard,
334 provider, agent, action, interval_ms, timeout,
335 params, flags);
336 if (op == NULL || op->rc != 0) {
337 services_action_free(op);
338 return NULL;
339 } else {
340
341 op->rc = PCMK_OCF_OK;
342 op->status = PCMK_EXEC_DONE;
343
344 return op;
345 }
346 }
347
348 svc_action_t *
349 services_action_create_generic(const char *exec, const char *args[])
350 {
351 svc_action_t *op = new_action();
352
353 pcmk__mem_assert(op);
354
355 op->opaque->exec = strdup(exec);
356 op->opaque->args[0] = strdup(exec);
357 if ((op->opaque->exec == NULL) || (op->opaque->args[0] == NULL)) {
358 crm_crit("Cannot prepare action for '%s': %s", exec, strerror(ENOMEM));
359 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
360 strerror(ENOMEM));
361 return op;
362 }
363
364 if (args == NULL) {
365 return op;
366 }
367
368 for (int cur_arg = 1; args[cur_arg - 1] != NULL; cur_arg++) {
369
370 if (cur_arg == PCMK__NELEM(op->opaque->args)) {
371 crm_info("Cannot prepare action for '%s': Too many arguments",
372 exec);
373 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR,
374 PCMK_EXEC_ERROR_HARD, "Too many arguments");
375 break;
376 }
377
378 op->opaque->args[cur_arg] = strdup(args[cur_arg - 1]);
379 if (op->opaque->args[cur_arg] == NULL) {
380 crm_crit("Cannot prepare action for '%s': %s",
381 exec, strerror(ENOMEM));
382 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
383 strerror(ENOMEM));
384 break;
385 }
386 }
387
388 return op;
389 }
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405 svc_action_t *
406 services_alert_create(const char *id, const char *exec, int timeout,
407 GHashTable *params, int sequence, void *cb_data)
408 {
409 svc_action_t *action = services_action_create_generic(exec, NULL);
410
411 action->id = pcmk__str_copy(id);
412 action->standard = pcmk__str_copy(PCMK_RESOURCE_CLASS_ALERT);
413 action->timeout = timeout;
414 action->params = params;
415 action->sequence = sequence;
416 action->cb_data = cb_data;
417 return action;
418 }
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434 int
435 services_action_user(svc_action_t *op, const char *user)
436 {
437 CRM_CHECK((op != NULL) && (user != NULL), return -EINVAL);
438 return crm_user_lookup(user, &(op->opaque->uid), &(op->opaque->gid));
439 }
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454 gboolean
455 services_alert_async(svc_action_t *action, void (*cb)(svc_action_t *op))
456 {
457 action->synchronous = false;
458 action->opaque->callback = cb;
459 return services__execute_file(action) == pcmk_rc_ok;
460 }
461
462 #if HAVE_DBUS
463
464
465
466
467
468
469
470 void
471 services_set_op_pending(svc_action_t *op, DBusPendingCall *pending)
472 {
473 if (op->opaque->pending && (op->opaque->pending != pending)) {
474 if (pending) {
475 crm_info("Lost pending %s DBus call (%p)", op->id, op->opaque->pending);
476 } else {
477 crm_trace("Done with pending %s DBus call (%p)", op->id, op->opaque->pending);
478 }
479 dbus_pending_call_unref(op->opaque->pending);
480 }
481 op->opaque->pending = pending;
482 if (pending) {
483 crm_trace("Updated pending %s DBus call (%p)", op->id, pending);
484 } else {
485 crm_trace("Cleared pending %s DBus call", op->id);
486 }
487 }
488 #endif
489
490 void
491 services_action_cleanup(svc_action_t * op)
492 {
493 if ((op == NULL) || (op->opaque == NULL)) {
494 return;
495 }
496
497 #if HAVE_DBUS
498 if(op->opaque->timerid != 0) {
499 crm_trace("Removing timer for call %s to %s", op->action, op->rsc);
500 g_source_remove(op->opaque->timerid);
501 op->opaque->timerid = 0;
502 }
503
504 if(op->opaque->pending) {
505 if (dbus_pending_call_get_completed(op->opaque->pending)) {
506
507 crm_warn("Result of %s op %s was unhandled",
508 op->standard, op->id);
509 } else {
510 crm_debug("Will ignore any result of canceled %s op %s",
511 op->standard, op->id);
512 }
513 dbus_pending_call_cancel(op->opaque->pending);
514 services_set_op_pending(op, NULL);
515 }
516 #endif
517
518 if (op->opaque->stderr_gsource) {
519 mainloop_del_fd(op->opaque->stderr_gsource);
520 op->opaque->stderr_gsource = NULL;
521 }
522
523 if (op->opaque->stdout_gsource) {
524 mainloop_del_fd(op->opaque->stdout_gsource);
525 op->opaque->stdout_gsource = NULL;
526 }
527 }
528
529
530
531
532
533
534
535
536
537
538
539 enum ocf_exitcode
540 services_result2ocf(const char *standard, const char *action, int exit_status)
541 {
542 if (pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_OCF, pcmk__str_casei)) {
543 return services__ocf2ocf(exit_status);
544
545 #if SUPPORT_SYSTEMD
546 } else if (pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_SYSTEMD,
547 pcmk__str_casei)) {
548 return services__systemd2ocf(exit_status);
549 #endif
550
551 #if PCMK__ENABLE_LSB
552 } else if (pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_LSB,
553 pcmk__str_casei)) {
554 return services__lsb2ocf(action, exit_status);
555 #endif
556
557 } else {
558 crm_warn("Treating result from unknown standard '%s' as OCF",
559 ((standard == NULL)? "unspecified" : standard));
560 return services__ocf2ocf(exit_status);
561 }
562 }
563
564 void
565 services_action_free(svc_action_t * op)
566 {
567 unsigned int i;
568
569 if (op == NULL) {
570 return;
571 }
572
573
574
575
576
577 CRM_CHECK(g_list_find(inflight_ops, op) == NULL, return);
578 CRM_CHECK(g_list_find(blocked_ops, op) == NULL, return);
579 CRM_CHECK((recurring_actions == NULL)
580 || (g_hash_table_lookup(recurring_actions, op->id) == NULL),
581 return);
582
583 services_action_cleanup(op);
584
585 if (op->opaque->repeat_timer) {
586 g_source_remove(op->opaque->repeat_timer);
587 op->opaque->repeat_timer = 0;
588 }
589
590 free(op->id);
591 free(op->opaque->exec);
592
593 for (i = 0; i < PCMK__NELEM(op->opaque->args); i++) {
594 free(op->opaque->args[i]);
595 }
596
597 free(op->opaque->exit_reason);
598 free(op->opaque);
599 free(op->rsc);
600 free(op->action);
601
602 free(op->standard);
603 free(op->agent);
604 free(op->provider);
605
606 free(op->stdout_data);
607 free(op->stderr_data);
608
609 if (op->params) {
610 g_hash_table_destroy(op->params);
611 op->params = NULL;
612 }
613
614 free(op);
615 }
616
617 gboolean
618 cancel_recurring_action(svc_action_t * op)
619 {
620 crm_info("Cancelling %s operation %s", op->standard, op->id);
621
622 if (recurring_actions) {
623 g_hash_table_remove(recurring_actions, op->id);
624 }
625
626 if (op->opaque->repeat_timer) {
627 g_source_remove(op->opaque->repeat_timer);
628 op->opaque->repeat_timer = 0;
629 }
630
631 return TRUE;
632 }
633
634
635
636
637
638
639
640
641
642
643 gboolean
644 services_action_cancel(const char *name, const char *action, guint interval_ms)
645 {
646 gboolean cancelled = FALSE;
647 char *id = pcmk__op_key(name, action, interval_ms);
648 svc_action_t *op = NULL;
649
650
651 init_recurring_actions();
652 op = g_hash_table_lookup(recurring_actions, id);
653 if (op == NULL) {
654 goto done;
655 }
656
657
658 op->cancel = TRUE;
659
660
661 cancel_recurring_action(op);
662
663
664
665
666
667
668
669 if (op->pid != 0) {
670 crm_info("Terminating in-flight op %s[%d] early because it was cancelled",
671 id, op->pid);
672 cancelled = mainloop_child_kill(op->pid);
673 if (cancelled == FALSE) {
674 crm_err("Termination of %s[%d] failed", id, op->pid);
675 }
676 goto done;
677 }
678
679 #if HAVE_DBUS
680
681 if (inflight_systemd(op)) {
682 inflight_ops = g_list_remove(inflight_ops, op);
683
684
685
686
687 services_action_cleanup(op);
688 }
689 #endif
690
691
692
693
694
695
696 services__set_cancelled(op);
697 if (op->opaque->callback) {
698 op->opaque->callback(op);
699 }
700
701 blocked_ops = g_list_remove(blocked_ops, op);
702 services_action_free(op);
703 cancelled = TRUE;
704
705
706 done:
707 free(id);
708 return cancelled;
709 }
710
711 gboolean
712 services_action_kick(const char *name, const char *action, guint interval_ms)
713 {
714 svc_action_t * op = NULL;
715 char *id = pcmk__op_key(name, action, interval_ms);
716
717 init_recurring_actions();
718 op = g_hash_table_lookup(recurring_actions, id);
719 free(id);
720
721 if (op == NULL) {
722 return FALSE;
723 }
724
725
726 if (op->pid || inflight_systemd(op)) {
727 return TRUE;
728 } else {
729 if (op->opaque->repeat_timer) {
730 g_source_remove(op->opaque->repeat_timer);
731 op->opaque->repeat_timer = 0;
732 }
733 recurring_action_timer(op);
734 return TRUE;
735 }
736
737 }
738
739
740
741
742
743
744
745
746
747 static gboolean
748 handle_duplicate_recurring(svc_action_t *op)
749 {
750 svc_action_t * dup = NULL;
751
752
753 dup = g_hash_table_lookup(recurring_actions, op->id);
754
755 if (dup && (dup != op)) {
756
757 if (op->opaque->callback) {
758 dup->opaque->callback = op->opaque->callback;
759 dup->cb_data = op->cb_data;
760 op->cb_data = NULL;
761 }
762
763 if (dup->pid != 0) {
764 if (op->opaque->repeat_timer) {
765 g_source_remove(op->opaque->repeat_timer);
766 op->opaque->repeat_timer = 0;
767 }
768 recurring_action_timer(dup);
769 }
770
771 services_action_free(op);
772 return TRUE;
773 }
774
775 return FALSE;
776 }
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794 static int
795 execute_action(svc_action_t *op)
796 {
797 #if SUPPORT_SYSTEMD
798 if (pcmk__str_eq(op->standard, PCMK_RESOURCE_CLASS_SYSTEMD,
799 pcmk__str_casei)) {
800 return services__execute_systemd(op);
801 }
802 #endif
803
804 return services__execute_file(op);
805 }
806
807 void
808 services_add_inflight_op(svc_action_t * op)
809 {
810 if (op == NULL) {
811 return;
812 }
813
814 pcmk__assert(op->synchronous == FALSE);
815
816
817 if (op->rsc) {
818 inflight_ops = g_list_append(inflight_ops, op);
819 }
820 }
821
822
823
824
825
826
827
828 void
829 services_untrack_op(const svc_action_t *op)
830 {
831
832 inflight_ops = g_list_remove(inflight_ops, op);
833 blocked_ops = g_list_remove(blocked_ops, op);
834
835
836 handle_blocked_ops();
837 }
838
839 gboolean
840 services_action_async_fork_notify(svc_action_t * op,
841 void (*action_callback) (svc_action_t *),
842 void (*action_fork_callback) (svc_action_t *))
843 {
844 CRM_CHECK(op != NULL, return TRUE);
845
846 op->synchronous = false;
847 if (action_callback != NULL) {
848 op->opaque->callback = action_callback;
849 }
850 if (action_fork_callback != NULL) {
851 op->opaque->fork_callback = action_fork_callback;
852 }
853
854 if (op->interval_ms > 0) {
855 init_recurring_actions();
856 if (handle_duplicate_recurring(op)) {
857
858
859 return TRUE;
860 }
861 g_hash_table_replace(recurring_actions, op->id, op);
862 }
863
864 if (!pcmk_is_set(op->flags, SVC_ACTION_NON_BLOCKED)
865 && op->rsc && is_op_blocked(op->rsc)) {
866 blocked_ops = g_list_append(blocked_ops, op);
867 return TRUE;
868 }
869
870 return execute_action(op) == pcmk_rc_ok;
871 }
872
873 gboolean
874 services_action_async(svc_action_t * op,
875 void (*action_callback) (svc_action_t *))
876 {
877 return services_action_async_fork_notify(op, action_callback, NULL);
878 }
879
880 static gboolean processing_blocked_ops = FALSE;
881
882 gboolean
883 is_op_blocked(const char *rsc)
884 {
885 GList *gIter = NULL;
886 svc_action_t *op = NULL;
887
888 for (gIter = inflight_ops; gIter != NULL; gIter = gIter->next) {
889 op = gIter->data;
890 if (pcmk__str_eq(op->rsc, rsc, pcmk__str_none)) {
891 return TRUE;
892 }
893 }
894
895 return FALSE;
896 }
897
898 static void
899 handle_blocked_ops(void)
900 {
901 GList *executed_ops = NULL;
902 GList *gIter = NULL;
903 svc_action_t *op = NULL;
904
905 if (processing_blocked_ops) {
906
907 return;
908 }
909
910 processing_blocked_ops = TRUE;
911
912
913
914 for (gIter = blocked_ops; gIter != NULL; gIter = gIter->next) {
915 op = gIter->data;
916 if (is_op_blocked(op->rsc)) {
917 continue;
918 }
919 executed_ops = g_list_append(executed_ops, op);
920 if (execute_action(op) != pcmk_rc_ok) {
921
922
923 services__finalize_async_op(op);
924 }
925 }
926
927 for (gIter = executed_ops; gIter != NULL; gIter = gIter->next) {
928 op = gIter->data;
929 blocked_ops = g_list_remove(blocked_ops, op);
930 }
931 g_list_free(executed_ops);
932
933 processing_blocked_ops = FALSE;
934 }
935
936
937
938
939
940
941
942
943
944 static int
945 execute_metadata_action(svc_action_t *op)
946 {
947 const char *class = op->standard;
948
949 if (op->agent == NULL) {
950 crm_info("Meta-data requested without specifying agent");
951 services__set_result(op, services__generic_error(op),
952 PCMK_EXEC_ERROR_FATAL, "Agent not specified");
953 return EINVAL;
954 }
955
956 if (class == NULL) {
957 crm_info("Meta-data requested for agent %s without specifying class",
958 op->agent);
959 services__set_result(op, services__generic_error(op),
960 PCMK_EXEC_ERROR_FATAL,
961 "Agent standard not specified");
962 return EINVAL;
963 }
964
965 #if PCMK__ENABLE_SERVICE
966 if (!strcmp(class, PCMK_RESOURCE_CLASS_SERVICE)) {
967 class = resources_find_service_class(op->agent);
968 }
969 if (class == NULL) {
970 crm_info("Meta-data requested for %s, but could not determine class",
971 op->agent);
972 services__set_result(op, services__generic_error(op),
973 PCMK_EXEC_ERROR_HARD,
974 "Agent standard could not be determined");
975 return EINVAL;
976 }
977 #endif
978
979 #if PCMK__ENABLE_LSB
980 if (pcmk__str_eq(class, PCMK_RESOURCE_CLASS_LSB, pcmk__str_casei)) {
981 return pcmk_legacy2rc(services__get_lsb_metadata(op->agent,
982 &op->stdout_data));
983 }
984 #endif
985
986 return execute_action(op);
987 }
988
989 gboolean
990 services_action_sync(svc_action_t * op)
991 {
992 gboolean rc = TRUE;
993
994 if (op == NULL) {
995 crm_trace("No operation to execute");
996 return FALSE;
997 }
998
999 op->synchronous = true;
1000
1001 if (pcmk__str_eq(op->action, PCMK_ACTION_META_DATA, pcmk__str_casei)) {
1002
1003
1004
1005
1006
1007
1008
1009 rc = (execute_metadata_action(op) == pcmk_rc_ok);
1010 } else {
1011 rc = (execute_action(op) == pcmk_rc_ok);
1012 }
1013 crm_trace(" > " PCMK__OP_FMT ": %s = %d",
1014 op->rsc, op->action, op->interval_ms, op->opaque->exec, op->rc);
1015 if (op->stdout_data) {
1016 crm_trace(" > stdout: %s", op->stdout_data);
1017 }
1018 if (op->stderr_data) {
1019 crm_trace(" > stderr: %s", op->stderr_data);
1020 }
1021 return rc;
1022 }
1023
1024 GList *
1025 get_directory_list(const char *root, gboolean files, gboolean executable)
1026 {
1027 return services_os_get_directory_list(root, files, executable);
1028 }
1029
1030 GList *
1031 resources_list_standards(void)
1032 {
1033 GList *standards = NULL;
1034
1035 standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_OCF));
1036
1037 #if PCMK__ENABLE_SERVICE
1038 standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_SERVICE));
1039 #endif
1040
1041 #if PCMK__ENABLE_LSB
1042 standards = g_list_append(standards, strdup(PCMK_RESOURCE_CLASS_LSB));
1043 #endif
1044
1045 #if SUPPORT_SYSTEMD
1046 {
1047 GList *agents = systemd_unit_listall();
1048
1049 if (agents != NULL) {
1050 standards = g_list_append(standards,
1051 strdup(PCMK_RESOURCE_CLASS_SYSTEMD));
1052 g_list_free_full(agents, free);
1053 }
1054 }
1055 #endif
1056
1057 return standards;
1058 }
1059
1060 GList *
1061 resources_list_providers(const char *standard)
1062 {
1063 if (pcmk_is_set(pcmk_get_ra_caps(standard), pcmk_ra_cap_provider)) {
1064 return resources_os_list_ocf_providers();
1065 }
1066
1067 return NULL;
1068 }
1069
1070 GList *
1071 resources_list_agents(const char *standard, const char *provider)
1072 {
1073 if ((standard == NULL)
1074 #if PCMK__ENABLE_SERVICE
1075 || (strcasecmp(standard, PCMK_RESOURCE_CLASS_SERVICE) == 0)
1076 #endif
1077 ) {
1078
1079 GList *tmp1;
1080 GList *tmp2;
1081 GList *result = NULL;
1082
1083 if (standard == NULL) {
1084 tmp1 = result;
1085 tmp2 = resources_os_list_ocf_agents(NULL);
1086 if (tmp2) {
1087 result = g_list_concat(tmp1, tmp2);
1088 }
1089 }
1090
1091 #if PCMK__ENABLE_LSB
1092 result = g_list_concat(result, services__list_lsb_agents());
1093 #endif
1094
1095 #if SUPPORT_SYSTEMD
1096 tmp1 = result;
1097 tmp2 = systemd_unit_listall();
1098 if (tmp2) {
1099 result = g_list_concat(tmp1, tmp2);
1100 }
1101 #endif
1102
1103 return result;
1104
1105 } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_OCF) == 0) {
1106 return resources_os_list_ocf_agents(provider);
1107 #if PCMK__ENABLE_LSB
1108 } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_LSB) == 0) {
1109 return services__list_lsb_agents();
1110 #endif
1111 #if SUPPORT_SYSTEMD
1112 } else if (strcasecmp(standard, PCMK_RESOURCE_CLASS_SYSTEMD) == 0) {
1113 return systemd_unit_listall();
1114 #endif
1115 }
1116
1117 return NULL;
1118 }
1119
1120 gboolean
1121 resources_agent_exists(const char *standard, const char *provider, const char *agent)
1122 {
1123 GList *standards = NULL;
1124 GList *providers = NULL;
1125 GList *iter = NULL;
1126 gboolean rc = FALSE;
1127 gboolean has_providers = FALSE;
1128
1129 standards = resources_list_standards();
1130 for (iter = standards; iter != NULL; iter = iter->next) {
1131 if (pcmk__str_eq(iter->data, standard, pcmk__str_none)) {
1132 rc = TRUE;
1133 break;
1134 }
1135 }
1136
1137 if (rc == FALSE) {
1138 goto done;
1139 }
1140
1141 rc = FALSE;
1142
1143 has_providers = pcmk_is_set(pcmk_get_ra_caps(standard), pcmk_ra_cap_provider);
1144 if (has_providers == TRUE && provider != NULL) {
1145 providers = resources_list_providers(standard);
1146 for (iter = providers; iter != NULL; iter = iter->next) {
1147 if (pcmk__str_eq(iter->data, provider, pcmk__str_none)) {
1148 rc = TRUE;
1149 break;
1150 }
1151 }
1152 } else if (has_providers == FALSE && provider == NULL) {
1153 rc = TRUE;
1154 }
1155
1156 if (rc == FALSE) {
1157 goto done;
1158 }
1159
1160 #if PCMK__ENABLE_SERVICE
1161 if (pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_SERVICE, pcmk__str_casei)) {
1162 #if PCMK__ENABLE_LSB
1163 if (services__lsb_agent_exists(agent)) {
1164 rc = TRUE;
1165 goto done;
1166 }
1167 #endif
1168 #if SUPPORT_SYSTEMD
1169 if (systemd_unit_exists(agent)) {
1170 rc = TRUE;
1171 goto done;
1172 }
1173 #endif
1174 rc = FALSE;
1175 goto done;
1176 }
1177 #endif
1178
1179 if (pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_OCF, pcmk__str_casei)) {
1180 rc = services__ocf_agent_exists(provider, agent);
1181
1182 #if PCMK__ENABLE_LSB
1183 } else if (pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_LSB, pcmk__str_casei)) {
1184 rc = services__lsb_agent_exists(agent);
1185 #endif
1186
1187 #if SUPPORT_SYSTEMD
1188 } else if (pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_SYSTEMD, pcmk__str_casei)) {
1189 rc = systemd_unit_exists(agent);
1190 #endif
1191
1192 } else {
1193 rc = FALSE;
1194 }
1195
1196 done:
1197 g_list_free(standards);
1198 g_list_free(providers);
1199 return rc;
1200 }
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211 void
1212 services__set_result(svc_action_t *action, int agent_status,
1213 enum pcmk_exec_status exec_status, const char *reason)
1214 {
1215 if (action == NULL) {
1216 return;
1217 }
1218
1219 action->rc = agent_status;
1220 action->status = exec_status;
1221
1222 if (!pcmk__str_eq(action->opaque->exit_reason, reason,
1223 pcmk__str_none)) {
1224 free(action->opaque->exit_reason);
1225 action->opaque->exit_reason = (reason == NULL)? NULL : strdup(reason);
1226 }
1227 }
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240 void
1241 services__format_result(svc_action_t *action, int agent_status,
1242 enum pcmk_exec_status exec_status,
1243 const char *format, ...)
1244 {
1245 va_list ap;
1246 int len = 0;
1247 char *reason = NULL;
1248
1249 if (action == NULL) {
1250 return;
1251 }
1252
1253 action->rc = agent_status;
1254 action->status = exec_status;
1255
1256 if (format != NULL) {
1257 va_start(ap, format);
1258 len = vasprintf(&reason, format, ap);
1259 pcmk__assert(len > 0);
1260 va_end(ap);
1261 }
1262 free(action->opaque->exit_reason);
1263 action->opaque->exit_reason = reason;
1264 }
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274 void
1275 services__set_cancelled(svc_action_t *action)
1276 {
1277 if (action != NULL) {
1278 action->status = PCMK_EXEC_CANCELLED;
1279 free(action->opaque->exit_reason);
1280 action->opaque->exit_reason = NULL;
1281 }
1282 }
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292 const char *
1293 services__action_kind(const svc_action_t *action)
1294 {
1295 if ((action == NULL) || (action->standard == NULL)) {
1296 return "Process";
1297 } else if (pcmk__str_eq(action->standard, PCMK_RESOURCE_CLASS_STONITH,
1298 pcmk__str_none)) {
1299 return "Fence agent";
1300 } else if (pcmk__str_eq(action->standard, PCMK_RESOURCE_CLASS_ALERT,
1301 pcmk__str_none)) {
1302 return "Alert agent";
1303 } else {
1304 return "Resource agent";
1305 }
1306 }
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316 const char *
1317 services__exit_reason(const svc_action_t *action)
1318 {
1319 return action->opaque->exit_reason;
1320 }
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332 char *
1333 services__grab_stdout(svc_action_t *action)
1334 {
1335 char *output = action->stdout_data;
1336
1337 action->stdout_data = NULL;
1338 return output;
1339 }
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351 char *
1352 services__grab_stderr(svc_action_t *action)
1353 {
1354 char *output = action->stderr_data;
1355
1356 action->stderr_data = NULL;
1357 return output;
1358 }