pacemaker  3.0.0-d8340737c4
Scalable High-Availability cluster resource manager
ipc_pacemakerd.c
Go to the documentation of this file.
1 /*
2  * Copyright 2020-2024 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 
12 #include <stdlib.h>
13 #include <time.h>
14 
15 #include <crm/crm.h>
16 #include <crm/common/xml.h>
17 #include <crm/common/ipc.h>
20 #include "crmcommon_private.h"
21 
22 typedef struct pacemakerd_api_private_s {
23  enum pcmk_pacemakerd_state state;
24  char *client_uuid;
26 
27 static const char *pacemakerd_state_str[] = {
35 };
36 
39 {
40  int i;
41 
42  if (state == NULL) {
44  }
46  i++) {
47  if (pcmk__str_eq(state, pacemakerd_state_str[i], pcmk__str_none)) {
48  return i;
49  }
50  }
52 }
53 
54 const char *
56  enum pcmk_pacemakerd_state state)
57 {
58  if ((state >= pcmk_pacemakerd_state_init) &&
59  (state <= pcmk_pacemakerd_state_max)) {
60  return pacemakerd_state_str[state];
61  }
62  return "invalid";
63 }
64 
74 const char *
76 {
77  switch (state) {
79  return "Initializing pacemaker";
81  return "Pacemaker daemons are starting";
83  return "Waiting for startup trigger from SBD";
85  return "Pacemaker is running";
87  return "Pacemaker daemons are shutting down";
89  /* Assuming pacemakerd won't process messages while in
90  * shutdown_complete state unless reporting to SBD
91  */
92  return "Pacemaker daemons are shut down (reporting to SBD)";
94  return PCMK__SERVER_REMOTED " is running "
95  "(on a Pacemaker Remote node)";
96  default:
97  return "Invalid pacemakerd state";
98  }
99 }
100 
109 const char *
111 {
112  switch (reply) {
114  return "ping";
116  return "shutdown";
117  default:
118  return "unknown";
119  }
120 }
121 
122 // \return Standard Pacemaker return code
123 static int
124 new_data(pcmk_ipc_api_t *api)
125 {
126  struct pacemakerd_api_private_s *private = NULL;
127 
128  api->api_data = calloc(1, sizeof(struct pacemakerd_api_private_s));
129 
130  if (api->api_data == NULL) {
131  return errno;
132  }
133 
134  private = api->api_data;
135  private->state = pcmk_pacemakerd_state_invalid;
136  /* other as with cib, controld, ... we are addressing pacemakerd just
137  from the local node -> pid is unique and thus sufficient as an ID
138  */
139  private->client_uuid = pcmk__getpid_s();
140 
141  return pcmk_rc_ok;
142 }
143 
144 static void
145 free_data(void *data)
146 {
147  free(((struct pacemakerd_api_private_s *) data)->client_uuid);
148  free(data);
149 }
150 
151 // \return Standard Pacemaker return code
152 static int
153 post_connect(pcmk_ipc_api_t *api)
154 {
155  struct pacemakerd_api_private_s *private = NULL;
156 
157  if (api->api_data == NULL) {
158  return EINVAL;
159  }
160  private = api->api_data;
161  private->state = pcmk_pacemakerd_state_invalid;
162 
163  return pcmk_rc_ok;
164 }
165 
166 static void
167 post_disconnect(pcmk_ipc_api_t *api)
168 {
169  struct pacemakerd_api_private_s *private = NULL;
170 
171  if (api->api_data == NULL) {
172  return;
173  }
174  private = api->api_data;
175  private->state = pcmk_pacemakerd_state_invalid;
176 
177  return;
178 }
179 
180 static bool
181 reply_expected(pcmk_ipc_api_t *api, const xmlNode *request)
182 {
183  const char *command = crm_element_value(request, PCMK__XA_CRM_TASK);
184 
185  if (command == NULL) {
186  return false;
187  }
188 
189  // We only need to handle commands that functions in this file can send
190  return pcmk__str_any_of(command, CRM_OP_PING, CRM_OP_QUIT, NULL);
191 }
192 
193 static bool
194 dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
195 {
196  crm_exit_t status = CRM_EX_OK;
197  xmlNode *wrapper = NULL;
198  xmlNode *msg_data = NULL;
199  pcmk_pacemakerd_api_reply_t reply_data = {
201  };
202  const char *value = NULL;
203  long long value_ll = 0;
204 
205  if (pcmk__xe_is(reply, PCMK__XE_ACK)) {
206  long long int ack_status = 0;
207  const char *status = crm_element_value(reply, PCMK_XA_STATUS);
208  int rc = pcmk__scan_ll(status, &ack_status, CRM_EX_OK);
209 
210  if (rc != pcmk_rc_ok) {
211  crm_warn("Ack reply from %s has invalid " PCMK_XA_STATUS
212  " '%s' (bug?)",
213  pcmk_ipc_name(api, true), pcmk__s(status, ""));
214  }
215  return ack_status == CRM_EX_INDETERMINATE;
216  }
217 
218  value = crm_element_value(reply, PCMK__XA_T);
219  if (pcmk__parse_server(value) != pcmk_ipc_pacemakerd) {
220  /* @COMPAT pacemakerd <3.0.0 sets PCMK__VALUE_CRMD as the message type,
221  * so we can't enforce this check until we no longer support
222  * Pacemaker Remote nodes connecting to cluster nodes older than that.
223  */
224  crm_trace("Message from %s has unexpected message type '%s' "
225  "(bug if not from pacemakerd <3.0.0)",
226  pcmk_ipc_name(api, true), pcmk__s(value, ""));
227  }
228 
229  value = crm_element_value(reply, PCMK__XA_SUBT);
230  if (!pcmk__str_eq(value, PCMK__VALUE_RESPONSE, pcmk__str_none)) {
231  crm_info("Unrecognizable message from %s: "
232  "message type '%s' not '" PCMK__VALUE_RESPONSE "'",
233  pcmk_ipc_name(api, true), pcmk__s(value, ""));
234  status = CRM_EX_PROTOCOL;
235  goto done;
236  }
237 
238  if (pcmk__str_empty(crm_element_value(reply, PCMK_XA_REFERENCE))) {
239  crm_info("Unrecognizable message from %s: no reference",
240  pcmk_ipc_name(api, true));
241  status = CRM_EX_PROTOCOL;
242  goto done;
243  }
244 
245  value = crm_element_value(reply, PCMK__XA_CRM_TASK);
246 
247  // Parse useful info from reply
248  wrapper = pcmk__xe_first_child(reply, PCMK__XE_CRM_XML, NULL, NULL);
249  msg_data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
250 
251  crm_element_value_ll(msg_data, PCMK_XA_CRM_TIMESTAMP, &value_ll);
252 
253  if (pcmk__str_eq(value, CRM_OP_PING, pcmk__str_none)) {
255  reply_data.data.ping.state =
258  reply_data.data.ping.status =
259  pcmk__str_eq(crm_element_value(msg_data, PCMK_XA_RESULT), "ok",
261  reply_data.data.ping.last_good = (value_ll < 0)? 0 : (time_t) value_ll;
262  reply_data.data.ping.sys_from =
264  } else if (pcmk__str_eq(value, CRM_OP_QUIT, pcmk__str_none)) {
265  const char *op_status = crm_element_value(msg_data, PCMK__XA_OP_STATUS);
266 
268  reply_data.data.shutdown.status = atoi(op_status);
269  } else {
270  crm_info("Unrecognizable message from %s: unknown command '%s'",
271  pcmk_ipc_name(api, true), pcmk__s(value, ""));
272  status = CRM_EX_PROTOCOL;
273  goto done;
274  }
275 
276 done:
277  pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
278  return false;
279 }
280 
283 {
284  pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
285 
286  if (cmds != NULL) {
287  cmds->new_data = new_data;
288  cmds->free_data = free_data;
289  cmds->post_connect = post_connect;
290  cmds->reply_expected = reply_expected;
291  cmds->dispatch = dispatch;
292  cmds->post_disconnect = post_disconnect;
293  }
294  return cmds;
295 }
296 
297 static int
298 do_pacemakerd_api_call(pcmk_ipc_api_t *api, const char *ipc_name, const char *task)
299 {
300  pacemakerd_api_private_t *private;
301  char *sender_system = NULL;
302  xmlNode *cmd;
303  int rc;
304 
305  if (api == NULL) {
306  return EINVAL;
307  }
308 
309  private = api->api_data;
310  pcmk__assert(private != NULL);
311 
312  sender_system = crm_strdup_printf("%s_%s", private->client_uuid,
313  pcmk__ipc_sys_name(ipc_name, "client"));
314  cmd = pcmk__new_request(pcmk_ipc_pacemakerd, sender_system, NULL,
315  CRM_SYSTEM_MCP, task, NULL);
316  free(sender_system);
317 
318  if (cmd) {
319  rc = pcmk__send_ipc_request(api, cmd);
320  if (rc != pcmk_rc_ok) {
321  crm_debug("Couldn't send request to %s: %s rc=%d",
322  pcmk_ipc_name(api, true), pcmk_rc_str(rc), rc);
323  }
324  pcmk__xml_free(cmd);
325  } else {
326  rc = ENOMSG;
327  }
328 
329  return rc;
330 }
331 
332 int
333 pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
334 {
335  return do_pacemakerd_api_call(api, ipc_name, CRM_OP_PING);
336 }
337 
338 int
339 pcmk_pacemakerd_api_shutdown(pcmk_ipc_api_t *api, const char *ipc_name)
340 {
341  return do_pacemakerd_api_call(api, ipc_name, CRM_OP_QUIT);
342 }
A dumping ground.
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml_element.c:42
#define PCMK__VALUE_RESPONSE
int crm_element_value_ll(const xmlNode *data, const char *name, long long *dest)
Retrieve the long long integer value of an XML attribute.
Definition: xml_element.c:1291
int pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
char data[0]
Definition: cpg.c:58
#define PCMK__SERVER_REMOTED
Launcher.
Definition: ipc.h:55
Could not determine status.
Definition: results.h:274
#define PCMK_XA_REFERENCE
Definition: xml_names.h:372
#define PCMK__XA_PACEMAKERD_STATE
#define CRM_OP_QUIT
Definition: crm.h:119
enum crm_exit_e crm_exit_t
#define PCMK__VALUE_SHUTDOWN_COMPLETE
#define PCMK__XA_SUBT
struct pcmk_pacemakerd_api_reply_t::@5::@6 ping
pcmk_pacemakerd_api_reply
Possible types of pacemakerd replies.
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:609
G_GNUC_INTERNAL void pcmk__call_ipc_callback(pcmk_ipc_api_t *api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data)
Definition: ipc_client.c:150
#define CRM_SYSTEM_MCP
Definition: crm.h:88
struct pacemakerd_api_private_s pacemakerd_api_private_t
union pcmk_pacemakerd_api_reply_t::@5 data
void pcmk__xml_free(xmlNode *xml)
Definition: xml.c:789
#define PCMK__XA_CRM_TASK
#define PCMK_XA_CRM_TIMESTAMP
Definition: xml_names.h:255
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
Definition: strings.c:92
#define crm_warn(fmt, args...)
Definition: logging.h:362
enum pcmk_pacemakerd_api_reply reply_type
Protocol violated.
Definition: results.h:257
#define crm_debug(fmt, args...)
Definition: logging.h:370
G_GNUC_INTERNAL int pcmk__send_ipc_request(pcmk_ipc_api_t *api, const xmlNode *request)
Definition: ipc_client.c:658
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: xml_element.c:1168
#define crm_trace(fmt, args...)
Definition: logging.h:372
#define PCMK__VALUE_WAIT_FOR_PING
Wrappers for and extensions to libxml2.
enum pcmk_ipc_server pcmk__parse_server(const char *text)
Definition: servers.c:178
#define PCMK__VALUE_RUNNING
#define PCMK__VALUE_STARTING_DAEMONS
#define pcmk__new_request(server, sender_system, recipient_node, recipient_system, task, data)
Success.
Definition: results.h:231
IPC commands for Pacemakerd.
#define PCMK__VALUE_INIT
int(* post_connect)(pcmk_ipc_api_t *api)
#define PCMK__XA_CRM_SUBSYSTEM
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1051
#define PCMK_XA_STATUS
Definition: xml_names.h:410
#define pcmk__assert(expr)
#define PCMK__VALUE_SHUTTING_DOWN
pcmk_pacemakerd_state
int(* new_data)(pcmk_ipc_api_t *api)
int pcmk_pacemakerd_api_shutdown(pcmk_ipc_api_t *api, const char *ipc_name)
enum pcmk_pacemakerd_state pcmk_pacemakerd_api_daemon_state_text2enum(const char *state)
const char * pcmk_pacemakerd_api_daemon_state_enum2text(enum pcmk_pacemakerd_state state)
#define PCMK__XE_CRM_XML
bool(* dispatch)(pcmk_ipc_api_t *api, xmlNode *msg)
bool(* reply_expected)(pcmk_ipc_api_t *api, const xmlNode *request)
#define PCMK__XE_ACK
#define PCMK__XA_OP_STATUS
void(* free_data)(void *api_data)
const char * pcmk_ipc_name(const pcmk_ipc_api_t *api, bool for_log)
Get the IPC name used with an IPC API connection.
Definition: ipc_client.c:247
struct pcmk_pacemakerd_api_reply_t::@5::@7 shutdown
IPC interface to Pacemaker daemons.
const char * pcmk__pcmkd_state_enum2friendly(enum pcmk_pacemakerd_state state)
const char * pcmk__pcmkd_api_reply2str(enum pcmk_pacemakerd_api_reply reply)
#define PCMK__XA_T
#define CRM_OP_PING
Definition: crm.h:112
void(* post_disconnect)(pcmk_ipc_api_t *api)
Daemon&#39;s reply to client IPC request.
Definition: ipc.h:68
#define PCMK_XA_RESULT
Definition: xml_names.h:386
#define PCMK_VALUE_REMOTE
Definition: options.h:201
#define crm_info(fmt, args...)
Definition: logging.h:367
pcmk__ipc_methods_t * pcmk__pacemakerd_api_methods(void)
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1