This source file includes following definitions.
- services__systemd_prepare
- services__systemd2ocf
- systemd_new_method
- systemd_send
- systemd_send_recv
- systemd_call_simple_method
- systemd_init
- systemd_get_property
- systemd_cleanup
- systemd_unit_extension
- systemd_service_name
- systemd_daemon_reload_complete
- systemd_daemon_reload
- set_result_from_method_error
- execute_after_loadunit
- loadunit_completed
- invoke_unit_by_name
- sort_str
- systemd_unit_listall
- systemd_unit_exists
- systemd_unit_metadata
- process_unit_method_reply
- unit_method_complete
- create_world_readable
- create_override_dir
- get_override_filename
- systemd_create_override
- systemd_remove_override
- parse_status_result
- invoke_unit_by_path
- systemd_timeout_callback
- services__execute_systemd
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11 #include <crm/crm.h>
12 #include <crm/services.h>
13 #include <crm/services_internal.h>
14 #include <crm/common/mainloop.h>
15
16 #include <sys/stat.h>
17 #include <gio/gio.h>
18 #include <services_private.h>
19 #include <systemd.h>
20 #include <dbus/dbus.h>
21 #include <pcmk-dbus.h>
22
23 static void invoke_unit_by_path(svc_action_t *op, const char *unit);
24
25 #define BUS_NAME "org.freedesktop.systemd1"
26 #define BUS_NAME_MANAGER BUS_NAME ".Manager"
27 #define BUS_NAME_UNIT BUS_NAME ".Unit"
28 #define BUS_PATH "/org/freedesktop/systemd1"
29
30
31
32
33
34
35
36
37
38 int
39 services__systemd_prepare(svc_action_t *op)
40 {
41 op->opaque->exec = strdup("systemd-dbus");
42 if (op->opaque->exec == NULL) {
43 return ENOMEM;
44 }
45 return pcmk_rc_ok;
46 }
47
48
49
50
51
52
53
54
55
56 enum ocf_exitcode
57 services__systemd2ocf(int exit_status)
58 {
59
60 return (enum ocf_exitcode) exit_status;
61 }
62
63 static inline DBusMessage *
64 systemd_new_method(const char *method)
65 {
66 crm_trace("Calling: %s on " BUS_NAME_MANAGER, method);
67 return dbus_message_new_method_call(BUS_NAME, BUS_PATH, BUS_NAME_MANAGER,
68 method);
69 }
70
71
72
73
74
75 static DBusConnection* systemd_proxy = NULL;
76
77 static inline DBusPendingCall *
78 systemd_send(DBusMessage *msg,
79 void(*done)(DBusPendingCall *pending, void *user_data),
80 void *user_data, int timeout)
81 {
82 return pcmk_dbus_send(msg, systemd_proxy, done, user_data, timeout);
83 }
84
85 static inline DBusMessage *
86 systemd_send_recv(DBusMessage *msg, DBusError *error, int timeout)
87 {
88 return pcmk_dbus_send_recv(msg, systemd_proxy, error, timeout);
89 }
90
91
92
93
94
95
96
97
98
99
100
101
102 static DBusMessage *
103 systemd_call_simple_method(const char *method)
104 {
105 DBusMessage *msg = systemd_new_method(method);
106 DBusMessage *reply = NULL;
107 DBusError error;
108
109
110 CRM_CHECK(systemd_proxy, return NULL);
111
112 if (msg == NULL) {
113 crm_err("Could not create message to send %s to systemd", method);
114 return NULL;
115 }
116
117 dbus_error_init(&error);
118 reply = systemd_send_recv(msg, &error, DBUS_TIMEOUT_USE_DEFAULT);
119 dbus_message_unref(msg);
120
121 if (dbus_error_is_set(&error)) {
122 crm_err("Could not send %s to systemd: %s (%s)",
123 method, error.message, error.name);
124 dbus_error_free(&error);
125 return NULL;
126
127 } else if (reply == NULL) {
128 crm_err("Could not send %s to systemd: no reply received", method);
129 return NULL;
130 }
131
132 return reply;
133 }
134
135 static gboolean
136 systemd_init(void)
137 {
138 static int need_init = 1;
139
140
141 if (systemd_proxy
142 && dbus_connection_get_is_connected(systemd_proxy) == FALSE) {
143 crm_warn("Connection to System DBus is closed. Reconnecting...");
144 pcmk_dbus_disconnect(systemd_proxy);
145 systemd_proxy = NULL;
146 need_init = 1;
147 }
148
149 if (need_init) {
150 need_init = 0;
151 systemd_proxy = pcmk_dbus_connect();
152 }
153 if (systemd_proxy == NULL) {
154 return FALSE;
155 }
156 return TRUE;
157 }
158
159 static inline char *
160 systemd_get_property(const char *unit, const char *name,
161 void (*callback)(const char *name, const char *value, void *userdata),
162 void *userdata, DBusPendingCall **pending, int timeout)
163 {
164 return systemd_proxy?
165 pcmk_dbus_get_property(systemd_proxy, BUS_NAME, unit, BUS_NAME_UNIT,
166 name, callback, userdata, pending, timeout)
167 : NULL;
168 }
169
170 void
171 systemd_cleanup(void)
172 {
173 if (systemd_proxy) {
174 pcmk_dbus_disconnect(systemd_proxy);
175 systemd_proxy = NULL;
176 }
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191 static const char *
192 systemd_unit_extension(const char *name)
193 {
194 if (name) {
195 const char *dot = strrchr(name, '.');
196
197 if (dot && (!strcmp(dot, ".service")
198 || !strcmp(dot, ".socket")
199 || !strcmp(dot, ".mount")
200 || !strcmp(dot, ".timer")
201 || !strcmp(dot, ".path"))) {
202 return dot;
203 }
204 }
205 return NULL;
206 }
207
208 static char *
209 systemd_service_name(const char *name, bool add_instance_name)
210 {
211 const char *dot = NULL;
212
213 if (pcmk__str_empty(name)) {
214 return NULL;
215 }
216
217
218
219
220
221
222
223
224
225
226 dot = systemd_unit_extension(name);
227
228 if (dot) {
229 if (dot != name && *(dot-1) == '@') {
230 char *s = NULL;
231
232 if (asprintf(&s, "%.*spacemaker%s", (int) (dot-name), name, dot) == -1) {
233
234 return strdup(name);
235 }
236
237 return s;
238 } else {
239 return strdup(name);
240 }
241
242 } else if (add_instance_name && *(name+strlen(name)-1) == '@') {
243 return crm_strdup_printf("%spacemaker.service", name);
244
245 } else {
246 return crm_strdup_printf("%s.service", name);
247 }
248 }
249
250 static void
251 systemd_daemon_reload_complete(DBusPendingCall *pending, void *user_data)
252 {
253 DBusError error;
254 DBusMessage *reply = NULL;
255 unsigned int reload_count = GPOINTER_TO_UINT(user_data);
256
257 dbus_error_init(&error);
258 if(pending) {
259 reply = dbus_pending_call_steal_reply(pending);
260 }
261
262 if (pcmk_dbus_find_error(pending, reply, &error)) {
263 crm_warn("Could not issue systemd reload %d: %s",
264 reload_count, error.message);
265 dbus_error_free(&error);
266
267 } else {
268 crm_trace("Reload %d complete", reload_count);
269 }
270
271 if(pending) {
272 dbus_pending_call_unref(pending);
273 }
274 if(reply) {
275 dbus_message_unref(reply);
276 }
277 }
278
279 static bool
280 systemd_daemon_reload(int timeout)
281 {
282 static unsigned int reload_count = 0;
283 DBusMessage *msg = systemd_new_method("Reload");
284
285 reload_count++;
286 CRM_ASSERT(msg != NULL);
287 systemd_send(msg, systemd_daemon_reload_complete,
288 GUINT_TO_POINTER(reload_count), timeout);
289 dbus_message_unref(msg);
290
291 return TRUE;
292 }
293
294
295
296
297
298
299
300
301 static void
302 set_result_from_method_error(svc_action_t *op, const DBusError *error)
303 {
304 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
305 "Unable to invoke systemd DBus method");
306
307 if (strstr(error->name, "org.freedesktop.systemd1.InvalidName")
308 || strstr(error->name, "org.freedesktop.systemd1.LoadFailed")
309 || strstr(error->name, "org.freedesktop.systemd1.NoSuchUnit")) {
310
311 if (pcmk__str_eq(op->action, "stop", pcmk__str_casei)) {
312 crm_trace("Masking systemd stop failure (%s) for %s "
313 "because unknown service can be considered stopped",
314 error->name, pcmk__s(op->rsc, "unknown resource"));
315 services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
316 return;
317 }
318
319 services__format_result(op, PCMK_OCF_NOT_INSTALLED,
320 PCMK_EXEC_NOT_INSTALLED,
321 "systemd unit %s not found", op->agent);
322 }
323
324 crm_info("DBus request for %s of systemd unit %s%s%s failed: %s",
325 op->action, op->agent,
326 ((op->rsc == NULL)? "" : " for resource "), pcmk__s(op->rsc, ""),
327 error->message);
328 }
329
330
331
332
333
334
335
336
337
338
339
340 static const char *
341 execute_after_loadunit(DBusMessage *reply, svc_action_t *op)
342 {
343 const char *path = NULL;
344 DBusError error;
345
346
347
348
349 if (pcmk_dbus_find_error((void *) &path, reply, &error)) {
350 if (op != NULL) {
351 set_result_from_method_error(op, &error);
352 }
353 dbus_error_free(&error);
354
355 } else if (!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH,
356 __func__, __LINE__)) {
357 if (op != NULL) {
358 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
359 "systemd DBus method had unexpected reply");
360 crm_info("Could not load systemd unit %s for %s: "
361 "DBus reply has unexpected type", op->agent, op->id);
362 } else {
363 crm_info("Could not load systemd unit: "
364 "DBus reply has unexpected type");
365 }
366
367 } else {
368 dbus_message_get_args (reply, NULL,
369 DBUS_TYPE_OBJECT_PATH, &path,
370 DBUS_TYPE_INVALID);
371 }
372
373 if (op != NULL) {
374 if (path != NULL) {
375 invoke_unit_by_path(op, path);
376
377 } else if (!(op->synchronous)) {
378 services__format_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
379 "No DBus object found for systemd unit %s",
380 op->agent);
381 services__finalize_async_op(op);
382 }
383 }
384
385 return path;
386 }
387
388
389
390
391
392
393
394
395 static void
396 loadunit_completed(DBusPendingCall *pending, void *user_data)
397 {
398 DBusMessage *reply = NULL;
399 svc_action_t *op = user_data;
400
401 crm_trace("LoadUnit result for %s arrived", op->id);
402
403
404 if (pending != NULL) {
405 reply = dbus_pending_call_steal_reply(pending);
406 }
407
408
409 CRM_LOG_ASSERT(pending == op->opaque->pending);
410 services_set_op_pending(op, NULL);
411
412
413 execute_after_loadunit(reply, user_data);
414 if (reply != NULL) {
415 dbus_message_unref(reply);
416 }
417 }
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434 static int
435 invoke_unit_by_name(const char *arg_name, svc_action_t *op, char **path)
436 {
437 DBusMessage *msg;
438 DBusMessage *reply = NULL;
439 DBusPendingCall *pending = NULL;
440 char *name = NULL;
441
442 if (!systemd_init()) {
443 if (op != NULL) {
444 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
445 "No DBus connection");
446 }
447 return ENOTCONN;
448 }
449
450
451
452
453
454
455
456
457
458 msg = systemd_new_method("LoadUnit");
459 CRM_ASSERT(msg != NULL);
460
461
462 name = systemd_service_name(arg_name, op == NULL || pcmk__str_eq(op->action, "meta-data", pcmk__str_none));
463 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
464 DBUS_TYPE_INVALID));
465 free(name);
466
467 if ((op == NULL) || op->synchronous) {
468
469 const char *unit = NULL;
470 int rc = pcmk_rc_ok;
471
472 reply = systemd_send_recv(msg, NULL,
473 (op? op->timeout : DBUS_TIMEOUT_USE_DEFAULT));
474 dbus_message_unref(msg);
475
476 unit = execute_after_loadunit(reply, op);
477 if (unit == NULL) {
478 rc = ENOENT;
479 if (path != NULL) {
480 *path = NULL;
481 }
482 } else if (path != NULL) {
483 *path = strdup(unit);
484 if (*path == NULL) {
485 rc = ENOMEM;
486 }
487 }
488
489 if (reply != NULL) {
490 dbus_message_unref(reply);
491 }
492 return rc;
493 }
494
495
496 pending = systemd_send(msg, loadunit_completed, op, op->timeout);
497 if (pending == NULL) {
498 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
499 "Unable to send DBus message");
500 dbus_message_unref(msg);
501 return ECOMM;
502 }
503
504
505 services__set_result(op, PCMK_OCF_UNKNOWN, PCMK_EXEC_PENDING, NULL);
506 services_set_op_pending(op, pending);
507 dbus_message_unref(msg);
508 return pcmk_rc_ok;
509 }
510
511
512
513
514
515
516
517
518
519
520
521
522
523 static gint
524 sort_str(gconstpointer a, gconstpointer b)
525 {
526 if (!a && !b) {
527 return 0;
528 } else if (!a) {
529 return -1;
530 } else if (!b) {
531 return 1;
532 }
533 return strcasecmp(a, b);
534 }
535
536 GList *
537 systemd_unit_listall(void)
538 {
539 int nfiles = 0;
540 GList *units = NULL;
541 DBusMessageIter args;
542 DBusMessageIter unit;
543 DBusMessageIter elem;
544 DBusMessage *reply = NULL;
545
546 if (systemd_init() == FALSE) {
547 return NULL;
548 }
549
550
551
552
553
554
555
556 reply = systemd_call_simple_method("ListUnitFiles");
557 if (reply == NULL) {
558 return NULL;
559 }
560 if (!dbus_message_iter_init(reply, &args)) {
561 crm_err("Could not list systemd unit files: systemd reply has no arguments");
562 dbus_message_unref(reply);
563 return NULL;
564 }
565 if (!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY,
566 __func__, __LINE__)) {
567 crm_err("Could not list systemd unit files: systemd reply has invalid arguments");
568 dbus_message_unref(reply);
569 return NULL;
570 }
571
572 dbus_message_iter_recurse(&args, &unit);
573 for (; dbus_message_iter_get_arg_type(&unit) != DBUS_TYPE_INVALID;
574 dbus_message_iter_next(&unit)) {
575
576 DBusBasicValue value;
577 const char *match = NULL;
578 char *unit_name = NULL;
579 char *basename = NULL;
580
581 if(!pcmk_dbus_type_check(reply, &unit, DBUS_TYPE_STRUCT, __func__, __LINE__)) {
582 crm_warn("Skipping systemd reply argument with unexpected type");
583 continue;
584 }
585
586 dbus_message_iter_recurse(&unit, &elem);
587 if(!pcmk_dbus_type_check(reply, &elem, DBUS_TYPE_STRING, __func__, __LINE__)) {
588 crm_warn("Skipping systemd reply argument with no string");
589 continue;
590 }
591
592 dbus_message_iter_get_basic(&elem, &value);
593 if (value.str == NULL) {
594 crm_debug("ListUnitFiles reply did not provide a string");
595 continue;
596 }
597 crm_trace("DBus ListUnitFiles listed: %s", value.str);
598
599 match = systemd_unit_extension(value.str);
600 if (match == NULL) {
601
602 crm_debug("ListUnitFiles entry '%s' is not supported as resource",
603 value.str);
604 continue;
605 }
606
607
608 basename = strrchr(value.str, '/');
609 if (basename) {
610 basename = basename + 1;
611 } else {
612 basename = value.str;
613 }
614
615 if (!strcmp(match, ".service")) {
616
617 unit_name = strndup(basename, match - basename);
618 } else {
619 unit_name = strdup(basename);
620 }
621
622 nfiles++;
623 units = g_list_prepend(units, unit_name);
624 }
625
626 dbus_message_unref(reply);
627
628 crm_trace("Found %d manageable systemd unit files", nfiles);
629 units = g_list_sort(units, sort_str);
630 return units;
631 }
632
633 gboolean
634 systemd_unit_exists(const char *name)
635 {
636 char *path = NULL;
637 char *state = NULL;
638
639
640
641
642 if ((invoke_unit_by_name(name, NULL, &path) != pcmk_rc_ok)
643 || (path == NULL)) {
644 return FALSE;
645 }
646
647
648
649
650
651 state = systemd_get_property(path, "LoadState", NULL, NULL, NULL,
652 DBUS_TIMEOUT_USE_DEFAULT);
653 free(path);
654 if (pcmk__str_any_of(state, "loaded", "masked", NULL)) {
655 free(state);
656 return TRUE;
657 }
658 free(state);
659 return FALSE;
660 }
661
662 #define METADATA_FORMAT \
663 "<?xml version=\"1.0\"?>\n" \
664 "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n" \
665 "<resource-agent name=\"%s\" version=\"" PCMK_DEFAULT_AGENT_VERSION "\">\n" \
666 " <version>1.1</version>\n" \
667 " <longdesc lang=\"en\">\n" \
668 " %s\n" \
669 " </longdesc>\n" \
670 " <shortdesc lang=\"en\">systemd unit file for %s</shortdesc>\n" \
671 " <parameters/>\n" \
672 " <actions>\n" \
673 " <action name=\"start\" timeout=\"100\" />\n" \
674 " <action name=\"stop\" timeout=\"100\" />\n" \
675 " <action name=\"status\" timeout=\"100\" />\n" \
676 " <action name=\"monitor\" timeout=\"100\" interval=\"60\"/>\n" \
677 " <action name=\"meta-data\" timeout=\"5\" />\n" \
678 " </actions>\n" \
679 " <special tag=\"systemd\"/>\n" \
680 "</resource-agent>\n"
681
682 static char *
683 systemd_unit_metadata(const char *name, int timeout)
684 {
685 char *meta = NULL;
686 char *desc = NULL;
687 char *path = NULL;
688
689 char *escaped = NULL;
690
691 if (invoke_unit_by_name(name, NULL, &path) == pcmk_rc_ok) {
692
693 desc = systemd_get_property(path, "Description", NULL, NULL, NULL,
694 timeout);
695 } else {
696 desc = crm_strdup_printf("Systemd unit file for %s", name);
697 }
698
699 escaped = crm_xml_escape(desc);
700
701 meta = crm_strdup_printf(METADATA_FORMAT, name, escaped, name);
702 free(desc);
703 free(path);
704 free(escaped);
705 return meta;
706 }
707
708
709
710
711
712
713
714
715 static void
716 process_unit_method_reply(DBusMessage *reply, svc_action_t *op)
717 {
718 DBusError error;
719
720
721
722
723 if (pcmk_dbus_find_error((void *) &error, reply, &error)) {
724 set_result_from_method_error(op, &error);
725 dbus_error_free(&error);
726
727 } else if (!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH,
728 __func__, __LINE__)) {
729 crm_info("DBus request for %s of %s succeeded but "
730 "return type was unexpected",
731 op->action, pcmk__s(op->rsc, "unknown resource"));
732 services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE,
733 "systemd DBus method had unexpected reply");
734
735 } else {
736 const char *path = NULL;
737
738 dbus_message_get_args(reply, NULL,
739 DBUS_TYPE_OBJECT_PATH, &path,
740 DBUS_TYPE_INVALID);
741 crm_debug("DBus request for %s of %s using %s succeeded",
742 op->action, pcmk__s(op->rsc, "unknown resource"), path);
743 services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
744 }
745 }
746
747
748
749
750
751
752
753
754 static void
755 unit_method_complete(DBusPendingCall *pending, void *user_data)
756 {
757 DBusMessage *reply = NULL;
758 svc_action_t *op = user_data;
759
760 crm_trace("Result for %s arrived", op->id);
761
762
763 if (pending != NULL) {
764 reply = dbus_pending_call_steal_reply(pending);
765 }
766
767
768 CRM_LOG_ASSERT(pending == op->opaque->pending);
769 services_set_op_pending(op, NULL);
770
771
772 process_unit_method_reply(reply, op);
773 services__finalize_async_op(op);
774 if (reply != NULL) {
775 dbus_message_unref(reply);
776 }
777 }
778
779 #define SYSTEMD_OVERRIDE_ROOT "/run/systemd/system/"
780
781
782
783
784
785
786
787
788
789
790 #define SYSTEMD_OVERRIDE_TEMPLATE \
791 "[Unit]\n" \
792 "Description=Cluster Controlled %s\n" \
793 "Before=pacemaker.service pacemaker_remote.service\n" \
794 "\n" \
795 "[Service]\n" \
796 "Restart=no\n"
797
798
799 static FILE *
800 create_world_readable(const char *filename)
801 {
802 mode_t orig_umask = umask(S_IWGRP | S_IWOTH);
803 FILE *fp = fopen(filename, "w");
804
805 umask(orig_umask);
806 return fp;
807 }
808
809 static void
810 create_override_dir(const char *agent)
811 {
812 char *override_dir = crm_strdup_printf(SYSTEMD_OVERRIDE_ROOT
813 "/%s.service.d", agent);
814 int rc = pcmk__build_path(override_dir, 0755);
815
816 if (rc != pcmk_rc_ok) {
817 crm_warn("Could not create systemd override directory %s: %s",
818 override_dir, pcmk_rc_str(rc));
819 }
820 free(override_dir);
821 }
822
823 static char *
824 get_override_filename(const char *agent)
825 {
826 return crm_strdup_printf(SYSTEMD_OVERRIDE_ROOT
827 "/%s.service.d/50-pacemaker.conf", agent);
828 }
829
830 static void
831 systemd_create_override(const char *agent, int timeout)
832 {
833 FILE *file_strm = NULL;
834 char *override_file = get_override_filename(agent);
835
836 create_override_dir(agent);
837
838
839
840
841 file_strm = create_world_readable(override_file);
842 if (file_strm == NULL) {
843 crm_err("Cannot open systemd override file %s for writing",
844 override_file);
845 } else {
846 char *override = crm_strdup_printf(SYSTEMD_OVERRIDE_TEMPLATE, agent);
847
848 int rc = fprintf(file_strm, "%s\n", override);
849
850 free(override);
851 if (rc < 0) {
852 crm_perror(LOG_WARNING, "Cannot write to systemd override file %s",
853 override_file);
854 }
855 fflush(file_strm);
856 fclose(file_strm);
857 systemd_daemon_reload(timeout);
858 }
859
860 free(override_file);
861 }
862
863 static void
864 systemd_remove_override(const char *agent, int timeout)
865 {
866 char *override_file = get_override_filename(agent);
867 int rc = unlink(override_file);
868
869 if (rc < 0) {
870
871 crm_perror(LOG_DEBUG, "Cannot remove systemd override file %s",
872 override_file);
873 } else {
874 systemd_daemon_reload(timeout);
875 }
876 free(override_file);
877 }
878
879
880
881
882
883
884
885
886
887
888
889
890 static void
891 parse_status_result(const char *name, const char *state, void *userdata)
892 {
893 svc_action_t *op = userdata;
894
895 crm_trace("Resource %s has %s='%s'",
896 pcmk__s(op->rsc, "(unspecified)"), name,
897 pcmk__s(state, "<null>"));
898
899 if (pcmk__str_eq(state, "active", pcmk__str_none)) {
900 services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
901
902 } else if (pcmk__str_eq(state, "reloading", pcmk__str_none)) {
903 services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
904
905 } else if (pcmk__str_eq(state, "activating", pcmk__str_none)) {
906 services__set_result(op, PCMK_OCF_UNKNOWN, PCMK_EXEC_PENDING, NULL);
907
908 } else if (pcmk__str_eq(state, "deactivating", pcmk__str_none)) {
909 services__set_result(op, PCMK_OCF_UNKNOWN, PCMK_EXEC_PENDING, NULL);
910
911 } else {
912 services__set_result(op, PCMK_OCF_NOT_RUNNING, PCMK_EXEC_DONE, state);
913 }
914
915 if (!(op->synchronous)) {
916 services_set_op_pending(op, NULL);
917 services__finalize_async_op(op);
918 }
919 }
920
921
922
923
924
925
926
927
928 static void
929 invoke_unit_by_path(svc_action_t *op, const char *unit)
930 {
931 const char *method = NULL;
932 DBusMessage *msg = NULL;
933 DBusMessage *reply = NULL;
934
935 if (pcmk__str_any_of(op->action, "monitor", "status", NULL)) {
936 DBusPendingCall *pending = NULL;
937 char *state;
938
939 state = systemd_get_property(unit, "ActiveState",
940 (op->synchronous? NULL : parse_status_result),
941 op, (op->synchronous? NULL : &pending),
942 op->timeout);
943 if (op->synchronous) {
944 parse_status_result("ActiveState", state, op);
945 free(state);
946
947 } else if (pending == NULL) {
948 services__format_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
949 "Could not get state for unit %s from DBus",
950 op->agent);
951 services__finalize_async_op(op);
952
953 } else {
954 services_set_op_pending(op, pending);
955 }
956 return;
957
958 } else if (pcmk__str_eq(op->action, "start", pcmk__str_none)) {
959 method = "StartUnit";
960 systemd_create_override(op->agent, op->timeout);
961
962 } else if (pcmk__str_eq(op->action, "stop", pcmk__str_none)) {
963 method = "StopUnit";
964 systemd_remove_override(op->agent, op->timeout);
965
966 } else if (pcmk__str_eq(op->action, "restart", pcmk__str_none)) {
967 method = "RestartUnit";
968
969 } else {
970 services__format_result(op, PCMK_OCF_UNIMPLEMENT_FEATURE,
971 PCMK_EXEC_ERROR,
972 "Action %s not implemented "
973 "for systemd resources",
974 pcmk__s(op->action, "(unspecified)"));
975 if (!(op->synchronous)) {
976 services__finalize_async_op(op);
977 }
978 return;
979 }
980
981 crm_trace("Calling %s for unit path %s%s%s",
982 method, unit,
983 ((op->rsc == NULL)? "" : " for resource "), pcmk__s(op->rsc, ""));
984
985 msg = systemd_new_method(method);
986 CRM_ASSERT(msg != NULL);
987
988
989 {
990 const char *replace_s = "replace";
991 char *name = systemd_service_name(op->agent, pcmk__str_eq(op->action, "meta-data", pcmk__str_none));
992
993 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
994 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &replace_s, DBUS_TYPE_INVALID));
995
996 free(name);
997 }
998
999 if (op->synchronous) {
1000 reply = systemd_send_recv(msg, NULL, op->timeout);
1001 dbus_message_unref(msg);
1002 process_unit_method_reply(reply, op);
1003 if (reply != NULL) {
1004 dbus_message_unref(reply);
1005 }
1006
1007 } else {
1008 DBusPendingCall *pending = systemd_send(msg, unit_method_complete, op,
1009 op->timeout);
1010
1011 dbus_message_unref(msg);
1012 if (pending == NULL) {
1013 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
1014 "Unable to send DBus message");
1015 services__finalize_async_op(op);
1016
1017 } else {
1018 services_set_op_pending(op, pending);
1019 }
1020 }
1021 }
1022
1023 static gboolean
1024 systemd_timeout_callback(gpointer p)
1025 {
1026 svc_action_t * op = p;
1027
1028 op->opaque->timerid = 0;
1029 crm_info("%s action for systemd unit %s named '%s' timed out",
1030 op->action, op->agent, op->rsc);
1031 services__format_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_TIMEOUT,
1032 "%s action for systemd unit %s "
1033 "did not complete in time", op->action, op->agent);
1034 services__finalize_async_op(op);
1035 return FALSE;
1036 }
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054 int
1055 services__execute_systemd(svc_action_t *op)
1056 {
1057 CRM_ASSERT(op != NULL);
1058
1059 if ((op->action == NULL) || (op->agent == NULL)) {
1060 services__set_result(op, PCMK_OCF_NOT_CONFIGURED, PCMK_EXEC_ERROR_FATAL,
1061 "Bug in action caller");
1062 goto done;
1063 }
1064
1065 if (!systemd_init()) {
1066 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
1067 "No DBus connection");
1068 goto done;
1069 }
1070
1071 crm_debug("Performing %ssynchronous %s op on systemd unit %s%s%s",
1072 (op->synchronous? "" : "a"), op->action, op->agent,
1073 ((op->rsc == NULL)? "" : " for resource "), pcmk__s(op->rsc, ""));
1074
1075 if (pcmk__str_eq(op->action, "meta-data", pcmk__str_casei)) {
1076 op->stdout_data = systemd_unit_metadata(op->agent, op->timeout);
1077 services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
1078 goto done;
1079 }
1080
1081
1082
1083
1084 services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
1085 "Bug in service library");
1086
1087 if (invoke_unit_by_name(op->agent, op, NULL) == pcmk_rc_ok) {
1088 op->opaque->timerid = g_timeout_add(op->timeout + 5000,
1089 systemd_timeout_callback, op);
1090 services_add_inflight_op(op);
1091 return pcmk_rc_ok;
1092 }
1093
1094 done:
1095 if (op->synchronous) {
1096 return (op->rc == PCMK_OCF_OK)? pcmk_rc_ok : pcmk_rc_error;
1097 } else {
1098 return services__finalize_async_op(op);
1099 }
1100 }