pacemaker  2.0.4-2deceaa
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
systemd.c
Go to the documentation of this file.
1 /*
2  * Copyright 2012-2020 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 #include <crm/crm.h>
12 #include <crm/services.h>
13 #include <crm/common/mainloop.h>
14 
15 #include <sys/stat.h>
16 #include <gio/gio.h>
17 #include <services_private.h>
18 #include <systemd.h>
19 #include <dbus/dbus.h>
20 #include <pcmk-dbus.h>
21 
22 gboolean systemd_unit_exec_with_unit(svc_action_t * op, const char *unit);
23 
24 #define BUS_NAME "org.freedesktop.systemd1"
25 #define BUS_NAME_MANAGER BUS_NAME ".Manager"
26 #define BUS_NAME_UNIT BUS_NAME ".Unit"
27 #define BUS_PATH "/org/freedesktop/systemd1"
28 
29 static inline DBusMessage *
30 systemd_new_method(const char *method)
31 {
32  crm_trace("Calling: %s on " BUS_NAME_MANAGER, method);
33  return dbus_message_new_method_call(BUS_NAME, BUS_PATH, BUS_NAME_MANAGER,
34  method);
35 }
36 
37 /*
38  * Functions to manage a static DBus connection
39  */
40 
41 static DBusConnection* systemd_proxy = NULL;
42 
43 static inline DBusPendingCall *
44 systemd_send(DBusMessage *msg,
45  void(*done)(DBusPendingCall *pending, void *user_data),
46  void *user_data, int timeout)
47 {
48  return pcmk_dbus_send(msg, systemd_proxy, done, user_data, timeout);
49 }
50 
51 static inline DBusMessage *
52 systemd_send_recv(DBusMessage *msg, DBusError *error, int timeout)
53 {
54  return pcmk_dbus_send_recv(msg, systemd_proxy, error, timeout);
55 }
56 
68 static DBusMessage *
69 systemd_call_simple_method(const char *method)
70 {
71  DBusMessage *msg = systemd_new_method(method);
72  DBusMessage *reply = NULL;
73  DBusError error;
74 
75  /* Don't call systemd_init() here, because that calls this */
76  CRM_CHECK(systemd_proxy, return NULL);
77 
78  if (msg == NULL) {
79  crm_err("Could not create message to send %s to systemd", method);
80  return NULL;
81  }
82 
83  dbus_error_init(&error);
84  reply = systemd_send_recv(msg, &error, DBUS_TIMEOUT_USE_DEFAULT);
85  dbus_message_unref(msg);
86 
87  if (dbus_error_is_set(&error)) {
88  crm_err("Could not send %s to systemd: %s (%s)",
89  method, error.message, error.name);
90  dbus_error_free(&error);
91  return NULL;
92 
93  } else if (reply == NULL) {
94  crm_err("Could not send %s to systemd: no reply received", method);
95  return NULL;
96  }
97 
98  return reply;
99 }
100 
101 static gboolean
102 systemd_init(void)
103 {
104  static int need_init = 1;
105  // https://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html
106 
107  if (systemd_proxy
108  && dbus_connection_get_is_connected(systemd_proxy) == FALSE) {
109  crm_warn("Connection to System DBus is closed. Reconnecting...");
110  pcmk_dbus_disconnect(systemd_proxy);
111  systemd_proxy = NULL;
112  need_init = 1;
113  }
114 
115  if (need_init) {
116  need_init = 0;
117  systemd_proxy = pcmk_dbus_connect();
118  }
119  if (systemd_proxy == NULL) {
120  return FALSE;
121  }
122  return TRUE;
123 }
124 
125 static inline char *
126 systemd_get_property(const char *unit, const char *name,
127  void (*callback)(const char *name, const char *value, void *userdata),
128  void *userdata, DBusPendingCall **pending, int timeout)
129 {
130  return systemd_proxy?
131  pcmk_dbus_get_property(systemd_proxy, BUS_NAME, unit, BUS_NAME_UNIT,
132  name, callback, userdata, pending, timeout)
133  : NULL;
134 }
135 
136 void
138 {
139  if (systemd_proxy) {
140  pcmk_dbus_disconnect(systemd_proxy);
141  systemd_proxy = NULL;
142  }
143 }
144 
145 /*
146  * end of systemd_proxy functions
147  */
148 
157 static const char *
158 systemd_unit_extension(const char *name)
159 {
160  if (name) {
161  const char *dot = strrchr(name, '.');
162 
163  if (dot && (!strcmp(dot, ".service")
164  || !strcmp(dot, ".socket")
165  || !strcmp(dot, ".mount")
166  || !strcmp(dot, ".timer")
167  || !strcmp(dot, ".path"))) {
168  return dot;
169  }
170  }
171  return NULL;
172 }
173 
174 static char *
175 systemd_service_name(const char *name)
176 {
177  if (name == NULL) {
178  return NULL;
179  }
180 
181  if (systemd_unit_extension(name)) {
182  return strdup(name);
183  }
184 
185  return crm_strdup_printf("%s.service", name);
186 }
187 
188 static void
189 systemd_daemon_reload_complete(DBusPendingCall *pending, void *user_data)
190 {
191  DBusError error;
192  DBusMessage *reply = NULL;
193  unsigned int reload_count = GPOINTER_TO_UINT(user_data);
194 
195  dbus_error_init(&error);
196  if(pending) {
197  reply = dbus_pending_call_steal_reply(pending);
198  }
199 
200  if (pcmk_dbus_find_error(pending, reply, &error)) {
201  crm_err("Could not issue systemd reload %d: %s", reload_count, error.message);
202  dbus_error_free(&error);
203 
204  } else {
205  crm_trace("Reload %d complete", reload_count);
206  }
207 
208  if(pending) {
209  dbus_pending_call_unref(pending);
210  }
211  if(reply) {
212  dbus_message_unref(reply);
213  }
214 }
215 
216 static bool
217 systemd_daemon_reload(int timeout)
218 {
219  static unsigned int reload_count = 0;
220  DBusMessage *msg = systemd_new_method("Reload");
221 
222  reload_count++;
223  CRM_ASSERT(msg != NULL);
224  systemd_send(msg, systemd_daemon_reload_complete,
225  GUINT_TO_POINTER(reload_count), timeout);
226  dbus_message_unref(msg);
227 
228  return TRUE;
229 }
230 
231 static bool
232 systemd_mask_error(svc_action_t *op, const char *error)
233 {
234  crm_trace("Could not issue %s for %s: %s", op->action, op->rsc, error);
235  if(strstr(error, "org.freedesktop.systemd1.InvalidName")
236  || strstr(error, "org.freedesktop.systemd1.LoadFailed")
237  || strstr(error, "org.freedesktop.systemd1.NoSuchUnit")) {
238 
239  if (safe_str_eq(op->action, "stop")) {
240  crm_trace("Masking %s failure for %s: unknown services are stopped", op->action, op->rsc);
241  op->rc = PCMK_OCF_OK;
242  return TRUE;
243 
244  } else {
245  crm_trace("Mapping %s failure for %s: unknown services are not installed", op->action, op->rsc);
248  return FALSE;
249  }
250  }
251 
252  return FALSE;
253 }
254 
255 static const char *
256 systemd_loadunit_result(DBusMessage *reply, svc_action_t * op)
257 {
258  const char *path = NULL;
259  DBusError error;
260 
261  if (pcmk_dbus_find_error((void*)&path, reply, &error)) {
262  if(op && !systemd_mask_error(op, error.name)) {
263  crm_err("Could not load systemd unit %s for %s: %s",
264  op->agent, op->id, error.message);
265  }
266  dbus_error_free(&error);
267 
268  } else if(pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) {
269  dbus_message_get_args (reply, NULL,
270  DBUS_TYPE_OBJECT_PATH, &path,
271  DBUS_TYPE_INVALID);
272  }
273 
274  if(op) {
275  if (path) {
276  systemd_unit_exec_with_unit(op, path);
277 
278  } else if (op->synchronous == FALSE) {
279  operation_finalize(op);
280  }
281  }
282 
283  return path;
284 }
285 
286 
287 static void
288 systemd_loadunit_cb(DBusPendingCall *pending, void *user_data)
289 {
290  DBusMessage *reply = NULL;
291  svc_action_t * op = user_data;
292 
293  if(pending) {
294  reply = dbus_pending_call_steal_reply(pending);
295  }
296 
297  crm_trace("Got result: %p for %p / %p for %s", reply, pending, op->opaque->pending, op->id);
298 
299  CRM_LOG_ASSERT(pending == op->opaque->pending);
300  services_set_op_pending(op, NULL);
301 
302  systemd_loadunit_result(reply, user_data);
303 
304  if(reply) {
305  dbus_message_unref(reply);
306  }
307 }
308 
309 static char *
310 systemd_unit_by_name(const gchar * arg_name, svc_action_t *op)
311 {
312  DBusMessage *msg;
313  DBusMessage *reply = NULL;
314  DBusPendingCall* pending = NULL;
315  char *name = NULL;
316 
317 /*
318  Equivalent to GetUnit if it's already loaded
319  <method name="LoadUnit">
320  <arg name="name" type="s" direction="in"/>
321  <arg name="unit" type="o" direction="out"/>
322  </method>
323  */
324 
325  if (systemd_init() == FALSE) {
326  return FALSE;
327  }
328 
329  msg = systemd_new_method("LoadUnit");
330  CRM_ASSERT(msg != NULL);
331 
332  name = systemd_service_name(arg_name);
333  CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
334  free(name);
335 
336  if(op == NULL || op->synchronous) {
337  const char *unit = NULL;
338  char *munit = NULL;
339 
340  reply = systemd_send_recv(msg, NULL,
341  (op? op->timeout : DBUS_TIMEOUT_USE_DEFAULT));
342  dbus_message_unref(msg);
343 
344  unit = systemd_loadunit_result(reply, op);
345  if(unit) {
346  munit = strdup(unit);
347  }
348  if(reply) {
349  dbus_message_unref(reply);
350  }
351  return munit;
352  }
353 
354  pending = systemd_send(msg, systemd_loadunit_cb, op, op->timeout);
355  if(pending) {
356  services_set_op_pending(op, pending);
357  }
358 
359  dbus_message_unref(msg);
360  return NULL;
361 }
362 
375 static gint
376 sort_str(gconstpointer a, gconstpointer b)
377 {
378  if (!a && !b) {
379  return 0;
380  } else if (!a) {
381  return -1;
382  } else if (!b) {
383  return 1;
384  }
385  return strcasecmp(a, b);
386 }
387 
388 GList *
390 {
391  int nfiles = 0;
392  GList *units = NULL;
393  DBusMessageIter args;
394  DBusMessageIter unit;
395  DBusMessageIter elem;
396  DBusMessage *reply = NULL;
397 
398  if (systemd_init() == FALSE) {
399  return NULL;
400  }
401 
402 /*
403  " <method name=\"ListUnitFiles\">\n" \
404  " <arg name=\"files\" type=\"a(ss)\" direction=\"out\"/>\n" \
405  " </method>\n" \
406 */
407 
408  reply = systemd_call_simple_method("ListUnitFiles");
409  if (reply == NULL) {
410  return NULL;
411  }
412  if (!dbus_message_iter_init(reply, &args)) {
413  crm_err("Could not list systemd unit files: systemd reply has no arguments");
414  dbus_message_unref(reply);
415  return NULL;
416  }
417  if (!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY,
418  __FUNCTION__, __LINE__)) {
419  crm_err("Could not list systemd unit files: systemd reply has invalid arguments");
420  dbus_message_unref(reply);
421  return NULL;
422  }
423 
424  dbus_message_iter_recurse(&args, &unit);
425  for (; dbus_message_iter_get_arg_type(&unit) != DBUS_TYPE_INVALID;
426  dbus_message_iter_next(&unit)) {
427 
428  DBusBasicValue value;
429  const char *match = NULL;
430  char *unit_name = NULL;
431  char *basename = NULL;
432 
433  if(!pcmk_dbus_type_check(reply, &unit, DBUS_TYPE_STRUCT, __FUNCTION__, __LINE__)) {
434  crm_debug("ListUnitFiles reply has unexpected type");
435  continue;
436  }
437 
438  dbus_message_iter_recurse(&unit, &elem);
439  if(!pcmk_dbus_type_check(reply, &elem, DBUS_TYPE_STRING, __FUNCTION__, __LINE__)) {
440  crm_debug("ListUnitFiles reply does not contain a string");
441  continue;
442  }
443 
444  dbus_message_iter_get_basic(&elem, &value);
445  if (value.str == NULL) {
446  crm_debug("ListUnitFiles reply did not provide a string");
447  continue;
448  }
449  crm_trace("DBus ListUnitFiles listed: %s", value.str);
450 
451  match = systemd_unit_extension(value.str);
452  if (match == NULL) {
453  // This is not a unit file type we know how to manage
454  crm_debug("ListUnitFiles entry '%s' is not supported as resource",
455  value.str);
456  continue;
457  }
458 
459  // ListUnitFiles returns full path names, we just want base name
460  basename = strrchr(value.str, '/');
461  if (basename) {
462  basename = basename + 1;
463  } else {
464  basename = value.str;
465  }
466 
467  if (!strcmp(match, ".service")) {
468  // Service is the "default" unit type, so strip it
469  unit_name = strndup(basename, match - basename);
470  } else {
471  unit_name = strdup(basename);
472  }
473 
474  nfiles++;
475  units = g_list_prepend(units, unit_name);
476  }
477 
478  dbus_message_unref(reply);
479 
480  crm_trace("Found %d manageable systemd unit files", nfiles);
481  units = g_list_sort(units, sort_str);
482  return units;
483 }
484 
485 gboolean
486 systemd_unit_exists(const char *name)
487 {
488  char *unit = NULL;
489 
490  /* Note: Makes a blocking dbus calls
491  * Used by resources_find_service_class() when resource class=service
492  */
493  unit = systemd_unit_by_name(name, NULL);
494  if(unit) {
495  free(unit);
496  return TRUE;
497  }
498  return FALSE;
499 }
500 
501 static char *
502 systemd_unit_metadata(const char *name, int timeout)
503 {
504  char *meta = NULL;
505  char *desc = NULL;
506  char *path = systemd_unit_by_name(name, NULL);
507 
508  if (path) {
509  /* TODO: Worth a making blocking call for? Probably not. Possibly if cached. */
510  desc = systemd_get_property(path, "Description", NULL, NULL, NULL,
511  timeout);
512  } else {
513  desc = crm_strdup_printf("Systemd unit file for %s", name);
514  }
515 
516  meta = crm_strdup_printf("<?xml version=\"1.0\"?>\n"
517  "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
518  "<resource-agent name=\"%s\" version=\"" PCMK_DEFAULT_AGENT_VERSION "\">\n"
519  " <version>1.0</version>\n"
520  " <longdesc lang=\"en\">\n"
521  " %s\n"
522  " </longdesc>\n"
523  " <shortdesc lang=\"en\">systemd unit file for %s</shortdesc>\n"
524  " <parameters>\n"
525  " </parameters>\n"
526  " <actions>\n"
527  " <action name=\"start\" timeout=\"100\" />\n"
528  " <action name=\"stop\" timeout=\"100\" />\n"
529  " <action name=\"status\" timeout=\"100\" />\n"
530  " <action name=\"monitor\" timeout=\"100\" interval=\"60\"/>\n"
531  " <action name=\"meta-data\" timeout=\"5\" />\n"
532  " </actions>\n"
533  " <special tag=\"systemd\">\n"
534  " </special>\n" "</resource-agent>\n", name, desc, name);
535  free(desc);
536  free(path);
537  return meta;
538 }
539 
540 static void
541 systemd_exec_result(DBusMessage *reply, svc_action_t *op)
542 {
543  DBusError error;
544 
545  if (pcmk_dbus_find_error((void*)&error, reply, &error)) {
546 
547  /* ignore "already started" or "not running" errors */
548  if (!systemd_mask_error(op, error.name)) {
549  crm_err("Could not issue %s for %s: %s", op->action, op->rsc, error.message);
550  }
551  dbus_error_free(&error);
552 
553  } else {
554  if(!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH, __FUNCTION__, __LINE__)) {
555  crm_warn("Call to %s passed but return type was unexpected", op->action);
556  op->rc = PCMK_OCF_OK;
557 
558  } else {
559  const char *path = NULL;
560 
561  dbus_message_get_args (reply, NULL,
562  DBUS_TYPE_OBJECT_PATH, &path,
563  DBUS_TYPE_INVALID);
564  crm_info("Call to %s passed: %s", op->action, path);
565  op->rc = PCMK_OCF_OK;
566  }
567  }
568 
569  operation_finalize(op);
570 }
571 
572 static void
573 systemd_async_dispatch(DBusPendingCall *pending, void *user_data)
574 {
575  DBusMessage *reply = NULL;
576  svc_action_t *op = user_data;
577 
578  if(pending) {
579  reply = dbus_pending_call_steal_reply(pending);
580  }
581 
582  crm_trace("Got result: %p for %p for %s, %s", reply, pending, op->rsc, op->action);
583 
584  CRM_LOG_ASSERT(pending == op->opaque->pending);
585  services_set_op_pending(op, NULL);
586  systemd_exec_result(reply, op);
587 
588  if(reply) {
589  dbus_message_unref(reply);
590  }
591 }
592 
593 #define SYSTEMD_OVERRIDE_ROOT "/run/systemd/system/"
594 
595 /* When the cluster manages a systemd resource, we create a unit file override
596  * to order the service "before" pacemaker. The "before" relationship won't
597  * actually be used, since systemd won't ever start the resource -- we're
598  * interested in the reverse shutdown ordering it creates, to ensure that
599  * systemd doesn't stop the resource at shutdown while pacemaker is still
600  * running.
601  *
602  * @TODO Add start timeout
603  */
604 #define SYSTEMD_OVERRIDE_TEMPLATE \
605  "[Unit]\n" \
606  "Description=Cluster Controlled %s\n" \
607  "Before=pacemaker.service pacemaker_remote.service\n" \
608  "\n" \
609  "[Service]\n" \
610  "Restart=no\n"
611 
612 // Temporarily use rwxr-xr-x umask when opening a file for writing
613 static FILE *
614 create_world_readable(const char *filename)
615 {
616  mode_t orig_umask = umask(S_IWGRP | S_IWOTH);
617  FILE *fp = fopen(filename, "w");
618 
619  umask(orig_umask);
620  return fp;
621 }
622 
623 static void
624 create_override_dir(const char *agent)
625 {
626  char *override_dir = crm_strdup_printf(SYSTEMD_OVERRIDE_ROOT
627  "/%s.service.d", agent);
628 
629  crm_build_path(override_dir, 0755);
630  free(override_dir);
631 }
632 
633 static char *
634 get_override_filename(const char *agent)
635 {
637  "/%s.service.d/50-pacemaker.conf", agent);
638 }
639 
640 static void
641 systemd_create_override(const char *agent, int timeout)
642 {
643  FILE *file_strm = NULL;
644  char *override_file = get_override_filename(agent);
645 
646  create_override_dir(agent);
647 
648  /* Ensure the override file is world-readable. This is not strictly
649  * necessary, but it avoids a systemd warning in the logs.
650  */
651  file_strm = create_world_readable(override_file);
652  if (file_strm == NULL) {
653  crm_err("Cannot open systemd override file %s for writing",
654  override_file);
655  } else {
656  char *override = crm_strdup_printf(SYSTEMD_OVERRIDE_TEMPLATE, agent);
657 
658  int rc = fprintf(file_strm, "%s\n", override);
659 
660  free(override);
661  if (rc < 0) {
662  crm_perror(LOG_WARNING, "Cannot write to systemd override file %s",
663  override_file);
664  }
665  fflush(file_strm);
666  fclose(file_strm);
667  systemd_daemon_reload(timeout);
668  }
669 
670  free(override_file);
671 }
672 
673 static void
674 systemd_remove_override(const char *agent, int timeout)
675 {
676  char *override_file = get_override_filename(agent);
677  int rc = unlink(override_file);
678 
679  if (rc < 0) {
680  // Stop may be called when already stopped, which is fine
681  crm_perror(LOG_DEBUG, "Cannot remove systemd override file %s",
682  override_file);
683  } else {
684  systemd_daemon_reload(timeout);
685  }
686  free(override_file);
687 }
688 
689 static void
690 systemd_unit_check(const char *name, const char *state, void *userdata)
691 {
692  svc_action_t * op = userdata;
693 
694  crm_trace("Resource %s has %s='%s'", op->rsc, name, state);
695 
696  if(state == NULL) {
697  op->rc = PCMK_OCF_NOT_RUNNING;
698 
699  } else if (g_strcmp0(state, "active") == 0) {
700  op->rc = PCMK_OCF_OK;
701  } else if (g_strcmp0(state, "reloading") == 0) {
702  op->rc = PCMK_OCF_OK;
703  } else if (g_strcmp0(state, "activating") == 0) {
704  op->rc = PCMK_OCF_PENDING;
705  } else if (g_strcmp0(state, "deactivating") == 0) {
706  op->rc = PCMK_OCF_PENDING;
707  } else {
708  op->rc = PCMK_OCF_NOT_RUNNING;
709  }
710 
711  if (op->synchronous == FALSE) {
712  services_set_op_pending(op, NULL);
713  operation_finalize(op);
714  }
715 }
716 
717 gboolean
719 {
720  const char *method = op->action;
721  DBusMessage *msg = NULL;
722  DBusMessage *reply = NULL;
723 
724  CRM_ASSERT(unit);
725 
726  if (safe_str_eq(op->action, "monitor") || safe_str_eq(method, "status")) {
727  DBusPendingCall *pending = NULL;
728  char *state;
729 
730  state = systemd_get_property(unit, "ActiveState",
731  (op->synchronous? NULL : systemd_unit_check),
732  op, (op->synchronous? NULL : &pending),
733  op->timeout);
734  if (op->synchronous) {
735  systemd_unit_check("ActiveState", state, op);
736  free(state);
737  return op->rc == PCMK_OCF_OK;
738  } else if (pending) {
739  services_set_op_pending(op, pending);
740  return TRUE;
741 
742  } else {
743  return operation_finalize(op);
744  }
745 
746  } else if (g_strcmp0(method, "start") == 0) {
747  method = "StartUnit";
748  systemd_create_override(op->agent, op->timeout);
749 
750  } else if (g_strcmp0(method, "stop") == 0) {
751  method = "StopUnit";
752  systemd_remove_override(op->agent, op->timeout);
753 
754  } else if (g_strcmp0(method, "restart") == 0) {
755  method = "RestartUnit";
756 
757  } else {
759  goto cleanup;
760  }
761 
762  crm_debug("Calling %s for %s: %s", method, op->rsc, unit);
763 
764  msg = systemd_new_method(method);
765  CRM_ASSERT(msg != NULL);
766 
767  /* (ss) */
768  {
769  const char *replace_s = "replace";
770  char *name = systemd_service_name(op->agent);
771 
772  CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
773  CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &replace_s, DBUS_TYPE_INVALID));
774 
775  free(name);
776  }
777 
778  if (op->synchronous == FALSE) {
779  DBusPendingCall *pending = systemd_send(msg, systemd_async_dispatch,
780  op, op->timeout);
781 
782  dbus_message_unref(msg);
783  if(pending) {
784  services_set_op_pending(op, pending);
785  return TRUE;
786 
787  } else {
788  return operation_finalize(op);
789  }
790 
791  } else {
792  reply = systemd_send_recv(msg, NULL, op->timeout);
793  dbus_message_unref(msg);
794  systemd_exec_result(reply, op);
795 
796  if(reply) {
797  dbus_message_unref(reply);
798  }
799  return FALSE;
800  }
801 
802  cleanup:
803  if (op->synchronous == FALSE) {
804  return operation_finalize(op);
805  }
806 
807  return op->rc == PCMK_OCF_OK;
808 }
809 
810 static gboolean
811 systemd_timeout_callback(gpointer p)
812 {
813  svc_action_t * op = p;
814 
815  op->opaque->timerid = 0;
816  crm_warn("%s operation on systemd unit %s named '%s' timed out", op->action, op->agent, op->rsc);
817  operation_finalize(op);
818 
819  return FALSE;
820 }
821 
822 /* For an asynchronous 'op', returns FALSE if 'op' should be free'd by the caller */
823 /* For a synchronous 'op', returns FALSE if 'op' fails */
824 gboolean
826 {
827  char *unit = NULL;
828 
829  CRM_ASSERT(op);
830  CRM_ASSERT(systemd_init());
832  crm_debug("Performing %ssynchronous %s op on systemd unit %s named '%s'",
833  op->synchronous ? "" : "a", op->action, op->agent, op->rsc);
834 
835  if (safe_str_eq(op->action, "meta-data")) {
836  // @TODO Implement an async meta-data call in executor API
837  op->stdout_data = systemd_unit_metadata(op->agent, op->timeout);
838  op->rc = PCMK_OCF_OK;
839 
840  if (op->synchronous == FALSE) {
841  return operation_finalize(op);
842  }
843  return TRUE;
844  }
845 
846  unit = systemd_unit_by_name(op->agent, op);
847  free(unit);
848 
849  if (op->synchronous == FALSE) {
850  if (op->opaque->pending) {
851  op->opaque->timerid = g_timeout_add(op->timeout + 5000, systemd_timeout_callback, op);
853  return TRUE;
854 
855  } else {
856  return operation_finalize(op);
857  }
858  }
859 
860  return op->rc == PCMK_OCF_OK;
861 }
Services API.
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:233
A dumping ground.
void crm_build_path(const char *path_c, mode_t mode)
Create a directory, including any parent directories needed.
Definition: io.c:81
char * id
Definition: services.h:152
void pcmk_dbus_disconnect(DBusConnection *connection)
Definition: dbus.c:55
#define DBUS_TIMEOUT_USE_DEFAULT
Definition: pcmk-dbus.h:14
char * rsc
Definition: services.h:153
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:219
Wrappers for and extensions to glib mainloop.
bool pcmk_dbus_find_error(DBusPendingCall *pending, DBusMessage *reply, DBusError *ret)
Definition: dbus.c:76
char * strndup(const char *str, size_t len)
#define crm_warn(fmt, args...)
Definition: logging.h:364
int rc
Definition: pcmk_fence.c:34
svc_action_private_t * opaque
Definition: services.h:187
#define crm_debug(fmt, args...)
Definition: logging.h:368
#define BUS_NAME_UNIT
Definition: systemd.c:26
gboolean operation_finalize(svc_action_t *op)
char * stdout_data
Definition: services.h:177
gboolean systemd_unit_exists(const char *name)
Definition: systemd.c:486
#define crm_trace(fmt, args...)
Definition: logging.h:369
#define BUS_NAME
Definition: systemd.c:24
char * agent
Definition: services.h:159
int synchronous
Definition: services.h:173
#define BUS_PATH
Definition: systemd.c:27
char * pcmk_dbus_get_property(DBusConnection *connection, const char *target, const char *obj, const gchar *iface, const char *name, void(*callback)(const char *name, const char *value, void *userdata), void *userdata, DBusPendingCall **pending, int timeout)
Definition: dbus.c:408
#define SYSTEMD_OVERRIDE_ROOT
Definition: systemd.c:593
GList * systemd_unit_listall(void)
Definition: systemd.c:389
DBusPendingCall * pcmk_dbus_send(DBusMessage *msg, DBusConnection *connection, void(*done)(DBusPendingCall *pending, void *user_data), void *user_data, int timeout)
Definition: dbus.c:223
DBusConnection * pcmk_dbus_connect(void)
Definition: dbus.c:36
void services_add_inflight_op(svc_action_t *op)
Definition: services.c:705
void systemd_cleanup(void)
Definition: systemd.c:137
char * action
Definition: services.h:154
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:314
#define crm_err(fmt, args...)
Definition: logging.h:363
#define CRM_ASSERT(expr)
Definition: results.h:42
#define PCMK_DEFAULT_AGENT_VERSION
Definition: services.h:58
bool pcmk_dbus_type_check(DBusMessage *msg, DBusMessageIter *field, int expected, const char *function, int line)
Definition: dbus.c:270
gboolean systemd_unit_exec_with_unit(svc_action_t *op, const char *unit)
Definition: systemd.c:718
#define safe_str_eq(a, b)
Definition: util.h:65
#define SYSTEMD_OVERRIDE_TEMPLATE
Definition: systemd.c:604
char * name
Definition: pcmk_fence.c:30
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
unsigned int timeout
Definition: pcmk_fence.c:31
DBusMessage * pcmk_dbus_send_recv(DBusMessage *msg, DBusConnection *connection, DBusError *error, int timeout)
Definition: dbus.c:159
gboolean systemd_unit_exec(svc_action_t *op)
Definition: systemd.c:825
#define crm_info(fmt, args...)
Definition: logging.h:366
#define BUS_NAME_MANAGER
Definition: systemd.c:25