pacemaker 3.0.1-16e74fc4da
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
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
22typedef struct pacemakerd_api_private_s {
23 enum pcmk_pacemakerd_state state;
24 char *client_uuid;
26
27static 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
54const 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
74const 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
109const 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
123static int
124new_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
144static void
145free_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
152static int
153post_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
166static void
167post_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
180static bool
181reply_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
193static bool
194dispatch(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);
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
276done:
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
297static int
298do_pacemakerd_api_call(pcmk_ipc_api_t *api, const char *ipc_name, const char *task)
299{
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
332int
333pcmk_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
338int
340{
341 return do_pacemakerd_api_call(api, ipc_name, CRM_OP_QUIT);
342}
char data[0]
Definition cpg.c:10
A dumping ground.
#define CRM_SYSTEM_MCP
Definition crm.h:88
#define CRM_OP_QUIT
Definition crm.h:119
#define CRM_OP_PING
Definition crm.h:112
G_GNUC_INTERNAL int pcmk__send_ipc_request(pcmk_ipc_api_t *api, const xmlNode *request)
Definition ipc_client.c:684
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:144
IPC interface to Pacemaker daemons.
@ pcmk_ipc_event_reply
Daemon's reply to client IPC request.
Definition ipc.h:68
@ pcmk_ipc_pacemakerd
Launcher.
Definition ipc.h:55
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:241
const char * pcmk__pcmkd_state_enum2friendly(enum pcmk_pacemakerd_state state)
const char * pcmk_pacemakerd_api_daemon_state_enum2text(enum pcmk_pacemakerd_state state)
const char * pcmk__pcmkd_api_reply2str(enum pcmk_pacemakerd_api_reply reply)
pcmk__ipc_methods_t * pcmk__pacemakerd_api_methods(void)
int pcmk_pacemakerd_api_shutdown(pcmk_ipc_api_t *api, const char *ipc_name)
struct pacemakerd_api_private_s pacemakerd_api_private_t
enum pcmk_pacemakerd_state pcmk_pacemakerd_api_daemon_state_text2enum(const char *state)
int pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
IPC commands for Pacemakerd.
pcmk_pacemakerd_api_reply
Possible types of pacemakerd replies.
@ pcmk_pacemakerd_reply_unknown
@ pcmk_pacemakerd_reply_shutdown
@ pcmk_pacemakerd_reply_ping
pcmk_pacemakerd_state
@ pcmk_pacemakerd_state_wait_for_ping
@ pcmk_pacemakerd_state_starting_daemons
@ pcmk_pacemakerd_state_invalid
@ pcmk_pacemakerd_state_running
@ pcmk_pacemakerd_state_shutting_down
@ pcmk_pacemakerd_state_max
@ pcmk_pacemakerd_state_remote
@ pcmk_pacemakerd_state_init
@ pcmk_pacemakerd_state_shutdown_complete
#define crm_info(fmt, args...)
Definition logging.h:365
#define crm_warn(fmt, args...)
Definition logging.h:360
#define crm_debug(fmt, args...)
Definition logging.h:368
#define crm_trace(fmt, args...)
Definition logging.h:370
#define pcmk__new_request(server, sender_system, recipient_node, recipient_system, task, data)
#define PCMK_VALUE_REMOTE
Definition options.h:202
#define PCMK__VALUE_RESPONSE
#define PCMK__VALUE_INIT
#define PCMK__VALUE_SHUTTING_DOWN
#define PCMK__VALUE_RUNNING
#define PCMK__VALUE_SHUTDOWN_COMPLETE
#define PCMK__VALUE_STARTING_DAEMONS
#define PCMK__VALUE_WAIT_FOR_PING
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition results.c:617
@ CRM_EX_PROTOCOL
Protocol violated.
Definition results.h:259
@ CRM_EX_OK
Success.
Definition results.h:233
@ CRM_EX_INDETERMINATE
Could not determine status.
Definition results.h:276
@ pcmk_rc_ok
Definition results.h:159
@ pcmk_rc_error
Definition results.h:154
enum crm_exit_e crm_exit_t
Exit status codes for tools and daemons.
#define pcmk__assert(expr)
enum pcmk_ipc_server pcmk__parse_server(const char *text)
Definition servers.c:178
#define PCMK__SERVER_REMOTED
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
Definition strings.c:92
@ pcmk__str_none
@ pcmk__str_casei
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1053
int(* new_data)(pcmk_ipc_api_t *api)
bool(* reply_expected)(pcmk_ipc_api_t *api, const xmlNode *request)
void(* free_data)(void *api_data)
bool(* dispatch)(pcmk_ipc_api_t *api, xmlNode *msg)
void(* post_disconnect)(pcmk_ipc_api_t *api)
int(* post_connect)(pcmk_ipc_api_t *api)
enum pcmk_pacemakerd_api_reply reply_type
union pcmk_pacemakerd_api_reply_t::@5 data
struct pcmk_pacemakerd_api_reply_t::@5::@7 shutdown
struct pcmk_pacemakerd_api_reply_t::@5::@6 ping
enum pcmk_pacemakerd_state state
Wrappers for and extensions to libxml2.
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
int crm_element_value_ll(const xmlNode *data, const char *name, long long *dest)
Retrieve the long long integer value of an XML attribute.
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml_element.c:43
void pcmk__xml_free(xmlNode *xml)
Definition xml.c:816
#define PCMK_XA_RESULT
Definition xml_names.h:386
#define PCMK_XA_STATUS
Definition xml_names.h:410
#define PCMK_XA_CRM_TIMESTAMP
Definition xml_names.h:255
#define PCMK_XA_REFERENCE
Definition xml_names.h:372
#define PCMK__XA_PACEMAKERD_STATE
#define PCMK__XA_CRM_TASK
#define PCMK__XA_T
#define PCMK__XA_SUBT
#define PCMK__XE_ACK
#define PCMK__XA_OP_STATUS
#define PCMK__XA_CRM_SUBSYSTEM
#define PCMK__XE_CRM_XML