pacemaker  2.1.5-b7adf64e51
Scalable High-Availability cluster resource manager
ipc_pacemakerd.c
Go to the documentation of this file.
1 /*
2  * Copyright 2020-2022 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[] = {
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)";
93  default:
94  return "Invalid pacemakerd state";
95  }
96 }
97 
98 // \return Standard Pacemaker return code
99 static int
100 new_data(pcmk_ipc_api_t *api)
101 {
102  struct pacemakerd_api_private_s *private = NULL;
103 
104  api->api_data = calloc(1, sizeof(struct pacemakerd_api_private_s));
105 
106  if (api->api_data == NULL) {
107  return errno;
108  }
109 
110  private = api->api_data;
111  private->state = pcmk_pacemakerd_state_invalid;
112  /* other as with cib, controld, ... we are addressing pacemakerd just
113  from the local node -> pid is unique and thus sufficient as an ID
114  */
115  private->client_uuid = pcmk__getpid_s();
116 
117  return pcmk_rc_ok;
118 }
119 
120 static void
121 free_data(void *data)
122 {
123  free(((struct pacemakerd_api_private_s *) data)->client_uuid);
124  free(data);
125 }
126 
127 // \return Standard Pacemaker return code
128 static int
129 post_connect(pcmk_ipc_api_t *api)
130 {
131  struct pacemakerd_api_private_s *private = NULL;
132 
133  if (api->api_data == NULL) {
134  return EINVAL;
135  }
136  private = api->api_data;
137  private->state = pcmk_pacemakerd_state_invalid;
138 
139  return pcmk_rc_ok;
140 }
141 
142 static void
143 post_disconnect(pcmk_ipc_api_t *api)
144 {
145  struct pacemakerd_api_private_s *private = NULL;
146 
147  if (api->api_data == NULL) {
148  return;
149  }
150  private = api->api_data;
151  private->state = pcmk_pacemakerd_state_invalid;
152 
153  return;
154 }
155 
156 static bool
157 reply_expected(pcmk_ipc_api_t *api, xmlNode *request)
158 {
159  const char *command = crm_element_value(request, F_CRM_TASK);
160 
161  if (command == NULL) {
162  return false;
163  }
164 
165  // We only need to handle commands that functions in this file can send
166  return pcmk__str_any_of(command, CRM_OP_PING, CRM_OP_QUIT, NULL);
167 }
168 
169 static bool
170 dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
171 {
172  crm_exit_t status = CRM_EX_OK;
173  xmlNode *msg_data = NULL;
174  pcmk_pacemakerd_api_reply_t reply_data = {
176  };
177  const char *value = NULL;
178  long long value_ll = 0;
179 
180  if (pcmk__str_eq((const char *) reply->name, "ack", pcmk__str_none)) {
181  long long int ack_status = 0;
182  pcmk__scan_ll(crm_element_value(reply, "status"), &ack_status, CRM_EX_OK);
183  return ack_status == CRM_EX_INDETERMINATE;
184  }
185 
186  value = crm_element_value(reply, F_CRM_MSG_TYPE);
187  if (pcmk__str_empty(value)
188  || !pcmk__str_eq(value, XML_ATTR_RESPONSE, pcmk__str_none)) {
189  crm_info("Unrecognizable message from pacemakerd: "
190  "message type '%s' not '" XML_ATTR_RESPONSE "'",
191  pcmk__s(value, ""));
192  status = CRM_EX_PROTOCOL;
193  goto done;
194  }
195 
196  if (pcmk__str_empty(crm_element_value(reply, XML_ATTR_REFERENCE))) {
197  crm_info("Unrecognizable message from pacemakerd: no reference");
198  status = CRM_EX_PROTOCOL;
199  goto done;
200  }
201 
202  value = crm_element_value(reply, F_CRM_TASK);
203 
204  // Parse useful info from reply
205  msg_data = get_message_xml(reply, F_CRM_DATA);
206  crm_element_value_ll(msg_data, XML_ATTR_TSTAMP, &value_ll);
207 
208  if (pcmk__str_eq(value, CRM_OP_PING, pcmk__str_none)) {
210  reply_data.data.ping.state =
213  reply_data.data.ping.status =
214  pcmk__str_eq(crm_element_value(msg_data, XML_PING_ATTR_STATUS), "ok",
216  reply_data.data.ping.last_good = (value_ll < 0)? 0 : (time_t) value_ll;
217  reply_data.data.ping.sys_from = crm_element_value(msg_data,
219  } else if (pcmk__str_eq(value, CRM_OP_QUIT, pcmk__str_none)) {
221  reply_data.data.shutdown.status = atoi(crm_element_value(msg_data, XML_LRM_ATTR_OPSTATUS));
222  } else {
223  crm_info("Unrecognizable message from pacemakerd: "
224  "unknown command '%s'", pcmk__s(value, ""));
225  status = CRM_EX_PROTOCOL;
226  goto done;
227  }
228 
229 done:
230  pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
231  return false;
232 }
233 
236 {
237  pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
238 
239  if (cmds != NULL) {
240  cmds->new_data = new_data;
241  cmds->free_data = free_data;
242  cmds->post_connect = post_connect;
243  cmds->reply_expected = reply_expected;
244  cmds->dispatch = dispatch;
245  cmds->post_disconnect = post_disconnect;
246  }
247  return cmds;
248 }
249 
250 static int
251 do_pacemakerd_api_call(pcmk_ipc_api_t *api, const char *ipc_name, const char *task)
252 {
253  pacemakerd_api_private_t *private;
254  xmlNode *cmd;
255  int rc;
256 
257  if (api == NULL) {
258  return EINVAL;
259  }
260 
261  private = api->api_data;
262  CRM_ASSERT(private != NULL);
263 
264  cmd = create_request(task, NULL, NULL, CRM_SYSTEM_MCP,
265  pcmk__ipc_sys_name(ipc_name, "client"),
266  private->client_uuid);
267 
268  if (cmd) {
269  rc = pcmk__send_ipc_request(api, cmd);
270  if (rc != pcmk_rc_ok) {
271  crm_debug("Couldn't send request to pacemakerd: %s rc=%d",
272  pcmk_rc_str(rc), rc);
273  }
274  free_xml(cmd);
275  } else {
276  rc = ENOMSG;
277  }
278 
279  return rc;
280 }
281 
282 int
283 pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
284 {
285  return do_pacemakerd_api_call(api, ipc_name, CRM_OP_PING);
286 }
287 
288 int
289 pcmk_pacemakerd_api_shutdown(pcmk_ipc_api_t *api, const char *ipc_name)
290 {
291  return do_pacemakerd_api_call(api, ipc_name, CRM_OP_QUIT);
292 }
#define F_CRM_TASK
Definition: msg_xml.h:91
A dumping ground.
int pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
char data[0]
Definition: cpg.c:55
Could not determine status.
Definition: results.h:277
#define F_CRM_MSG_TYPE
Definition: msg_xml.h:93
#define XML_PING_ATTR_PACEMAKERDSTATE_INIT
Definition: msg_xml.h:166
#define XML_PING_ATTR_PACEMAKERDSTATE_WAITPING
Definition: msg_xml.h:168
#define CRM_OP_QUIT
Definition: crm.h:140
#define XML_PING_ATTR_PACEMAKERDSTATE_STARTINGDAEMONS
Definition: msg_xml.h:167
enum crm_exit_e crm_exit_t
struct pcmk_pacemakerd_api_reply_t::@5::@6 ping
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:476
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:585
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:146
#define CRM_SYSTEM_MCP
Definition: crm.h:110
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:260
#define XML_PING_ATTR_PACEMAKERDSTATE_SHUTDOWNCOMPLETE
Definition: msg_xml.h:171
#define crm_debug(fmt, args...)
Definition: logging.h:364
#define XML_PING_ATTR_STATUS
Definition: msg_xml.h:162
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:517
#define XML_ATTR_TSTAMP
Definition: msg_xml.h:130
Wrappers for and extensions to libxml2.
#define XML_PING_ATTR_PACEMAKERDSTATE_RUNNING
Definition: msg_xml.h:169
#define XML_PING_ATTR_PACEMAKERDSTATE_SHUTTINGDOWN
Definition: msg_xml.h:170
G_GNUC_INTERNAL int pcmk__send_ipc_request(pcmk_ipc_api_t *api, xmlNode *request)
Definition: ipc_client.c:619
Success.
Definition: results.h:234
IPC commands for Pacemakerd.
void free_xml(xmlNode *child)
Definition: xml.c:885
int(* post_connect)(pcmk_ipc_api_t *api)
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:952
xmlNode * get_message_xml(const xmlNode *msg, const char *field)
Definition: messages.c:154
#define XML_PING_ATTR_SYSFROM
Definition: msg_xml.h:163
#define F_CRM_DATA
Definition: msg_xml.h:90
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)
#define CRM_ASSERT(expr)
Definition: results.h:42
#define XML_ATTR_REFERENCE
Definition: msg_xml.h:159
void(* free_data)(void *api_data)
#define XML_ATTR_RESPONSE
Definition: msg_xml.h:155
#define XML_LRM_ATTR_OPSTATUS
Definition: msg_xml.h:310
struct pcmk_pacemakerd_api_reply_t::@5::@7 shutdown
bool(* reply_expected)(pcmk_ipc_api_t *api, xmlNode *request)
IPC interface to Pacemaker daemons.
const char * pcmk__pcmkd_state_enum2friendly(enum pcmk_pacemakerd_state state)
#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:165
#define crm_info(fmt, args...)
Definition: logging.h:362
pcmk__ipc_methods_t * pcmk__pacemakerd_api_methods(void)