26ad17
From 17d5ceac78f610aabf6a3678813706faf252c2fb Mon Sep 17 00:00:00 2001
26ad17
From: Klaus Wenninger <klaus.wenninger@aon.at>
26ad17
Date: Mon, 20 Jul 2020 17:56:29 +0200
26ad17
Subject: [PATCH 1/6] Fix: ipc-api: allow calling connect after disconnection
26ad17
26ad17
---
26ad17
 lib/common/crmcommon_private.h |  1 +
26ad17
 lib/common/ipc_client.c        | 22 ++++++++++++++++------
26ad17
 2 files changed, 17 insertions(+), 6 deletions(-)
26ad17
26ad17
diff --git a/lib/common/crmcommon_private.h b/lib/common/crmcommon_private.h
26ad17
index 49dae6c..d55df99 100644
26ad17
--- a/lib/common/crmcommon_private.h
26ad17
+++ b/lib/common/crmcommon_private.h
26ad17
@@ -175,6 +175,7 @@ typedef struct pcmk__ipc_methods_s {
26ad17
 struct pcmk_ipc_api_s {
26ad17
     enum pcmk_ipc_server server;          // Daemon this IPC API instance is for
26ad17
     enum pcmk_ipc_dispatch dispatch_type; // How replies should be dispatched
26ad17
+    size_t ipc_size_max;                  // maximum IPC buffer size
26ad17
     crm_ipc_t *ipc;                       // IPC connection
26ad17
     mainloop_io_t *mainloop_io;     // If using mainloop, I/O source for IPC
26ad17
     bool free_on_disconnect;        // Whether disconnect should free object
26ad17
diff --git a/lib/common/ipc_client.c b/lib/common/ipc_client.c
26ad17
index 4077d61..df687da 100644
26ad17
--- a/lib/common/ipc_client.c
26ad17
+++ b/lib/common/ipc_client.c
26ad17
@@ -46,8 +46,6 @@
26ad17
 int
26ad17
 pcmk_new_ipc_api(pcmk_ipc_api_t **api, enum pcmk_ipc_server server)
26ad17
 {
26ad17
-    size_t max_size = 0;
26ad17
-
26ad17
     if (api == NULL) {
26ad17
         return EINVAL;
26ad17
     }
26ad17
@@ -64,13 +62,15 @@ pcmk_new_ipc_api(pcmk_ipc_api_t **api, enum pcmk_ipc_server server)
26ad17
         return EOPNOTSUPP;
26ad17
     }
26ad17
 
26ad17
+    (*api)->ipc_size_max = 0;
26ad17
+
26ad17
     // Set server methods and max_size (if not default)
26ad17
     switch (server) {
26ad17
         case pcmk_ipc_attrd:
26ad17
             break;
26ad17
 
26ad17
         case pcmk_ipc_based:
26ad17
-            max_size = 512 * 1024; // 512KB
26ad17
+            (*api)->ipc_size_max = 512 * 1024; // 512KB
26ad17
             break;
26ad17
 
26ad17
         case pcmk_ipc_controld:
26ad17
@@ -88,7 +88,7 @@ pcmk_new_ipc_api(pcmk_ipc_api_t **api, enum pcmk_ipc_server server)
26ad17
 
26ad17
         case pcmk_ipc_schedulerd:
26ad17
             // @TODO max_size could vary by client, maybe take as argument?
26ad17
-            max_size = 5 * 1024 * 1024; // 5MB
26ad17
+            (*api)->ipc_size_max = 5 * 1024 * 1024; // 5MB
26ad17
             break;
26ad17
     }
26ad17
     if ((*api)->cmds == NULL) {
26ad17
@@ -97,7 +97,8 @@ pcmk_new_ipc_api(pcmk_ipc_api_t **api, enum pcmk_ipc_server server)
26ad17
         return ENOMEM;
26ad17
     }
26ad17
 
26ad17
-    (*api)->ipc = crm_ipc_new(pcmk_ipc_name(*api, false), max_size);
26ad17
+    (*api)->ipc = crm_ipc_new(pcmk_ipc_name(*api, false),
26ad17
+                              (*api)->ipc_size_max);
26ad17
     if ((*api)->ipc == NULL) {
26ad17
         pcmk_free_ipc_api(*api);
26ad17
         *api = NULL;
26ad17
@@ -451,11 +452,20 @@ pcmk_connect_ipc(pcmk_ipc_api_t *api, enum pcmk_ipc_dispatch dispatch_type)
26ad17
 {
26ad17
     int rc = pcmk_rc_ok;
26ad17
 
26ad17
-    if ((api == NULL) || (api->ipc == NULL)) {
26ad17
+    if (api == NULL) {
26ad17
         crm_err("Cannot connect to uninitialized API object");
26ad17
         return EINVAL;
26ad17
     }
26ad17
 
26ad17
+    if (api->ipc == NULL) {
26ad17
+        api->ipc = crm_ipc_new(pcmk_ipc_name(api, false),
26ad17
+                                  api->ipc_size_max);
26ad17
+        if (api->ipc == NULL) {
26ad17
+            crm_err("Failed to re-create IPC API");
26ad17
+            return ENOMEM;
26ad17
+        }
26ad17
+    }
26ad17
+
26ad17
     if (crm_ipc_connected(api->ipc)) {
26ad17
         crm_trace("Already connected to %s IPC API", pcmk_ipc_name(api, true));
26ad17
         return pcmk_rc_ok;
26ad17
-- 
26ad17
1.8.3.1
26ad17
26ad17
26ad17
From e5ad1a6c54da48c86c8ab262abd4921cb37e998d Mon Sep 17 00:00:00 2001
26ad17
From: Klaus Wenninger <klaus.wenninger@aon.at>
26ad17
Date: Mon, 20 Jul 2020 18:18:01 +0200
26ad17
Subject: [PATCH 2/6] Fix: ipc-api: avoid infinite loop when disconnected
26ad17
26ad17
Happens when using pcmk_dispatch_ipc when dispatching without
26ad17
mainloop.
26ad17
---
26ad17
 lib/common/ipc_client.c | 2 +-
26ad17
 1 file changed, 1 insertion(+), 1 deletion(-)
26ad17
26ad17
diff --git a/lib/common/ipc_client.c b/lib/common/ipc_client.c
26ad17
index df687da..aa032fe 100644
26ad17
--- a/lib/common/ipc_client.c
26ad17
+++ b/lib/common/ipc_client.c
26ad17
@@ -392,7 +392,7 @@ pcmk_dispatch_ipc(pcmk_ipc_api_t *api)
26ad17
     if (api == NULL) {
26ad17
         return;
26ad17
     }
26ad17
-    while (crm_ipc_ready(api->ipc)) {
26ad17
+    while (crm_ipc_ready(api->ipc) > 0) {
26ad17
         if (crm_ipc_read(api->ipc) > 0) {
26ad17
             dispatch_ipc_data(crm_ipc_buffer(api->ipc), 0, api);
26ad17
         }
26ad17
-- 
26ad17
1.8.3.1
26ad17
26ad17
26ad17
From 927b43a57d5e8256fbce8fe0792f8ea228c57687 Mon Sep 17 00:00:00 2001
26ad17
From: Klaus Wenninger <klaus.wenninger@aon.at>
26ad17
Date: Mon, 9 Dec 2019 15:13:11 +0100
26ad17
Subject: [PATCH 3/6] Fix: sbd-integration: sync pacemakerd with sbd
26ad17
26ad17
Make pacemakerd wait to be pinged by sbd before starting
26ad17
sub-daemons. Pings further reply health-state and timestamp
26ad17
of last successful check. On shutdown bring down all the
26ad17
sub-daemons and wait to be polled for state by sbd before
26ad17
finally exiting pacemakerd.
26ad17
Add new api as not to make the xml-structure an external interface.
26ad17
---
26ad17
 daemons/pacemakerd/pacemakerd.c     | 100 ++++++++++++++--
26ad17
 include/crm/common/Makefile.am      |   2 +-
26ad17
 include/crm/common/ipc_pacemakerd.h |  71 +++++++++++
26ad17
 include/crm/msg_xml.h               |   7 ++
26ad17
 lib/common/Makefile.am              |   1 +
26ad17
 lib/common/crmcommon_private.h      |   3 +
26ad17
 lib/common/ipc_client.c             |   5 +-
26ad17
 lib/common/ipc_pacemakerd.c         | 232 ++++++++++++++++++++++++++++++++++++
26ad17
 8 files changed, 410 insertions(+), 11 deletions(-)
26ad17
 create mode 100644 include/crm/common/ipc_pacemakerd.h
26ad17
 create mode 100644 lib/common/ipc_pacemakerd.c
26ad17
26ad17
diff --git a/daemons/pacemakerd/pacemakerd.c b/daemons/pacemakerd/pacemakerd.c
26ad17
index 652d6ca..ccfae66 100644
26ad17
--- a/daemons/pacemakerd/pacemakerd.c
26ad17
+++ b/daemons/pacemakerd/pacemakerd.c
26ad17
@@ -40,8 +40,25 @@ static bool global_keep_tracking = false;
26ad17
 #define PCMK_PROCESS_CHECK_INTERVAL 5
26ad17
 
26ad17
 static crm_trigger_t *shutdown_trigger = NULL;
26ad17
+static crm_trigger_t *startup_trigger = NULL;
26ad17
 static const char *pid_file = PCMK_RUN_DIR "/pacemaker.pid";
26ad17
 
26ad17
+/* state we report when asked via pacemakerd-api status-ping */
26ad17
+static const char *pacemakerd_state = XML_PING_ATTR_PACEMAKERDSTATE_INIT;
26ad17
+static gboolean running_with_sbd = FALSE; /* local copy */
26ad17
+/* When contacted via pacemakerd-api by a client having sbd in
26ad17
+ * the name we assume it is sbd-daemon which wants to know
26ad17
+ * if pacemakerd shutdown gracefully.
26ad17
+ * Thus when everything is shutdown properly pacemakerd
26ad17
+ * waits till it has reported the graceful completion of
26ad17
+ * shutdown to sbd and just when sbd-client closes the
26ad17
+ * connection we can assume that the report has arrived
26ad17
+ * properly so that pacemakerd can finally exit.
26ad17
+ * Following two variables are used to track that handshake.
26ad17
+ */
26ad17
+static unsigned int shutdown_complete_state_reported_to = 0;
26ad17
+static gboolean shutdown_complete_state_reported_client_closed = FALSE;
26ad17
+
26ad17
 typedef struct pcmk_child_s {
26ad17
     pid_t pid;
26ad17
     long flag;
26ad17
@@ -374,21 +391,20 @@ escalate_shutdown(gpointer data)
26ad17
 static gboolean
26ad17
 pcmk_shutdown_worker(gpointer user_data)
26ad17
 {
26ad17
-    static int phase = 0;
26ad17
+    static int phase = SIZEOF(pcmk_children);
26ad17
     static time_t next_log = 0;
26ad17
-    static int max = SIZEOF(pcmk_children);
26ad17
 
26ad17
     int lpc = 0;
26ad17
 
26ad17
-    if (phase == 0) {
26ad17
+    if (phase == SIZEOF(pcmk_children)) {
26ad17
         crm_notice("Shutting down Pacemaker");
26ad17
-        phase = max;
26ad17
+        pacemakerd_state = XML_PING_ATTR_PACEMAKERDSTATE_SHUTTINGDOWN;
26ad17
     }
26ad17
 
26ad17
     for (; phase > 0; phase--) {
26ad17
         /* Don't stop anything with start_seq < 1 */
26ad17
 
26ad17
-        for (lpc = max - 1; lpc >= 0; lpc--) {
26ad17
+        for (lpc = SIZEOF(pcmk_children) - 1; lpc >= 0; lpc--) {
26ad17
             pcmk_child_t *child = &(pcmk_children[lpc]);
26ad17
 
26ad17
             if (phase != child->start_seq) {
26ad17
@@ -436,6 +452,11 @@ pcmk_shutdown_worker(gpointer user_data)
26ad17
     }
26ad17
 
26ad17
     crm_notice("Shutdown complete");
26ad17
+    pacemakerd_state = XML_PING_ATTR_PACEMAKERDSTATE_SHUTDOWNCOMPLETE;
26ad17
+    if (!fatal_error && running_with_sbd &&
26ad17
+        !shutdown_complete_state_reported_client_closed) {
26ad17
+        return TRUE;
26ad17
+    }
26ad17
 
26ad17
     {
26ad17
         const char *delay = pcmk__env_option("shutdown_delay");
26ad17
@@ -489,6 +510,51 @@ pcmk_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
26ad17
     return 0;
26ad17
 }
26ad17
 
26ad17
+static void
26ad17
+pcmk_handle_ping_request(pcmk__client_t *c, xmlNode *msg, uint32_t id)
26ad17
+{
26ad17
+    const char *value = NULL;
26ad17
+    xmlNode *ping = NULL;
26ad17
+    xmlNode *reply = NULL;
26ad17
+    time_t pinged = time(NULL);
26ad17
+    const char *from = crm_element_value(msg, F_CRM_SYS_FROM);
26ad17
+
26ad17
+    /* Pinged for status */
26ad17
+    crm_trace("Pinged from %s.%s",
26ad17
+              crm_str(crm_element_value(msg, F_CRM_ORIGIN)),
26ad17
+              from?from:"unknown");
26ad17
+    ping = create_xml_node(NULL, XML_CRM_TAG_PING);
26ad17
+    value = crm_element_value(msg, F_CRM_SYS_TO);
26ad17
+    crm_xml_add(ping, XML_PING_ATTR_SYSFROM, value);
26ad17
+    crm_xml_add(ping, XML_PING_ATTR_PACEMAKERDSTATE, pacemakerd_state);
26ad17
+    crm_xml_add_ll(ping, XML_ATTR_TSTAMP, (long long) pinged);
26ad17
+    crm_xml_add(ping, XML_PING_ATTR_STATUS, "ok");
26ad17
+    reply = create_reply(msg, ping);
26ad17
+    free_xml(ping);
26ad17
+    if (reply) {
26ad17
+        if (pcmk__ipc_send_xml(c, id, reply, crm_ipc_server_event) !=
26ad17
+                pcmk_rc_ok) {
26ad17
+            crm_err("Failed sending ping-reply");
26ad17
+        }
26ad17
+        free_xml(reply);
26ad17
+    } else {
26ad17
+        crm_err("Failed building ping-reply");
26ad17
+    }
26ad17
+    /* just proceed state on sbd pinging us */
26ad17
+    if (from && strstr(from, "sbd")) {
26ad17
+        if (crm_str_eq(pacemakerd_state,
26ad17
+                       XML_PING_ATTR_PACEMAKERDSTATE_SHUTDOWNCOMPLETE,
26ad17
+                       TRUE)) {
26ad17
+            shutdown_complete_state_reported_to = c->pid;
26ad17
+        } else if (crm_str_eq(pacemakerd_state,
26ad17
+                              XML_PING_ATTR_PACEMAKERDSTATE_WAITPING,
26ad17
+                              TRUE)) {
26ad17
+            pacemakerd_state = XML_PING_ATTR_PACEMAKERDSTATE_STARTINGDAEMONS;
26ad17
+            mainloop_set_trigger(startup_trigger);
26ad17
+        }
26ad17
+    }
26ad17
+}
26ad17
+
26ad17
 /* Exit code means? */
26ad17
 static int32_t
26ad17
 pcmk_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size)
26ad17
@@ -514,6 +580,9 @@ pcmk_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size)
26ad17
         crm_trace("Ignoring IPC request to purge node "
26ad17
                   "because peer cache is not used");
26ad17
 
26ad17
+    } else if (crm_str_eq(task, CRM_OP_PING, TRUE)) {
26ad17
+        pcmk_handle_ping_request(c, msg, id);
26ad17
+
26ad17
     } else {
26ad17
         crm_debug("Unrecognized IPC command '%s' sent to pacemakerd",
26ad17
                   crm_str(task));
26ad17
@@ -533,6 +602,12 @@ pcmk_ipc_closed(qb_ipcs_connection_t * c)
26ad17
         return 0;
26ad17
     }
26ad17
     crm_trace("Connection %p", c);
26ad17
+    if (shutdown_complete_state_reported_to == client->pid) {
26ad17
+        shutdown_complete_state_reported_client_closed = TRUE;
26ad17
+        if (shutdown_trigger) {
26ad17
+            mainloop_set_trigger(shutdown_trigger);
26ad17
+        }
26ad17
+    }
26ad17
     pcmk__free_client(client);
26ad17
     return 0;
26ad17
 }
26ad17
@@ -924,8 +999,8 @@ find_and_track_existing_processes(void)
26ad17
     return pcmk_rc_ok;
26ad17
 }
26ad17
 
26ad17
-static void
26ad17
-init_children_processes(void)
26ad17
+static gboolean
26ad17
+init_children_processes(void *user_data)
26ad17
 {
26ad17
     int start_seq = 1, lpc = 0;
26ad17
     static int max = SIZEOF(pcmk_children);
26ad17
@@ -951,6 +1026,8 @@ init_children_processes(void)
26ad17
      * This may be useful for the daemons to know
26ad17
      */
26ad17
     setenv("PCMK_respawned", "true", 1);
26ad17
+    pacemakerd_state = XML_PING_ATTR_PACEMAKERDSTATE_RUNNING;
26ad17
+    return TRUE;
26ad17
 }
26ad17
 
26ad17
 static void
26ad17
@@ -1154,6 +1231,7 @@ main(int argc, char **argv)
26ad17
 
26ad17
     if(pcmk_locate_sbd() > 0) {
26ad17
         setenv("PCMK_watchdog", "true", 1);
26ad17
+        running_with_sbd = TRUE;
26ad17
     } else {
26ad17
         setenv("PCMK_watchdog", "false", 1);
26ad17
     }
26ad17
@@ -1170,7 +1248,13 @@ main(int argc, char **argv)
26ad17
     mainloop_add_signal(SIGTERM, pcmk_shutdown);
26ad17
     mainloop_add_signal(SIGINT, pcmk_shutdown);
26ad17
 
26ad17
-    init_children_processes();
26ad17
+    if (running_with_sbd) {
26ad17
+        pacemakerd_state = XML_PING_ATTR_PACEMAKERDSTATE_WAITPING;
26ad17
+        startup_trigger = mainloop_add_trigger(G_PRIORITY_HIGH, init_children_processes, NULL);
26ad17
+    } else {
26ad17
+        pacemakerd_state = XML_PING_ATTR_PACEMAKERDSTATE_STARTINGDAEMONS;
26ad17
+        init_children_processes(NULL);
26ad17
+    }
26ad17
 
26ad17
     crm_notice("Pacemaker daemon successfully started and accepting connections");
26ad17
     g_main_loop_run(mainloop);
26ad17
diff --git a/include/crm/common/Makefile.am b/include/crm/common/Makefile.am
26ad17
index f29d105..1b5730a 100644
26ad17
--- a/include/crm/common/Makefile.am
26ad17
+++ b/include/crm/common/Makefile.am
26ad17
@@ -12,7 +12,7 @@ MAINTAINERCLEANFILES = Makefile.in
26ad17
 headerdir=$(pkgincludedir)/crm/common
26ad17
 
26ad17
 header_HEADERS = xml.h ipc.h util.h iso8601.h mainloop.h logging.h results.h \
26ad17
-		 nvpair.h acl.h ipc_controld.h
26ad17
+		 nvpair.h acl.h ipc_controld.h ipc_pacemakerd.h
26ad17
 noinst_HEADERS = internal.h alerts_internal.h \
26ad17
 		 iso8601_internal.h remote_internal.h xml_internal.h \
26ad17
 		 ipc_internal.h output.h cmdline_internal.h curses_internal.h \
26ad17
diff --git a/include/crm/common/ipc_pacemakerd.h b/include/crm/common/ipc_pacemakerd.h
26ad17
new file mode 100644
26ad17
index 0000000..00e3edd
26ad17
--- /dev/null
26ad17
+++ b/include/crm/common/ipc_pacemakerd.h
26ad17
@@ -0,0 +1,71 @@
26ad17
+/*
26ad17
+ * Copyright 2020 the Pacemaker project contributors
26ad17
+ *
26ad17
+ * The version control history for this file may have further details.
26ad17
+ *
26ad17
+ * This source code is licensed under the GNU Lesser General Public License
26ad17
+ * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
26ad17
+ */
26ad17
+
26ad17
+#ifndef PCMK__IPC_PACEMAKERD__H
26ad17
+#  define PCMK__IPC_PACEMAKERD__H
26ad17
+
26ad17
+#ifdef __cplusplus
26ad17
+extern "C" {
26ad17
+#endif
26ad17
+
26ad17
+/**
26ad17
+ * \file
26ad17
+ * \brief IPC commands for Pacemakerd
26ad17
+ *
26ad17
+ * \ingroup core
26ad17
+ */
26ad17
+
26ad17
+#include <sys/types.h>       // time_t
26ad17
+#include <crm/common/ipc.h>  // pcmk_ipc_api_t
26ad17
+
26ad17
+enum pcmk_pacemakerd_state {
26ad17
+    pcmk_pacemakerd_state_invalid = -1,
26ad17
+    pcmk_pacemakerd_state_init = 0,
26ad17
+    pcmk_pacemakerd_state_starting_daemons,
26ad17
+    pcmk_pacemakerd_state_wait_for_ping,
26ad17
+    pcmk_pacemakerd_state_running,
26ad17
+    pcmk_pacemakerd_state_shutting_down,
26ad17
+    pcmk_pacemakerd_state_shutdown_complete,
26ad17
+    pcmk_pacemakerd_state_max = pcmk_pacemakerd_state_shutdown_complete,
26ad17
+};
26ad17
+
26ad17
+//! Possible types of pacemakerd replies
26ad17
+enum pcmk_pacemakerd_api_reply {
26ad17
+    pcmk_pacemakerd_reply_unknown,
26ad17
+    pcmk_pacemakerd_reply_ping,
26ad17
+};
26ad17
+
26ad17
+/*!
26ad17
+ * Pacemakerd reply passed to event callback
26ad17
+ */
26ad17
+typedef struct {
26ad17
+    enum pcmk_pacemakerd_api_reply reply_type;
26ad17
+
26ad17
+    union {
26ad17
+        // pcmk_pacemakerd_reply_ping
26ad17
+        struct {
26ad17
+            const char *sys_from;
26ad17
+            enum pcmk_pacemakerd_state state;
26ad17
+            time_t last_good;
26ad17
+            int status;
26ad17
+        } ping;
26ad17
+    } data;
26ad17
+} pcmk_pacemakerd_api_reply_t;
26ad17
+
26ad17
+int pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name);
26ad17
+enum pcmk_pacemakerd_state
26ad17
+    pcmk_pacemakerd_api_daemon_state_text2enum(const char *state);
26ad17
+const char
26ad17
+    *pcmk_pacemakerd_api_daemon_state_enum2text(enum pcmk_pacemakerd_state state);
26ad17
+
26ad17
+#ifdef __cplusplus
26ad17
+}
26ad17
+#endif
26ad17
+
26ad17
+#endif // PCMK__IPC_PACEMAKERD__H
26ad17
diff --git a/include/crm/msg_xml.h b/include/crm/msg_xml.h
26ad17
index af3f33e..1fcb72d 100644
26ad17
--- a/include/crm/msg_xml.h
26ad17
+++ b/include/crm/msg_xml.h
26ad17
@@ -123,6 +123,13 @@ extern "C" {
26ad17
 #  define XML_PING_ATTR_STATUS		"result"
26ad17
 #  define XML_PING_ATTR_SYSFROM		"crm_subsystem"
26ad17
 #  define XML_PING_ATTR_CRMDSTATE   "crmd_state"
26ad17
+#  define XML_PING_ATTR_PACEMAKERDSTATE "pacemakerd_state"
26ad17
+#  define XML_PING_ATTR_PACEMAKERDSTATE_INIT "init"
26ad17
+#  define XML_PING_ATTR_PACEMAKERDSTATE_STARTINGDAEMONS "starting_daemons"
26ad17
+#  define XML_PING_ATTR_PACEMAKERDSTATE_WAITPING "wait_for_ping"
26ad17
+#  define XML_PING_ATTR_PACEMAKERDSTATE_RUNNING "running"
26ad17
+#  define XML_PING_ATTR_PACEMAKERDSTATE_SHUTTINGDOWN "shutting_down"
26ad17
+#  define XML_PING_ATTR_PACEMAKERDSTATE_SHUTDOWNCOMPLETE "shutdown_complete"
26ad17
 
26ad17
 #  define XML_TAG_FRAGMENT		"cib_fragment"
26ad17
 
26ad17
diff --git a/lib/common/Makefile.am b/lib/common/Makefile.am
26ad17
index db66a6e..e0249b9 100644
26ad17
--- a/lib/common/Makefile.am
26ad17
+++ b/lib/common/Makefile.am
26ad17
@@ -50,6 +50,7 @@ libcrmcommon_la_SOURCES	+= io.c
26ad17
 libcrmcommon_la_SOURCES	+= ipc_client.c
26ad17
 libcrmcommon_la_SOURCES	+= ipc_common.c
26ad17
 libcrmcommon_la_SOURCES	+= ipc_controld.c
26ad17
+libcrmcommon_la_SOURCES	+= ipc_pacemakerd.c
26ad17
 libcrmcommon_la_SOURCES	+= ipc_server.c
26ad17
 libcrmcommon_la_SOURCES	+= iso8601.c
26ad17
 libcrmcommon_la_SOURCES	+= logging.c
26ad17
diff --git a/lib/common/crmcommon_private.h b/lib/common/crmcommon_private.h
26ad17
index d55df99..68e3390 100644
26ad17
--- a/lib/common/crmcommon_private.h
26ad17
+++ b/lib/common/crmcommon_private.h
26ad17
@@ -210,4 +210,7 @@ bool pcmk__valid_ipc_header(const pcmk__ipc_header_t *header);
26ad17
 G_GNUC_INTERNAL
26ad17
 pcmk__ipc_methods_t *pcmk__controld_api_methods(void);
26ad17
 
26ad17
+G_GNUC_INTERNAL
26ad17
+pcmk__ipc_methods_t *pcmk__pacemakerd_api_methods(void);
26ad17
+
26ad17
 #endif  // CRMCOMMON_PRIVATE__H
26ad17
diff --git a/lib/common/ipc_client.c b/lib/common/ipc_client.c
26ad17
index aa032fe..033199d 100644
26ad17
--- a/lib/common/ipc_client.c
26ad17
+++ b/lib/common/ipc_client.c
26ad17
@@ -41,7 +41,7 @@
26ad17
  *
26ad17
  * \note The caller is responsible for freeing *api using pcmk_free_ipc_api().
26ad17
  * \note This is intended to supersede crm_ipc_new() but currently only
26ad17
- *       supports the controller IPC API.
26ad17
+ *       supports the controller & pacemakerd IPC API.
26ad17
  */
26ad17
 int
26ad17
 pcmk_new_ipc_api(pcmk_ipc_api_t **api, enum pcmk_ipc_server server)
26ad17
@@ -84,6 +84,7 @@ pcmk_new_ipc_api(pcmk_ipc_api_t **api, enum pcmk_ipc_server server)
26ad17
             break;
26ad17
 
26ad17
         case pcmk_ipc_pacemakerd:
26ad17
+            (*api)->cmds = pcmk__pacemakerd_api_methods();
26ad17
             break;
26ad17
 
26ad17
         case pcmk_ipc_schedulerd:
26ad17
@@ -259,7 +260,7 @@ pcmk_ipc_name(pcmk_ipc_api_t *api, bool for_log)
26ad17
             return for_log? "fencer" : NULL /* "stonith-ng" */;
26ad17
 
26ad17
         case pcmk_ipc_pacemakerd:
26ad17
-            return for_log? "launcher" : NULL /* CRM_SYSTEM_MCP */;
26ad17
+            return for_log? "launcher" : CRM_SYSTEM_MCP;
26ad17
 
26ad17
         case pcmk_ipc_schedulerd:
26ad17
             return for_log? "scheduler" : NULL /* CRM_SYSTEM_PENGINE */;
26ad17
diff --git a/lib/common/ipc_pacemakerd.c b/lib/common/ipc_pacemakerd.c
26ad17
new file mode 100644
26ad17
index 0000000..241722e
26ad17
--- /dev/null
26ad17
+++ b/lib/common/ipc_pacemakerd.c
26ad17
@@ -0,0 +1,232 @@
26ad17
+/*
26ad17
+ * Copyright 2020 the Pacemaker project contributors
26ad17
+ *
26ad17
+ * The version control history for this file may have further details.
26ad17
+ *
26ad17
+ * This source code is licensed under the GNU Lesser General Public License
26ad17
+ * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
26ad17
+ */
26ad17
+
26ad17
+#include <crm_internal.h>
26ad17
+
26ad17
+#include <stdlib.h>
26ad17
+#include <time.h>
26ad17
+
26ad17
+#include <crm/crm.h>
26ad17
+#include <crm/msg_xml.h>
26ad17
+#include <crm/common/xml.h>
26ad17
+#include <crm/common/ipc.h>
26ad17
+#include <crm/common/ipc_internal.h>
26ad17
+#include <crm/common/ipc_pacemakerd.h>
26ad17
+#include "crmcommon_private.h"
26ad17
+
26ad17
+typedef struct pacemakerd_api_private_s {
26ad17
+    enum pcmk_pacemakerd_state state;
26ad17
+    char *client_uuid;
26ad17
+} pacemakerd_api_private_t;
26ad17
+
26ad17
+static const char *pacemakerd_state_str[] = {
26ad17
+    XML_PING_ATTR_PACEMAKERDSTATE_INIT,
26ad17
+    XML_PING_ATTR_PACEMAKERDSTATE_STARTINGDAEMONS,
26ad17
+    XML_PING_ATTR_PACEMAKERDSTATE_WAITPING,
26ad17
+    XML_PING_ATTR_PACEMAKERDSTATE_RUNNING,
26ad17
+    XML_PING_ATTR_PACEMAKERDSTATE_SHUTTINGDOWN,
26ad17
+    XML_PING_ATTR_PACEMAKERDSTATE_SHUTDOWNCOMPLETE
26ad17
+};
26ad17
+
26ad17
+enum pcmk_pacemakerd_state
26ad17
+pcmk_pacemakerd_api_daemon_state_text2enum(const char *state)
26ad17
+{
26ad17
+    int i;
26ad17
+
26ad17
+    if (state == NULL) {
26ad17
+        return pcmk_pacemakerd_state_invalid;
26ad17
+    }
26ad17
+    for (i=pcmk_pacemakerd_state_init; i <= pcmk_pacemakerd_state_max;
26ad17
+         i++) {
26ad17
+        if (crm_str_eq(state, pacemakerd_state_str[i], TRUE)) {
26ad17
+            return i;
26ad17
+        }
26ad17
+    }
26ad17
+    return pcmk_pacemakerd_state_invalid;
26ad17
+}
26ad17
+
26ad17
+const char *
26ad17
+pcmk_pacemakerd_api_daemon_state_enum2text(
26ad17
+    enum pcmk_pacemakerd_state state)
26ad17
+{
26ad17
+    if ((state >= pcmk_pacemakerd_state_init) &&
26ad17
+        (state <= pcmk_pacemakerd_state_max)) {
26ad17
+        return pacemakerd_state_str[state];
26ad17
+    }
26ad17
+    return "invalid";
26ad17
+}
26ad17
+
26ad17
+// \return Standard Pacemaker return code
26ad17
+static int
26ad17
+new_data(pcmk_ipc_api_t *api)
26ad17
+{
26ad17
+    struct pacemakerd_api_private_s *private = NULL;
26ad17
+
26ad17
+    api->api_data = calloc(1, sizeof(struct pacemakerd_api_private_s));
26ad17
+
26ad17
+    if (api->api_data == NULL) {
26ad17
+        return errno;
26ad17
+    }
26ad17
+
26ad17
+    private = api->api_data;
26ad17
+    private->state = pcmk_pacemakerd_state_invalid;
26ad17
+    /* other as with cib, controld, ... we are addressing pacemakerd just
26ad17
+       from the local node -> pid is unique and thus sufficient as an ID
26ad17
+     */
26ad17
+    private->client_uuid = pcmk__getpid_s();
26ad17
+
26ad17
+    return pcmk_rc_ok;
26ad17
+}
26ad17
+
26ad17
+static void
26ad17
+free_data(void *data)
26ad17
+{
26ad17
+    free(((struct pacemakerd_api_private_s *) data)->client_uuid);
26ad17
+    free(data);
26ad17
+}
26ad17
+
26ad17
+// \return Standard Pacemaker return code
26ad17
+static int
26ad17
+post_connect(pcmk_ipc_api_t *api)
26ad17
+{
26ad17
+    struct pacemakerd_api_private_s *private = NULL;
26ad17
+
26ad17
+    if (api->api_data == NULL) {
26ad17
+        return EINVAL;
26ad17
+    }
26ad17
+    private = api->api_data;
26ad17
+    private->state = pcmk_pacemakerd_state_invalid;
26ad17
+
26ad17
+    return pcmk_rc_ok;
26ad17
+}
26ad17
+
26ad17
+static void
26ad17
+post_disconnect(pcmk_ipc_api_t *api)
26ad17
+{
26ad17
+    struct pacemakerd_api_private_s *private = NULL;
26ad17
+
26ad17
+    if (api->api_data == NULL) {
26ad17
+        return;
26ad17
+    }
26ad17
+    private = api->api_data;
26ad17
+    private->state = pcmk_pacemakerd_state_invalid;
26ad17
+
26ad17
+    return;
26ad17
+}
26ad17
+
26ad17
+static bool
26ad17
+reply_expected(pcmk_ipc_api_t *api, xmlNode *request)
26ad17
+{
26ad17
+    const char *command = crm_element_value(request, F_CRM_TASK);
26ad17
+
26ad17
+    if (command == NULL) {
26ad17
+        return false;
26ad17
+    }
26ad17
+
26ad17
+    // We only need to handle commands that functions in this file can send
26ad17
+    return !strcmp(command, CRM_OP_PING);
26ad17
+}
26ad17
+
26ad17
+static void
26ad17
+dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
26ad17
+{
26ad17
+    crm_exit_t status = CRM_EX_OK;
26ad17
+    xmlNode *msg_data = NULL;
26ad17
+    pcmk_pacemakerd_api_reply_t reply_data = {
26ad17
+        pcmk_pacemakerd_reply_unknown
26ad17
+    };
26ad17
+    const char *value = NULL;
26ad17
+    long long value_ll = 0;
26ad17
+
26ad17
+    value = crm_element_value(reply, F_CRM_MSG_TYPE);
26ad17
+    if ((value == NULL) || (strcmp(value, XML_ATTR_RESPONSE))) {
26ad17
+        crm_debug("Unrecognizable pacemakerd message: invalid message type '%s'",
26ad17
+                  crm_str(value));
26ad17
+        status = CRM_EX_PROTOCOL;
26ad17
+        goto done;
26ad17
+    }
26ad17
+
26ad17
+    if (crm_element_value(reply, XML_ATTR_REFERENCE) == NULL) {
26ad17
+        crm_debug("Unrecognizable pacemakerd message: no reference");
26ad17
+        status = CRM_EX_PROTOCOL;
26ad17
+        goto done;
26ad17
+    }
26ad17
+
26ad17
+    value = crm_element_value(reply, F_CRM_TASK);
26ad17
+    if ((value == NULL) || strcmp(value, CRM_OP_PING)) {
26ad17
+        crm_debug("Unrecognizable pacemakerd message: '%s'", crm_str(value));
26ad17
+        status = CRM_EX_PROTOCOL;
26ad17
+        goto done;
26ad17
+    }
26ad17
+
26ad17
+    // Parse useful info from reply
26ad17
+
26ad17
+    msg_data = get_message_xml(reply, F_CRM_DATA);
26ad17
+    crm_element_value_ll(msg_data, XML_ATTR_TSTAMP, &value_ll);
26ad17
+
26ad17
+    reply_data.reply_type = pcmk_pacemakerd_reply_ping;
26ad17
+    reply_data.data.ping.state =
26ad17
+        pcmk_pacemakerd_api_daemon_state_text2enum(
26ad17
+            crm_element_value(msg_data, XML_PING_ATTR_PACEMAKERDSTATE));
26ad17
+    reply_data.data.ping.status =
26ad17
+        crm_str_eq(crm_element_value(msg_data, XML_PING_ATTR_STATUS),
26ad17
+                   "ok", FALSE)?pcmk_rc_ok:pcmk_rc_error;
26ad17
+    reply_data.data.ping.last_good = (time_t) value_ll;
26ad17
+    reply_data.data.ping.sys_from = crm_element_value(msg_data,
26ad17
+                                        XML_PING_ATTR_SYSFROM);
26ad17
+
26ad17
+done:
26ad17
+    pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
26ad17
+}
26ad17
+
26ad17
+pcmk__ipc_methods_t *
26ad17
+pcmk__pacemakerd_api_methods()
26ad17
+{
26ad17
+    pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
26ad17
+
26ad17
+    if (cmds != NULL) {
26ad17
+        cmds->new_data = new_data;
26ad17
+        cmds->free_data = free_data;
26ad17
+        cmds->post_connect = post_connect;
26ad17
+        cmds->reply_expected = reply_expected;
26ad17
+        cmds->dispatch = dispatch;
26ad17
+        cmds->post_disconnect = post_disconnect;
26ad17
+    }
26ad17
+    return cmds;
26ad17
+}
26ad17
+
26ad17
+int
26ad17
+pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
26ad17
+{
26ad17
+    pacemakerd_api_private_t *private;
26ad17
+    xmlNode *cmd;
26ad17
+    int rc;
26ad17
+
26ad17
+    CRM_CHECK(api != NULL, return -EINVAL);
26ad17
+    private = api->api_data;
26ad17
+    CRM_ASSERT(private != NULL);
26ad17
+
26ad17
+    cmd = create_request(CRM_OP_PING, NULL, NULL, CRM_SYSTEM_MCP,
26ad17
+        ipc_name?ipc_name:((crm_system_name? crm_system_name : "client")),
26ad17
+        private->client_uuid);
26ad17
+
26ad17
+    if (cmd) {
26ad17
+        rc = pcmk__send_ipc_request(api, cmd);
26ad17
+        if (rc != pcmk_rc_ok) {
26ad17
+            crm_debug("Couldn't ping pacemakerd: %s rc=%d",
26ad17
+                pcmk_rc_str(rc), rc);
26ad17
+            rc = ECOMM;
26ad17
+        }
26ad17
+        free_xml(cmd);
26ad17
+    } else {
26ad17
+        rc = ENOMSG;
26ad17
+    }
26ad17
+
26ad17
+    return rc;
26ad17
+}
26ad17
-- 
26ad17
1.8.3.1
26ad17
26ad17
26ad17
From 06da3c3685b0bdf093a13067cc399e782115e39c Mon Sep 17 00:00:00 2001
26ad17
From: Klaus Wenninger <klaus.wenninger@aon.at>
26ad17
Date: Mon, 20 Jul 2020 23:28:32 +0200
26ad17
Subject: [PATCH 4/6] Feature: tools: Add -P to crmadmin to ping via
26ad17
 pacemakerd-api
26ad17
26ad17
---
26ad17
 include/crm/crm.h |   2 +-
26ad17
 tools/crmadmin.c  | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++----
26ad17
 2 files changed, 152 insertions(+), 11 deletions(-)
26ad17
26ad17
diff --git a/include/crm/crm.h b/include/crm/crm.h
26ad17
index dc2adc1..ce2074b 100644
26ad17
--- a/include/crm/crm.h
26ad17
+++ b/include/crm/crm.h
26ad17
@@ -51,7 +51,7 @@ extern "C" {
26ad17
  * >=3.0.13: Fail counts include operation name and interval
26ad17
  * >=3.2.0:  DC supports PCMK_LRM_OP_INVALID and PCMK_LRM_OP_NOT_CONNECTED
26ad17
  */
26ad17
-#  define CRM_FEATURE_SET		"3.4.0"
26ad17
+#  define CRM_FEATURE_SET		"3.4.1"
26ad17
 
26ad17
 #  define EOS		'\0'
26ad17
 #  define DIMOF(a)	((int) (sizeof(a)/sizeof(a[0])) )
26ad17
diff --git a/tools/crmadmin.c b/tools/crmadmin.c
26ad17
index 4688458..2ebdd14 100644
26ad17
--- a/tools/crmadmin.c
26ad17
+++ b/tools/crmadmin.c
26ad17
@@ -20,7 +20,9 @@
26ad17
 #include <crm/cib.h>
26ad17
 #include <crm/msg_xml.h>
26ad17
 #include <crm/common/xml.h>
26ad17
+#include <crm/common/iso8601.h>
26ad17
 #include <crm/common/ipc_controld.h>
26ad17
+#include <crm/common/ipc_pacemakerd.h>
26ad17
 #include <crm/common/mainloop.h>
26ad17
 
26ad17
 #define DEFAULT_MESSAGE_TIMEOUT_MS 30000
26ad17
@@ -31,6 +33,8 @@ static GMainLoop *mainloop = NULL;
26ad17
 
26ad17
 bool do_work(pcmk_ipc_api_t *api);
26ad17
 void do_find_node_list(xmlNode *xml_node);
26ad17
+static char *ipc_name = NULL;
26ad17
+
26ad17
 gboolean admin_message_timeout(gpointer data);
26ad17
 
26ad17
 static enum {
26ad17
@@ -40,6 +44,7 @@ static enum {
26ad17
     cmd_elect_dc,
26ad17
     cmd_whois_dc,
26ad17
     cmd_list_nodes,
26ad17
+    cmd_pacemakerd_health,
26ad17
 } command = cmd_none;
26ad17
 
26ad17
 static gboolean BE_VERBOSE = FALSE;
26ad17
@@ -82,6 +87,15 @@ static pcmk__cli_option_t long_options[] = {
26ad17
         pcmk__option_default
26ad17
     },
26ad17
     {
26ad17
+        "pacemakerd", no_argument, NULL, 'P',
26ad17
+        "Display the status of local pacemakerd.", pcmk__option_default
26ad17
+    },
26ad17
+    {
26ad17
+        "-spacer-", no_argument, NULL, '-',
26ad17
+        "\n\tResult is the state of the sub-daemons watched by pacemakerd.\n",
26ad17
+        pcmk__option_default
26ad17
+    },
26ad17
+    {
26ad17
         "dc_lookup", no_argument, NULL, 'D',
26ad17
         "Display the uname of the node co-ordinating the cluster.",
26ad17
         pcmk__option_default
26ad17
@@ -122,16 +136,21 @@ static pcmk__cli_option_t long_options[] = {
26ad17
     {
26ad17
         "bash-export", no_argument, NULL, 'B',
26ad17
         "Display nodes as shell commands of the form 'export uname=uuid' "
26ad17
-            "(valid with -N/--nodes)'\n",
26ad17
+            "(valid with -N/--nodes)",
26ad17
+        pcmk__option_default
26ad17
+    },
26ad17
+    {
26ad17
+        "ipc-name", required_argument, NULL, 'i',
26ad17
+        "Name to use for ipc instead of 'crmadmin' (with -P/--pacemakerd).",
26ad17
         pcmk__option_default
26ad17
     },
26ad17
     {
26ad17
         "-spacer-", no_argument, NULL, '-',
26ad17
-        "Notes:", pcmk__option_default
26ad17
+        "\nNotes:", pcmk__option_default
26ad17
     },
26ad17
     {
26ad17
         "-spacer-", no_argument, NULL, '-',
26ad17
-        "The -K and -E commands do not work and may be removed in a future "
26ad17
+        "\nThe -K and -E commands do not work and may be removed in a future "
26ad17
             "version.",
26ad17
         pcmk__option_default
26ad17
     },
26ad17
@@ -223,6 +242,88 @@ done:
26ad17
     quit_main_loop(exit_code);
26ad17
 }
26ad17
 
26ad17
+static void
26ad17
+pacemakerd_event_cb(pcmk_ipc_api_t *pacemakerd_api,
26ad17
+                    enum pcmk_ipc_event event_type, crm_exit_t status,
26ad17
+                    void *event_data, void *user_data)
26ad17
+{
26ad17
+    pcmk_pacemakerd_api_reply_t *reply = event_data;
26ad17
+
26ad17
+    switch (event_type) {
26ad17
+        case pcmk_ipc_event_disconnect:
26ad17
+            if (exit_code == CRM_EX_DISCONNECT) { // Unexpected
26ad17
+                fprintf(stderr, "error: Lost connection to pacemakerd\n");
26ad17
+            }
26ad17
+            goto done;
26ad17
+            break;
26ad17
+
26ad17
+        case pcmk_ipc_event_reply:
26ad17
+            break;
26ad17
+
26ad17
+        default:
26ad17
+            return;
26ad17
+    }
26ad17
+
26ad17
+    if (message_timer_id != 0) {
26ad17
+        g_source_remove(message_timer_id);
26ad17
+        message_timer_id = 0;
26ad17
+    }
26ad17
+
26ad17
+    if (status != CRM_EX_OK) {
26ad17
+        fprintf(stderr, "error: Bad reply from pacemakerd: %s",
26ad17
+                crm_exit_str(status));
26ad17
+        exit_code = status;
26ad17
+        goto done;
26ad17
+    }
26ad17
+
26ad17
+    if (reply->reply_type != pcmk_pacemakerd_reply_ping) {
26ad17
+        fprintf(stderr, "error: Unknown reply type %d from pacemakerd\n",
26ad17
+                reply->reply_type);
26ad17
+        goto done;
26ad17
+    }
26ad17
+
26ad17
+    // Parse desired information from reply
26ad17
+    switch (command) {
26ad17
+        case cmd_pacemakerd_health:
26ad17
+            {
26ad17
+                crm_time_t *crm_when = crm_time_new(NULL);
26ad17
+                char *pinged_buf = NULL;
26ad17
+
26ad17
+                crm_time_set_timet(crm_when, &reply->data.ping.last_good);
26ad17
+                pinged_buf = crm_time_as_string(crm_when,
26ad17
+                    crm_time_log_date | crm_time_log_timeofday |
26ad17
+                        crm_time_log_with_timezone);
26ad17
+
26ad17
+                printf("Status of %s: '%s' %s %s\n",
26ad17
+                    reply->data.ping.sys_from,
26ad17
+                    (reply->data.ping.status == pcmk_rc_ok)?
26ad17
+                        pcmk_pacemakerd_api_daemon_state_enum2text(
26ad17
+                            reply->data.ping.state):"query failed",
26ad17
+                    (reply->data.ping.status == pcmk_rc_ok)?"last updated":"",
26ad17
+                    (reply->data.ping.status == pcmk_rc_ok)?pinged_buf:"");
26ad17
+                if (BE_SILENT &&
26ad17
+                    (reply->data.ping.state != pcmk_pacemakerd_state_invalid)) {
26ad17
+                    fprintf(stderr, "%s\n",
26ad17
+                        (reply->data.ping.status == pcmk_rc_ok)?
26ad17
+                        pcmk_pacemakerd_api_daemon_state_enum2text(
26ad17
+                            reply->data.ping.state):
26ad17
+                        "query failed");
26ad17
+                }
26ad17
+                exit_code = CRM_EX_OK;
26ad17
+                free(pinged_buf);
26ad17
+            }
26ad17
+            break;
26ad17
+
26ad17
+        default: // Not really possible here
26ad17
+            exit_code = CRM_EX_SOFTWARE;
26ad17
+            break;
26ad17
+    }
26ad17
+
26ad17
+done:
26ad17
+    pcmk_disconnect_ipc(pacemakerd_api);
26ad17
+    quit_main_loop(exit_code);
26ad17
+}
26ad17
+
26ad17
 // \return Standard Pacemaker return code
26ad17
 static int
26ad17
 list_nodes()
26ad17
@@ -257,7 +358,9 @@ main(int argc, char **argv)
26ad17
     int flag;
26ad17
     int rc;
26ad17
     pcmk_ipc_api_t *controld_api = NULL;
26ad17
+    pcmk_ipc_api_t *pacemakerd_api = NULL;
26ad17
     bool need_controld_api = true;
26ad17
+    bool need_pacemakerd_api = false;
26ad17
 
26ad17
     crm_log_cli_init("crmadmin");
26ad17
     pcmk__set_cli_options(NULL, "<command> [options]", long_options,
26ad17
@@ -282,7 +385,9 @@ main(int argc, char **argv)
26ad17
                     message_timeout_ms = DEFAULT_MESSAGE_TIMEOUT_MS;
26ad17
                 }
26ad17
                 break;
26ad17
-
26ad17
+            case 'i':
26ad17
+                ipc_name = strdup(optarg);
26ad17
+                break;
26ad17
             case '$':
26ad17
             case '?':
26ad17
                 pcmk__cli_help(flag, CRM_EX_OK);
26ad17
@@ -304,6 +409,11 @@ main(int argc, char **argv)
26ad17
             case 'q':
26ad17
                 BE_SILENT = TRUE;
26ad17
                 break;
26ad17
+            case 'P':
26ad17
+                command = cmd_pacemakerd_health;
26ad17
+                need_pacemakerd_api = true;
26ad17
+                need_controld_api = false;
26ad17
+                break;
26ad17
             case 'S':
26ad17
                 command = cmd_health;
26ad17
                 crm_trace("Option %c => %s", flag, optarg);
26ad17
@@ -369,7 +479,26 @@ main(int argc, char **argv)
26ad17
         }
26ad17
     }
26ad17
 
26ad17
-    if (do_work(controld_api)) {
26ad17
+    // Connect to pacemakerd if needed
26ad17
+    if (need_pacemakerd_api) {
26ad17
+        rc = pcmk_new_ipc_api(&pacemakerd_api, pcmk_ipc_pacemakerd);
26ad17
+        if (pacemakerd_api == NULL) {
26ad17
+            fprintf(stderr, "error: Could not connect to pacemakerd: %s\n",
26ad17
+                    pcmk_rc_str(rc));
26ad17
+            exit_code = pcmk_rc2exitc(rc);
26ad17
+            goto done;
26ad17
+        }
26ad17
+        pcmk_register_ipc_callback(pacemakerd_api, pacemakerd_event_cb, NULL);
26ad17
+        rc = pcmk_connect_ipc(pacemakerd_api, pcmk_ipc_dispatch_main);
26ad17
+        if (rc != pcmk_rc_ok) {
26ad17
+            fprintf(stderr, "error: Could not connect to pacemakerd: %s\n",
26ad17
+                    pcmk_rc_str(rc));
26ad17
+            exit_code = pcmk_rc2exitc(rc);
26ad17
+            goto done;
26ad17
+        }
26ad17
+    }
26ad17
+
26ad17
+    if (do_work(controld_api?controld_api:pacemakerd_api)) {
26ad17
         // A reply is needed from controller, so run main loop to get it
26ad17
         exit_code = CRM_EX_DISCONNECT; // For unexpected disconnects
26ad17
         mainloop = g_main_loop_new(NULL, FALSE);
26ad17
@@ -379,12 +508,19 @@ main(int argc, char **argv)
26ad17
     }
26ad17
 
26ad17
 done:
26ad17
+
26ad17
     if (controld_api != NULL) {
26ad17
         pcmk_ipc_api_t *capi = controld_api;
26ad17
-
26ad17
         controld_api = NULL; // Ensure we can't free this twice
26ad17
         pcmk_free_ipc_api(capi);
26ad17
     }
26ad17
+
26ad17
+    if (pacemakerd_api != NULL) {
26ad17
+        pcmk_ipc_api_t *capi = pacemakerd_api;
26ad17
+        pacemakerd_api = NULL; // Ensure we can't free this twice
26ad17
+        pcmk_free_ipc_api(capi);
26ad17
+    }
26ad17
+
26ad17
     if (mainloop != NULL) {
26ad17
         g_main_loop_unref(mainloop);
26ad17
         mainloop = NULL;
26ad17
@@ -394,30 +530,35 @@ done:
26ad17
 
26ad17
 // \return True if reply from controller is needed
26ad17
 bool
26ad17
-do_work(pcmk_ipc_api_t *controld_api)
26ad17
+do_work(pcmk_ipc_api_t *api)
26ad17
 {
26ad17
     bool need_reply = false;
26ad17
     int rc = pcmk_rc_ok;
26ad17
 
26ad17
     switch (command) {
26ad17
         case cmd_shutdown:
26ad17
-            rc = pcmk_controld_api_shutdown(controld_api, dest_node);
26ad17
+            rc = pcmk_controld_api_shutdown(api, dest_node);
26ad17
             break;
26ad17
 
26ad17
         case cmd_health:    // dest_node != NULL
26ad17
         case cmd_whois_dc:  // dest_node == NULL
26ad17
-            rc = pcmk_controld_api_ping(controld_api, dest_node);
26ad17
+            rc = pcmk_controld_api_ping(api, dest_node);
26ad17
             need_reply = true;
26ad17
             break;
26ad17
 
26ad17
         case cmd_elect_dc:
26ad17
-            rc = pcmk_controld_api_start_election(controld_api);
26ad17
+            rc = pcmk_controld_api_start_election(api);
26ad17
             break;
26ad17
 
26ad17
         case cmd_list_nodes:
26ad17
             rc = list_nodes();
26ad17
             break;
26ad17
 
26ad17
+        case cmd_pacemakerd_health:
26ad17
+            rc = pcmk_pacemakerd_api_ping(api, ipc_name);
26ad17
+            need_reply = true;
26ad17
+            break;
26ad17
+
26ad17
         case cmd_none: // not actually possible here
26ad17
             break;
26ad17
     }
26ad17
-- 
26ad17
1.8.3.1
26ad17
26ad17
26ad17
From 6ce5bb0d6fd30a204468ea245209d34f2682d7c9 Mon Sep 17 00:00:00 2001
26ad17
From: Klaus Wenninger <klaus.wenninger@aon.at>
26ad17
Date: Tue, 21 Jul 2020 18:12:53 +0200
26ad17
Subject: [PATCH 5/6] Fix: pacemakerd: interworking with sbd not using
26ad17
 pacemakerd-api
26ad17
26ad17
---
26ad17
 daemons/pacemakerd/pacemakerd.c       |  8 +++++++-
26ad17
 include/crm/common/options_internal.h |  1 +
26ad17
 lib/common/watchdog.c                 | 15 +++++++++++++++
26ad17
 3 files changed, 23 insertions(+), 1 deletion(-)
26ad17
26ad17
diff --git a/daemons/pacemakerd/pacemakerd.c b/daemons/pacemakerd/pacemakerd.c
26ad17
index ccfae66..e91982a 100644
26ad17
--- a/daemons/pacemakerd/pacemakerd.c
26ad17
+++ b/daemons/pacemakerd/pacemakerd.c
26ad17
@@ -454,6 +454,7 @@ pcmk_shutdown_worker(gpointer user_data)
26ad17
     crm_notice("Shutdown complete");
26ad17
     pacemakerd_state = XML_PING_ATTR_PACEMAKERDSTATE_SHUTDOWNCOMPLETE;
26ad17
     if (!fatal_error && running_with_sbd &&
26ad17
+        pcmk__get_sbd_sync_resource_startup() &&
26ad17
         !shutdown_complete_state_reported_client_closed) {
26ad17
         return TRUE;
26ad17
     }
26ad17
@@ -1248,10 +1249,15 @@ main(int argc, char **argv)
26ad17
     mainloop_add_signal(SIGTERM, pcmk_shutdown);
26ad17
     mainloop_add_signal(SIGINT, pcmk_shutdown);
26ad17
 
26ad17
-    if (running_with_sbd) {
26ad17
+    if ((running_with_sbd) && pcmk__get_sbd_sync_resource_startup()) {
26ad17
         pacemakerd_state = XML_PING_ATTR_PACEMAKERDSTATE_WAITPING;
26ad17
         startup_trigger = mainloop_add_trigger(G_PRIORITY_HIGH, init_children_processes, NULL);
26ad17
     } else {
26ad17
+        if (running_with_sbd) {
26ad17
+            crm_warn("Enabling SBD_SYNC_RESOURCE_STARTUP would (if supported "
26ad17
+                     "by your sbd version) improve reliability of "
26ad17
+                     "interworking between SBD & pacemaker.");
26ad17
+        }
26ad17
         pacemakerd_state = XML_PING_ATTR_PACEMAKERDSTATE_STARTINGDAEMONS;
26ad17
         init_children_processes(NULL);
26ad17
     }
26ad17
diff --git a/include/crm/common/options_internal.h b/include/crm/common/options_internal.h
26ad17
index db54da4..d0429c9 100644
26ad17
--- a/include/crm/common/options_internal.h
26ad17
+++ b/include/crm/common/options_internal.h
26ad17
@@ -111,6 +111,7 @@ bool pcmk__valid_utilization(const char *value);
26ad17
 
26ad17
 // from watchdog.c
26ad17
 long pcmk__get_sbd_timeout(void);
26ad17
+bool pcmk__get_sbd_sync_resource_startup(void);
26ad17
 long pcmk__auto_watchdog_timeout(void);
26ad17
 bool pcmk__valid_sbd_timeout(const char *value);
26ad17
 
26ad17
diff --git a/lib/common/watchdog.c b/lib/common/watchdog.c
26ad17
index 9d8896b..8838be6 100644
26ad17
--- a/lib/common/watchdog.c
26ad17
+++ b/lib/common/watchdog.c
26ad17
@@ -227,6 +227,21 @@ pcmk__get_sbd_timeout(void)
26ad17
     return sbd_timeout;
26ad17
 }
26ad17
 
26ad17
+bool
26ad17
+pcmk__get_sbd_sync_resource_startup(void)
26ad17
+{
26ad17
+    static bool sync_resource_startup = false;
26ad17
+    static bool checked_sync_resource_startup = false;
26ad17
+
26ad17
+    if (!checked_sync_resource_startup) {
26ad17
+        sync_resource_startup =
26ad17
+            crm_is_true(getenv("SBD_SYNC_RESOURCE_STARTUP"));
26ad17
+        checked_sync_resource_startup = true;
26ad17
+    }
26ad17
+
26ad17
+    return sync_resource_startup;
26ad17
+}
26ad17
+
26ad17
 long
26ad17
 pcmk__auto_watchdog_timeout()
26ad17
 {
26ad17
-- 
26ad17
1.8.3.1
26ad17
26ad17
26ad17
From 567cb6ec6f317af9e973321633950ef26f43c486 Mon Sep 17 00:00:00 2001
26ad17
From: Klaus Wenninger <klaus.wenninger@aon.at>
26ad17
Date: Thu, 23 Jul 2020 23:00:23 +0200
26ad17
Subject: [PATCH 6/6] Fix: pacemakerd: improve logging when synced with SBD
26ad17
26ad17
---
26ad17
 daemons/pacemakerd/pacemakerd.c | 8 +++++++-
26ad17
 1 file changed, 7 insertions(+), 1 deletion(-)
26ad17
26ad17
diff --git a/daemons/pacemakerd/pacemakerd.c b/daemons/pacemakerd/pacemakerd.c
26ad17
index e91982a..c888b73 100644
26ad17
--- a/daemons/pacemakerd/pacemakerd.c
26ad17
+++ b/daemons/pacemakerd/pacemakerd.c
26ad17
@@ -456,6 +456,7 @@ pcmk_shutdown_worker(gpointer user_data)
26ad17
     if (!fatal_error && running_with_sbd &&
26ad17
         pcmk__get_sbd_sync_resource_startup() &&
26ad17
         !shutdown_complete_state_reported_client_closed) {
26ad17
+        crm_notice("Waiting for SBD to pick up shutdown-complete-state.");
26ad17
         return TRUE;
26ad17
     }
26ad17
 
26ad17
@@ -546,10 +547,14 @@ pcmk_handle_ping_request(pcmk__client_t *c, xmlNode *msg, uint32_t id)
26ad17
         if (crm_str_eq(pacemakerd_state,
26ad17
                        XML_PING_ATTR_PACEMAKERDSTATE_SHUTDOWNCOMPLETE,
26ad17
                        TRUE)) {
26ad17
+            if (pcmk__get_sbd_sync_resource_startup()) {
26ad17
+                crm_notice("Shutdown-complete-state passed to SBD.");
26ad17
+            }
26ad17
             shutdown_complete_state_reported_to = c->pid;
26ad17
         } else if (crm_str_eq(pacemakerd_state,
26ad17
                               XML_PING_ATTR_PACEMAKERDSTATE_WAITPING,
26ad17
                               TRUE)) {
26ad17
+            crm_notice("Received startup-trigger from SBD.");
26ad17
             pacemakerd_state = XML_PING_ATTR_PACEMAKERDSTATE_STARTINGDAEMONS;
26ad17
             mainloop_set_trigger(startup_trigger);
26ad17
         }
26ad17
@@ -1250,12 +1255,13 @@ main(int argc, char **argv)
26ad17
     mainloop_add_signal(SIGINT, pcmk_shutdown);
26ad17
 
26ad17
     if ((running_with_sbd) && pcmk__get_sbd_sync_resource_startup()) {
26ad17
+        crm_notice("Waiting for startup-trigger from SBD.");
26ad17
         pacemakerd_state = XML_PING_ATTR_PACEMAKERDSTATE_WAITPING;
26ad17
         startup_trigger = mainloop_add_trigger(G_PRIORITY_HIGH, init_children_processes, NULL);
26ad17
     } else {
26ad17
         if (running_with_sbd) {
26ad17
             crm_warn("Enabling SBD_SYNC_RESOURCE_STARTUP would (if supported "
26ad17
-                     "by your sbd version) improve reliability of "
26ad17
+                     "by your SBD version) improve reliability of "
26ad17
                      "interworking between SBD & pacemaker.");
26ad17
         }
26ad17
         pacemakerd_state = XML_PING_ATTR_PACEMAKERDSTATE_STARTINGDAEMONS;
26ad17
-- 
26ad17
1.8.3.1
26ad17