pacemaker  2.1.2-ada5c3b36
Scalable High-Availability cluster resource manager
systemd.c
Go to the documentation of this file.
1 /*
2  * Copyright 2012-2021 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 #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 
38 int
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 
56 enum ocf_exitcode
57 services__systemd2ocf(int exit_status)
58 {
59  // This library uses OCF codes for systemd actions
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  * Functions to manage a static DBus connection
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 
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  /* Don't call systemd_init() here, because that calls this */
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  // https://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html
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
172 {
173  if (systemd_proxy) {
174  pcmk_dbus_disconnect(systemd_proxy);
175  systemd_proxy = NULL;
176  }
177 }
178 
179 /*
180  * end of systemd_proxy functions
181  */
182 
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)
210 {
211  if (name == NULL) {
212  return NULL;
213  }
214 
215  if (systemd_unit_extension(name)) {
216  return strdup(name);
217  }
218 
219  return crm_strdup_printf("%s.service", name);
220 }
221 
222 static void
223 systemd_daemon_reload_complete(DBusPendingCall *pending, void *user_data)
224 {
225  DBusError error;
226  DBusMessage *reply = NULL;
227  unsigned int reload_count = GPOINTER_TO_UINT(user_data);
228 
229  dbus_error_init(&error);
230  if(pending) {
231  reply = dbus_pending_call_steal_reply(pending);
232  }
233 
234  if (pcmk_dbus_find_error(pending, reply, &error)) {
235  crm_err("Could not issue systemd reload %d: %s", reload_count, error.message);
236  dbus_error_free(&error);
237 
238  } else {
239  crm_trace("Reload %d complete", reload_count);
240  }
241 
242  if(pending) {
243  dbus_pending_call_unref(pending);
244  }
245  if(reply) {
246  dbus_message_unref(reply);
247  }
248 }
249 
250 static bool
251 systemd_daemon_reload(int timeout)
252 {
253  static unsigned int reload_count = 0;
254  DBusMessage *msg = systemd_new_method("Reload");
255 
256  reload_count++;
257  CRM_ASSERT(msg != NULL);
258  systemd_send(msg, systemd_daemon_reload_complete,
259  GUINT_TO_POINTER(reload_count), timeout);
260  dbus_message_unref(msg);
261 
262  return TRUE;
263 }
264 
272 static void
273 set_result_from_method_error(svc_action_t *op, const DBusError *error)
274 {
276  "Unable to invoke systemd DBus method");
277 
278  if (strstr(error->name, "org.freedesktop.systemd1.InvalidName")
279  || strstr(error->name, "org.freedesktop.systemd1.LoadFailed")
280  || strstr(error->name, "org.freedesktop.systemd1.NoSuchUnit")) {
281 
282  if (pcmk__str_eq(op->action, "stop", pcmk__str_casei)) {
283  crm_trace("Masking systemd stop failure (%s) for %s "
284  "because unknown service can be considered stopped",
285  error->name, crm_str(op->rsc));
287  return;
288  }
289 
291  PCMK_EXEC_NOT_INSTALLED, "systemd unit not found");
292  }
293 
294  crm_err("DBus request for %s of systemd unit %s for resource %s failed: %s",
295  op->action, op->agent, crm_str(op->rsc), error->message);
296 }
297 
308 static const char *
309 execute_after_loadunit(DBusMessage *reply, svc_action_t *op)
310 {
311  const char *path = NULL;
312  DBusError error;
313 
314  /* path here is not used other than as a non-NULL flag to indicate that a
315  * request was indeed sent
316  */
317  if (pcmk_dbus_find_error((void *) &path, reply, &error)) {
318  if (op != NULL) {
319  set_result_from_method_error(op, &error);
320  }
321  dbus_error_free(&error);
322 
323  } else if (!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH,
324  __func__, __LINE__)) {
325  if (op != NULL) {
327  "systemd DBus method had unexpected reply");
328  crm_err("Could not load systemd unit %s for %s: "
329  "DBus reply has unexpected type", op->agent, op->id);
330  } else {
331  crm_err("Could not load systemd unit: "
332  "DBus reply has unexpected type");
333  }
334 
335  } else {
336  dbus_message_get_args (reply, NULL,
337  DBUS_TYPE_OBJECT_PATH, &path,
338  DBUS_TYPE_INVALID);
339  }
340 
341  if (op != NULL) {
342  if (path != NULL) {
343  invoke_unit_by_path(op, path);
344 
345  } else if (!(op->synchronous)) {
347  "No DBus object found for systemd unit");
349  }
350  }
351 
352  return path;
353 }
354 
362 static void
363 loadunit_completed(DBusPendingCall *pending, void *user_data)
364 {
365  DBusMessage *reply = NULL;
366  svc_action_t *op = user_data;
367 
368  crm_trace("LoadUnit result for %s arrived", op->id);
369 
370  // Grab the reply
371  if (pending != NULL) {
372  reply = dbus_pending_call_steal_reply(pending);
373  }
374 
375  // The call is no longer pending
376  CRM_LOG_ASSERT(pending == op->opaque->pending);
377  services_set_op_pending(op, NULL);
378 
379  // Execute the desired action based on the reply
380  execute_after_loadunit(reply, user_data);
381  if (reply != NULL) {
382  dbus_message_unref(reply);
383  }
384 }
385 
401 static int
402 invoke_unit_by_name(const char *arg_name, svc_action_t *op, char **path)
403 {
404  DBusMessage *msg;
405  DBusMessage *reply = NULL;
406  DBusPendingCall *pending = NULL;
407  char *name = NULL;
408 
409  if (!systemd_init()) {
410  if (op != NULL) {
412  "No DBus connection");
413  }
414  return ENOTCONN;
415  }
416 
417  /* Create a LoadUnit DBus method (equivalent to GetUnit if already loaded),
418  * which makes the unit usable via further DBus methods.
419  *
420  * <method name="LoadUnit">
421  * <arg name="name" type="s" direction="in"/>
422  * <arg name="unit" type="o" direction="out"/>
423  * </method>
424  */
425  msg = systemd_new_method("LoadUnit");
426  CRM_ASSERT(msg != NULL);
427 
428  // Add the (expanded) unit name as the argument
429  name = systemd_service_name(arg_name);
430  CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
431  DBUS_TYPE_INVALID));
432  free(name);
433 
434  if ((op == NULL) || op->synchronous) {
435  // For synchronous ops, wait for a reply and extract the result
436  const char *unit = NULL;
437  int rc = pcmk_rc_ok;
438 
439  reply = systemd_send_recv(msg, NULL,
440  (op? op->timeout : DBUS_TIMEOUT_USE_DEFAULT));
441  dbus_message_unref(msg);
442 
443  unit = execute_after_loadunit(reply, op);
444  if (unit == NULL) {
445  rc = ENOENT;
446  if (path != NULL) {
447  *path = NULL;
448  }
449  } else if (path != NULL) {
450  *path = strdup(unit);
451  if (*path == NULL) {
452  rc = ENOMEM;
453  }
454  }
455 
456  if (reply != NULL) {
457  dbus_message_unref(reply);
458  }
459  return rc;
460  }
461 
462  // For asynchronous ops, initiate the LoadUnit call and return
463  pending = systemd_send(msg, loadunit_completed, op, op->timeout);
464  if (pending == NULL) {
466  "Unable to send DBus message");
467  dbus_message_unref(msg);
468  return ECOMM;
469  }
470 
471  // LoadUnit was successfully initiated
473  services_set_op_pending(op, pending);
474  dbus_message_unref(msg);
475  return pcmk_rc_ok;
476 }
477 
490 static gint
491 sort_str(gconstpointer a, gconstpointer b)
492 {
493  if (!a && !b) {
494  return 0;
495  } else if (!a) {
496  return -1;
497  } else if (!b) {
498  return 1;
499  }
500  return strcasecmp(a, b);
501 }
502 
503 GList *
505 {
506  int nfiles = 0;
507  GList *units = NULL;
508  DBusMessageIter args;
509  DBusMessageIter unit;
510  DBusMessageIter elem;
511  DBusMessage *reply = NULL;
512 
513  if (systemd_init() == FALSE) {
514  return NULL;
515  }
516 
517 /*
518  " <method name=\"ListUnitFiles\">\n" \
519  " <arg name=\"files\" type=\"a(ss)\" direction=\"out\"/>\n" \
520  " </method>\n" \
521 */
522 
523  reply = systemd_call_simple_method("ListUnitFiles");
524  if (reply == NULL) {
525  return NULL;
526  }
527  if (!dbus_message_iter_init(reply, &args)) {
528  crm_err("Could not list systemd unit files: systemd reply has no arguments");
529  dbus_message_unref(reply);
530  return NULL;
531  }
532  if (!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY,
533  __func__, __LINE__)) {
534  crm_err("Could not list systemd unit files: systemd reply has invalid arguments");
535  dbus_message_unref(reply);
536  return NULL;
537  }
538 
539  dbus_message_iter_recurse(&args, &unit);
540  for (; dbus_message_iter_get_arg_type(&unit) != DBUS_TYPE_INVALID;
541  dbus_message_iter_next(&unit)) {
542 
543  DBusBasicValue value;
544  const char *match = NULL;
545  char *unit_name = NULL;
546  char *basename = NULL;
547 
548  if(!pcmk_dbus_type_check(reply, &unit, DBUS_TYPE_STRUCT, __func__, __LINE__)) {
549  crm_warn("Skipping systemd reply argument with unexpected type");
550  continue;
551  }
552 
553  dbus_message_iter_recurse(&unit, &elem);
554  if(!pcmk_dbus_type_check(reply, &elem, DBUS_TYPE_STRING, __func__, __LINE__)) {
555  crm_warn("Skipping systemd reply argument with no string");
556  continue;
557  }
558 
559  dbus_message_iter_get_basic(&elem, &value);
560  if (value.str == NULL) {
561  crm_debug("ListUnitFiles reply did not provide a string");
562  continue;
563  }
564  crm_trace("DBus ListUnitFiles listed: %s", value.str);
565 
566  match = systemd_unit_extension(value.str);
567  if (match == NULL) {
568  // This is not a unit file type we know how to manage
569  crm_debug("ListUnitFiles entry '%s' is not supported as resource",
570  value.str);
571  continue;
572  }
573 
574  // ListUnitFiles returns full path names, we just want base name
575  basename = strrchr(value.str, '/');
576  if (basename) {
577  basename = basename + 1;
578  } else {
579  basename = value.str;
580  }
581 
582  if (!strcmp(match, ".service")) {
583  // Service is the "default" unit type, so strip it
584  unit_name = strndup(basename, match - basename);
585  } else {
586  unit_name = strdup(basename);
587  }
588 
589  nfiles++;
590  units = g_list_prepend(units, unit_name);
591  }
592 
593  dbus_message_unref(reply);
594 
595  crm_trace("Found %d manageable systemd unit files", nfiles);
596  units = g_list_sort(units, sort_str);
597  return units;
598 }
599 
600 gboolean
602 {
603  char *path = NULL;
604  char *state = NULL;
605 
606  /* Note: Makes a blocking dbus calls
607  * Used by resources_find_service_class() when resource class=service
608  */
609  if ((invoke_unit_by_name(name, NULL, &path) != pcmk_rc_ok)
610  || (path == NULL)) {
611  return FALSE;
612  }
613 
614  /* A successful LoadUnit is not sufficient to determine the unit's
615  * existence; it merely means the LoadUnit request received a reply.
616  * We must make another blocking call to check the LoadState property.
617  */
618  state = systemd_get_property(path, "LoadState", NULL, NULL, NULL,
620  free(path);
621  if (pcmk__str_any_of(state, "loaded", "masked", NULL)) {
622  free(state);
623  return TRUE;
624  }
625  free(state);
626  return FALSE;
627 }
628 
629 #define METADATA_FORMAT \
630  "<?xml version=\"1.0\"?>\n" \
631  "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n" \
632  "<resource-agent name=\"%s\" version=\"" PCMK_DEFAULT_AGENT_VERSION "\">\n" \
633  " <version>1.1</version>\n" \
634  " <longdesc lang=\"en\">\n" \
635  " %s\n" \
636  " </longdesc>\n" \
637  " <shortdesc lang=\"en\">systemd unit file for %s</shortdesc>\n" \
638  " <parameters/>\n" \
639  " <actions>\n" \
640  " <action name=\"start\" timeout=\"100\" />\n" \
641  " <action name=\"stop\" timeout=\"100\" />\n" \
642  " <action name=\"status\" timeout=\"100\" />\n" \
643  " <action name=\"monitor\" timeout=\"100\" interval=\"60\"/>\n" \
644  " <action name=\"meta-data\" timeout=\"5\" />\n" \
645  " </actions>\n" \
646  " <special tag=\"systemd\"/>\n" \
647  "</resource-agent>\n"
648 
649 static char *
650 systemd_unit_metadata(const char *name, int timeout)
651 {
652  char *meta = NULL;
653  char *desc = NULL;
654  char *path = NULL;
655 
656  if (invoke_unit_by_name(name, NULL, &path) == pcmk_rc_ok) {
657  /* TODO: Worth a making blocking call for? Probably not. Possibly if cached. */
658  desc = systemd_get_property(path, "Description", NULL, NULL, NULL,
659  timeout);
660  } else {
661  desc = crm_strdup_printf("Systemd unit file for %s", name);
662  }
663 
664  meta = crm_strdup_printf(METADATA_FORMAT, name, desc, name);
665  free(desc);
666  free(path);
667  return meta;
668 }
669 
677 static void
678 process_unit_method_reply(DBusMessage *reply, svc_action_t *op)
679 {
680  DBusError error;
681 
682  /* The first use of error here is not used other than as a non-NULL flag to
683  * indicate that a request was indeed sent
684  */
685  if (pcmk_dbus_find_error((void *) &error, reply, &error)) {
686  set_result_from_method_error(op, &error);
687  dbus_error_free(&error);
688 
689  } else if (!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH,
690  __func__, __LINE__)) {
691  crm_warn("DBus request for %s of %s succeeded but "
692  "return type was unexpected", op->action, crm_str(op->rsc));
694  "systemd DBus method had unexpected reply");
695 
696  } else {
697  const char *path = NULL;
698 
699  dbus_message_get_args(reply, NULL,
700  DBUS_TYPE_OBJECT_PATH, &path,
701  DBUS_TYPE_INVALID);
702  crm_debug("DBus request for %s of %s using %s succeeded",
703  op->action, crm_str(op->rsc), path);
705  }
706 }
707 
715 static void
716 unit_method_complete(DBusPendingCall *pending, void *user_data)
717 {
718  DBusMessage *reply = NULL;
719  svc_action_t *op = user_data;
720 
721  crm_trace("Result for %s arrived", op->id);
722 
723  // Grab the reply
724  if (pending != NULL) {
725  reply = dbus_pending_call_steal_reply(pending);
726  }
727 
728  // The call is no longer pending
729  CRM_LOG_ASSERT(pending == op->opaque->pending);
730  services_set_op_pending(op, NULL);
731 
732  // Determine result and finalize action
733  process_unit_method_reply(reply, op);
735  if (reply != NULL) {
736  dbus_message_unref(reply);
737  }
738 }
739 
740 #define SYSTEMD_OVERRIDE_ROOT "/run/systemd/system/"
741 
742 /* When the cluster manages a systemd resource, we create a unit file override
743  * to order the service "before" pacemaker. The "before" relationship won't
744  * actually be used, since systemd won't ever start the resource -- we're
745  * interested in the reverse shutdown ordering it creates, to ensure that
746  * systemd doesn't stop the resource at shutdown while pacemaker is still
747  * running.
748  *
749  * @TODO Add start timeout
750  */
751 #define SYSTEMD_OVERRIDE_TEMPLATE \
752  "[Unit]\n" \
753  "Description=Cluster Controlled %s\n" \
754  "Before=pacemaker.service pacemaker_remote.service\n" \
755  "\n" \
756  "[Service]\n" \
757  "Restart=no\n"
758 
759 // Temporarily use rwxr-xr-x umask when opening a file for writing
760 static FILE *
761 create_world_readable(const char *filename)
762 {
763  mode_t orig_umask = umask(S_IWGRP | S_IWOTH);
764  FILE *fp = fopen(filename, "w");
765 
766  umask(orig_umask);
767  return fp;
768 }
769 
770 static void
771 create_override_dir(const char *agent)
772 {
773  char *override_dir = crm_strdup_printf(SYSTEMD_OVERRIDE_ROOT
774  "/%s.service.d", agent);
775  int rc = pcmk__build_path(override_dir, 0755);
776 
777  if (rc != pcmk_rc_ok) {
778  crm_warn("Could not create systemd override directory %s: %s",
779  override_dir, pcmk_rc_str(rc));
780  }
781  free(override_dir);
782 }
783 
784 static char *
785 get_override_filename(const char *agent)
786 {
788  "/%s.service.d/50-pacemaker.conf", agent);
789 }
790 
791 static void
792 systemd_create_override(const char *agent, int timeout)
793 {
794  FILE *file_strm = NULL;
795  char *override_file = get_override_filename(agent);
796 
797  create_override_dir(agent);
798 
799  /* Ensure the override file is world-readable. This is not strictly
800  * necessary, but it avoids a systemd warning in the logs.
801  */
802  file_strm = create_world_readable(override_file);
803  if (file_strm == NULL) {
804  crm_err("Cannot open systemd override file %s for writing",
805  override_file);
806  } else {
807  char *override = crm_strdup_printf(SYSTEMD_OVERRIDE_TEMPLATE, agent);
808 
809  int rc = fprintf(file_strm, "%s\n", override);
810 
811  free(override);
812  if (rc < 0) {
813  crm_perror(LOG_WARNING, "Cannot write to systemd override file %s",
814  override_file);
815  }
816  fflush(file_strm);
817  fclose(file_strm);
818  systemd_daemon_reload(timeout);
819  }
820 
821  free(override_file);
822 }
823 
824 static void
825 systemd_remove_override(const char *agent, int timeout)
826 {
827  char *override_file = get_override_filename(agent);
828  int rc = unlink(override_file);
829 
830  if (rc < 0) {
831  // Stop may be called when already stopped, which is fine
832  crm_perror(LOG_DEBUG, "Cannot remove systemd override file %s",
833  override_file);
834  } else {
835  systemd_daemon_reload(timeout);
836  }
837  free(override_file);
838 }
839 
851 static void
852 parse_status_result(const char *name, const char *state, void *userdata)
853 {
854  svc_action_t *op = userdata;
855 
856  crm_trace("Resource %s has %s='%s'",
857  crm_str(op->rsc), name, crm_str(state));
858 
859  if (pcmk__str_eq(state, "active", pcmk__str_none)) {
861 
862  } else if (pcmk__str_eq(state, "reloading", pcmk__str_none)) {
864 
865  } else if (pcmk__str_eq(state, "activating", pcmk__str_none)) {
867 
868  } else if (pcmk__str_eq(state, "deactivating", pcmk__str_none)) {
870 
871  } else {
873  }
874 
875  if (!(op->synchronous)) {
876  services_set_op_pending(op, NULL);
878  }
879 }
880 
888 static void
889 invoke_unit_by_path(svc_action_t *op, const char *unit)
890 {
891  const char *method = NULL;
892  DBusMessage *msg = NULL;
893  DBusMessage *reply = NULL;
894 
895  if (pcmk__str_any_of(op->action, "monitor", "status", NULL)) {
896  DBusPendingCall *pending = NULL;
897  char *state;
898 
899  state = systemd_get_property(unit, "ActiveState",
900  (op->synchronous? NULL : parse_status_result),
901  op, (op->synchronous? NULL : &pending),
902  op->timeout);
903  if (op->synchronous) {
904  parse_status_result("ActiveState", state, op);
905  free(state);
906 
907  } else if (pending == NULL) { // Could not get ActiveState property
909  "Could not get unit state from DBus");
911 
912  } else {
913  services_set_op_pending(op, pending);
914  }
915  return;
916 
917  } else if (pcmk__str_eq(op->action, "start", pcmk__str_none)) {
918  method = "StartUnit";
919  systemd_create_override(op->agent, op->timeout);
920 
921  } else if (pcmk__str_eq(op->action, "stop", pcmk__str_none)) {
922  method = "StopUnit";
923  systemd_remove_override(op->agent, op->timeout);
924 
925  } else if (pcmk__str_eq(op->action, "restart", pcmk__str_none)) {
926  method = "RestartUnit";
927 
928  } else {
930  "Action not implemented for systemd resources");
931  if (!(op->synchronous)) {
933  }
934  return;
935  }
936 
937  crm_trace("Calling %s for unit path %s named %s",
938  method, unit, crm_str(op->rsc));
939 
940  msg = systemd_new_method(method);
941  CRM_ASSERT(msg != NULL);
942 
943  /* (ss) */
944  {
945  const char *replace_s = "replace";
946  char *name = systemd_service_name(op->agent);
947 
948  CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
949  CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &replace_s, DBUS_TYPE_INVALID));
950 
951  free(name);
952  }
953 
954  if (op->synchronous) {
955  reply = systemd_send_recv(msg, NULL, op->timeout);
956  dbus_message_unref(msg);
957  process_unit_method_reply(reply, op);
958  if (reply != NULL) {
959  dbus_message_unref(reply);
960  }
961 
962  } else {
963  DBusPendingCall *pending = systemd_send(msg, unit_method_complete, op,
964  op->timeout);
965 
966  dbus_message_unref(msg);
967  if (pending == NULL) {
969  "Unable to send DBus message");
971 
972  } else {
973  services_set_op_pending(op, pending);
974  }
975  }
976 }
977 
978 static gboolean
979 systemd_timeout_callback(gpointer p)
980 {
981  svc_action_t * op = p;
982 
983  op->opaque->timerid = 0;
984  crm_warn("%s operation on systemd unit %s named '%s' timed out", op->action, op->agent, op->rsc);
986  "Systemd action did not complete within specified timeout");
988  return FALSE;
989 }
990 
1007 int
1009 {
1010  CRM_ASSERT(op != NULL);
1011 
1012  if ((op->action == NULL) || (op->agent == NULL)) {
1014  "Bug in action caller");
1015  goto done;
1016  }
1017 
1018  if (!systemd_init()) {
1020  "No DBus connection");
1021  goto done;
1022  }
1023 
1024  crm_debug("Performing %ssynchronous %s op on systemd unit %s named '%s'",
1025  (op->synchronous? "" : "a"), op->action, op->agent,
1026  crm_str(op->rsc));
1027 
1028  if (pcmk__str_eq(op->action, "meta-data", pcmk__str_casei)) {
1029  op->stdout_data = systemd_unit_metadata(op->agent, op->timeout);
1031  goto done;
1032  }
1033 
1034  /* invoke_unit_by_name() should always override these values, which are here
1035  * just as a fail-safe in case there are any code paths that neglect to
1036  */
1038  "Bug in service library");
1039 
1040  if (invoke_unit_by_name(op->agent, op, NULL) == pcmk_rc_ok) {
1041  op->opaque->timerid = g_timeout_add(op->timeout + 5000,
1042  systemd_timeout_callback, op);
1044  return pcmk_rc_ok;
1045  }
1046 
1047 done:
1048  if (op->synchronous) {
1049  return (op->rc == PCMK_OCF_OK)? pcmk_rc_ok : pcmk_rc_error;
1050  } else {
1051  return services__finalize_async_op(op);
1052  }
1053 }
Services API.
int rc
Exit status of action (set by library upon completion)
Definition: services.h:153
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:225
int services__execute_systemd(svc_action_t *op)
Definition: systemd.c:1008
A dumping ground.
ocf_exitcode
Exit status codes for resource agents.
Definition: results.h:161
char * id
Definition: services.h:124
void pcmk_dbus_disconnect(DBusConnection *connection)
Definition: dbus.c:295
#define DBUS_TIMEOUT_USE_DEFAULT
Definition: pcmk-dbus.h:16
Service safely stopped.
Definition: results.h:169
#define METADATA_FORMAT
Definition: systemd.c:629
char * rsc
XML ID of resource being executed for resource actions, otherwise NULL.
Definition: services.h:127
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:209
int timeout
Action timeout (in milliseconds)
Definition: services.h:144
Action did not complete in time.
Definition: results.h:310
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:432
Wrappers for and extensions to glib mainloop.
bool pcmk_dbus_find_error(DBusPendingCall *pending, DBusMessage *reply, DBusError *ret)
Definition: dbus.c:330
char * strndup(const char *str, size_t len)
#define crm_warn(fmt, args...)
Definition: logging.h:358
int rc
Definition: pcmk_fence.c:35
svc_action_private_t * opaque
This field should be treated as internal to Pacemaker.
Definition: services.h:180
#define crm_debug(fmt, args...)
Definition: logging.h:362
#define BUS_NAME_UNIT
Definition: systemd.c:27
char * stdout_data
Action stdout (set by library)
Definition: services.h:176
Parameter invalid (inherently)
Definition: results.h:168
gboolean systemd_unit_exists(const char *name)
Definition: systemd.c:601
#define crm_trace(fmt, args...)
Definition: logging.h:363
#define BUS_NAME
Definition: systemd.c:25
int services__finalize_async_op(svc_action_t *op)
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
Object for executing external actions.
Definition: services.h:120
char * agent
Resource agent name for resource actions, otherwise NULL.
Definition: services.h:142
void services__set_result(svc_action_t *action, int agent_status, enum pcmk_exec_status exec_status, const char *exit_reason)
Definition: services.c:1264
int synchronous
Definition: services.h:171
Action completed, result is known.
Definition: results.h:308
#define ECOMM
Definition: portability.h:123
#define BUS_PATH
Definition: systemd.c:28
Execution failed, do not retry anywhere.
Definition: results.h:314
Dependencies not available locally.
Definition: results.h:167
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:955
#define SYSTEMD_OVERRIDE_ROOT
Definition: systemd.c:740
GList * systemd_unit_listall(void)
Definition: systemd.c:504
Unspecified error.
Definition: results.h:163
DBusPendingCall * pcmk_dbus_send(DBusMessage *msg, DBusConnection *connection, void(*done)(DBusPendingCall *pending, void *user_data), void *user_data, int timeout)
Definition: dbus.c:476
DBusConnection * pcmk_dbus_connect(void)
Definition: dbus.c:259
void services_add_inflight_op(svc_action_t *op)
Definition: services.c:830
Requested action not implemented.
Definition: results.h:165
int services__systemd_prepare(svc_action_t *op)
Definition: systemd.c:39
void systemd_cleanup(void)
Definition: systemd.c:171
char * action
Name of action being executed for resource actions, otherwise NULL.
Definition: services.h:130
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:308
#define crm_err(fmt, args...)
Definition: logging.h:357
enum ocf_exitcode services__systemd2ocf(int exit_status)
Definition: systemd.c:57
#define CRM_ASSERT(expr)
Definition: results.h:42
Success.
Definition: results.h:162
Action is pending.
Definition: results.h:188
bool pcmk_dbus_type_check(DBusMessage *msg, DBusMessageIter *field, int expected, const char *function, int line)
Definition: dbus.c:516
#define crm_str(x)
Definition: logging.h:383
Agent or dependency not available locally.
Definition: results.h:315
Action is in progress.
Definition: results.h:307
char * pcmk_dbus_get_property(DBusConnection *connection, const char *target, const char *obj, const gchar *iface, const char *name, property_callback_func callback, void *userdata, DBusPendingCall **pending, int timeout)
Definition: dbus.c:693
#define SYSTEMD_OVERRIDE_TEMPLATE
Definition: systemd.c:751
char * name
Definition: pcmk_fence.c:31
unsigned int timeout
Definition: pcmk_fence.c:32
DBusMessage * pcmk_dbus_send_recv(DBusMessage *msg, DBusConnection *connection, DBusError *error, int timeout)
Definition: dbus.c:412
Execution failed, may be retried.
Definition: results.h:312
#define BUS_NAME_MANAGER
Definition: systemd.c:26
int pcmk__build_path(const char *path_c, mode_t mode)
Definition: io.c:45