pacemaker  2.1.7-0f7f88312f
Scalable High-Availability cluster resource manager
ipc_pacemakerd.c
Go to the documentation of this file.
1 /*
2  * Copyright 2020-2023 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/msg_xml.h>
17 #include <crm/common/xml.h>
18 #include <crm/common/ipc.h>
21 #include "crmcommon_private.h"
22 
23 typedef struct pacemakerd_api_private_s {
24  enum pcmk_pacemakerd_state state;
25  char *client_uuid;
27 
28 static const char *pacemakerd_state_str[] = {
36 };
37 
40 {
41  int i;
42 
43  if (state == NULL) {
45  }
47  i++) {
48  if (pcmk__str_eq(state, pacemakerd_state_str[i], pcmk__str_none)) {
49  return i;
50  }
51  }
53 }
54 
55 const char *
57  enum pcmk_pacemakerd_state state)
58 {
59  if ((state >= pcmk_pacemakerd_state_init) &&
60  (state <= pcmk_pacemakerd_state_max)) {
61  return pacemakerd_state_str[state];
62  }
63  return "invalid";
64 }
65 
75 const char *
77 {
78  switch (state) {
80  return "Initializing pacemaker";
82  return "Pacemaker daemons are starting";
84  return "Waiting for startup trigger from SBD";
86  return "Pacemaker is running";
88  return "Pacemaker daemons are shutting down";
90  /* Assuming pacemakerd won't process messages while in
91  * shutdown_complete state unless reporting to SBD
92  */
93  return "Pacemaker daemons are shut down (reporting to SBD)";
95  return "pacemaker-remoted is running (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, F_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 *msg_data = NULL;
198  pcmk_pacemakerd_api_reply_t reply_data = {
200  };
201  const char *value = NULL;
202  long long value_ll = 0;
203 
204  if (pcmk__str_eq((const char *) reply->name, "ack", pcmk__str_none)) {
205  long long int ack_status = 0;
206  pcmk__scan_ll(crm_element_value(reply, "status"), &ack_status, CRM_EX_OK);
207  return ack_status == CRM_EX_INDETERMINATE;
208  }
209 
210  value = crm_element_value(reply, F_CRM_MSG_TYPE);
211  if (pcmk__str_empty(value)
212  || !pcmk__str_eq(value, XML_ATTR_RESPONSE, pcmk__str_none)) {
213  crm_info("Unrecognizable message from pacemakerd: "
214  "message type '%s' not '" XML_ATTR_RESPONSE "'",
215  pcmk__s(value, ""));
216  status = CRM_EX_PROTOCOL;
217  goto done;
218  }
219 
220  if (pcmk__str_empty(crm_element_value(reply, XML_ATTR_REFERENCE))) {
221  crm_info("Unrecognizable message from pacemakerd: no reference");
222  status = CRM_EX_PROTOCOL;
223  goto done;
224  }
225 
226  value = crm_element_value(reply, F_CRM_TASK);
227 
228  // Parse useful info from reply
229  msg_data = get_message_xml(reply, F_CRM_DATA);
230  crm_element_value_ll(msg_data, XML_ATTR_TSTAMP, &value_ll);
231 
232  if (pcmk__str_eq(value, CRM_OP_PING, pcmk__str_none)) {
234  reply_data.data.ping.state =
237  reply_data.data.ping.status =
238  pcmk__str_eq(crm_element_value(msg_data, XML_PING_ATTR_STATUS), "ok",
240  reply_data.data.ping.last_good = (value_ll < 0)? 0 : (time_t) value_ll;
241  reply_data.data.ping.sys_from = crm_element_value(msg_data,
243  } else if (pcmk__str_eq(value, CRM_OP_QUIT, pcmk__str_none)) {
245  reply_data.data.shutdown.status = atoi(crm_element_value(msg_data, XML_LRM_ATTR_OPSTATUS));
246  } else {
247  crm_info("Unrecognizable message from pacemakerd: "
248  "unknown command '%s'", pcmk__s(value, ""));
249  status = CRM_EX_PROTOCOL;
250  goto done;
251  }
252 
253 done:
254  pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
255  return false;
256 }
257 
260 {
261  pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
262 
263  if (cmds != NULL) {
264  cmds->new_data = new_data;
265  cmds->free_data = free_data;
266  cmds->post_connect = post_connect;
267  cmds->reply_expected = reply_expected;
268  cmds->dispatch = dispatch;
269  cmds->post_disconnect = post_disconnect;
270  }
271  return cmds;
272 }
273 
274 static int
275 do_pacemakerd_api_call(pcmk_ipc_api_t *api, const char *ipc_name, const char *task)
276 {
277  pacemakerd_api_private_t *private;
278  xmlNode *cmd;
279  int rc;
280 
281  if (api == NULL) {
282  return EINVAL;
283  }
284 
285  private = api->api_data;
286  CRM_ASSERT(private != NULL);
287 
288  cmd = create_request(task, NULL, NULL, CRM_SYSTEM_MCP,
289  pcmk__ipc_sys_name(ipc_name, "client"),
290  private->client_uuid);
291 
292  if (cmd) {
293  rc = pcmk__send_ipc_request(api, cmd);
294  if (rc != pcmk_rc_ok) {
295  crm_debug("Couldn't send request to pacemakerd: %s rc=%d",
296  pcmk_rc_str(rc), rc);
297  }
298  free_xml(cmd);
299  } else {
300  rc = ENOMSG;
301  }
302 
303  return rc;
304 }
305 
306 int
307 pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
308 {
309  return do_pacemakerd_api_call(api, ipc_name, CRM_OP_PING);
310 }
311 
312 int
313 pcmk_pacemakerd_api_shutdown(pcmk_ipc_api_t *api, const char *ipc_name)
314 {
315  return do_pacemakerd_api_call(api, ipc_name, CRM_OP_QUIT);
316 }
#define F_CRM_TASK
Definition: msg_xml.h:113
A dumping ground.
int pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
char data[0]
Definition: cpg.c:55
#define XML_PING_ATTR_PACEMAKERDSTATE_REMOTE
Definition: msg_xml.h:192
Could not determine status.
Definition: results.h:283
#define F_CRM_MSG_TYPE
Definition: msg_xml.h:115
#define XML_PING_ATTR_PACEMAKERDSTATE_INIT
Definition: msg_xml.h:186
#define XML_PING_ATTR_PACEMAKERDSTATE_WAITPING
Definition: msg_xml.h:188
#define CRM_OP_QUIT
Definition: crm.h:140
#define XML_PING_ATTR_PACEMAKERDSTATE_STARTINGDAEMONS
Definition: msg_xml.h:187
enum crm_exit_e crm_exit_t
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:501
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: nvpair.c:515
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:109
struct pacemakerd_api_private_s pacemakerd_api_private_t
union pcmk_pacemakerd_api_reply_t::@5 data
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
Definition: strings.c:97
enum pcmk_pacemakerd_api_reply reply_type
Protocol violated.
Definition: results.h:266
#define XML_PING_ATTR_PACEMAKERDSTATE_SHUTDOWNCOMPLETE
Definition: msg_xml.h:191
#define crm_debug(fmt, args...)
Definition: logging.h:386
#define XML_PING_ATTR_STATUS
Definition: msg_xml.h:182
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:447
#define XML_ATTR_TSTAMP
Definition: msg_xml.h:152
G_GNUC_INTERNAL int pcmk__send_ipc_request(pcmk_ipc_api_t *api, const xmlNode *request)
Definition: ipc_client.c:668
Wrappers for and extensions to libxml2.
#define XML_PING_ATTR_PACEMAKERDSTATE_RUNNING
Definition: msg_xml.h:189
#define XML_PING_ATTR_PACEMAKERDSTATE_SHUTTINGDOWN
Definition: msg_xml.h:190
Success.
Definition: results.h:240
IPC commands for Pacemakerd.
void free_xml(xmlNode *child)
Definition: xml.c:783
int(* post_connect)(pcmk_ipc_api_t *api)
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:957
xmlNode * get_message_xml(const xmlNode *msg, const char *field)
Definition: messages.c:154
#define XML_PING_ATTR_SYSFROM
Definition: msg_xml.h:183
#define F_CRM_DATA
Definition: msg_xml.h:112
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)
bool(* dispatch)(pcmk_ipc_api_t *api, xmlNode *msg)
bool(* reply_expected)(pcmk_ipc_api_t *api, const xmlNode *request)
#define CRM_ASSERT(expr)
Definition: results.h:42
#define XML_ATTR_REFERENCE
Definition: msg_xml.h:179
void(* free_data)(void *api_data)
#define XML_ATTR_RESPONSE
Definition: msg_xml.h:176
#define XML_LRM_ATTR_OPSTATUS
Definition: msg_xml.h:316
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 CRM_OP_PING
Definition: crm.h:133
void(* post_disconnect)(pcmk_ipc_api_t *api)
Daemon&#39;s reply to client IPC request.
Definition: ipc.h:83
#define create_request(task, xml_data, host_to, sys_to, sys_from, uuid_from)
Definition: ipc.h:43
#define XML_PING_ATTR_PACEMAKERDSTATE
Definition: msg_xml.h:185
#define crm_info(fmt, args...)
Definition: logging.h:384
pcmk__ipc_methods_t * pcmk__pacemakerd_api_methods(void)