pacemaker 2.1.6-6fdc9deea29
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
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
23typedef struct pacemakerd_api_private_s {
24 enum pcmk_pacemakerd_state state;
25 char *client_uuid;
27
28static 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
55const 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
75const 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
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, 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
193static bool
194dispatch(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
253done:
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
274static int
275do_pacemakerd_api_call(pcmk_ipc_api_t *api, const char *ipc_name, const char *task)
276{
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
306int
307pcmk_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
312int
314{
315 return do_pacemakerd_api_call(api, ipc_name, CRM_OP_QUIT);
316}
char data[0]
Definition cpg.c:10
A dumping ground.
#define CRM_SYSTEM_MCP
Definition crm.h:110
#define CRM_OP_QUIT
Definition crm.h:140
#define CRM_OP_PING
Definition crm.h:133
G_GNUC_INTERNAL int pcmk__send_ipc_request(pcmk_ipc_api_t *api, xmlNode *request)
Definition ipc_client.c:639
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
IPC interface to Pacemaker daemons.
#define create_request(task, xml_data, host_to, sys_to, sys_from, uuid_from)
Definition ipc.h:43
@ pcmk_ipc_event_reply
Daemon's reply to client IPC request.
Definition ipc.h:83
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:378
#define crm_debug(fmt, args...)
Definition logging.h:380
#define XML_PING_ATTR_PACEMAKERDSTATE_REMOTE
Definition msg_xml.h:184
#define XML_PING_ATTR_PACEMAKERDSTATE_WAITPING
Definition msg_xml.h:180
#define XML_PING_ATTR_SYSFROM
Definition msg_xml.h:175
#define XML_PING_ATTR_PACEMAKERDSTATE
Definition msg_xml.h:177
#define XML_PING_ATTR_PACEMAKERDSTATE_SHUTDOWNCOMPLETE
Definition msg_xml.h:183
#define XML_LRM_ATTR_OPSTATUS
Definition msg_xml.h:325
#define XML_PING_ATTR_PACEMAKERDSTATE_SHUTTINGDOWN
Definition msg_xml.h:182
#define XML_PING_ATTR_PACEMAKERDSTATE_STARTINGDAEMONS
Definition msg_xml.h:179
#define F_CRM_MSG_TYPE
Definition msg_xml.h:106
#define XML_PING_ATTR_STATUS
Definition msg_xml.h:174
#define XML_ATTR_RESPONSE
Definition msg_xml.h:168
#define XML_ATTR_REFERENCE
Definition msg_xml.h:171
#define F_CRM_DATA
Definition msg_xml.h:103
#define F_CRM_TASK
Definition msg_xml.h:104
#define XML_ATTR_TSTAMP
Definition msg_xml.h:143
#define XML_PING_ATTR_PACEMAKERDSTATE_RUNNING
Definition msg_xml.h:181
#define XML_PING_ATTR_PACEMAKERDSTATE_INIT
Definition msg_xml.h:178
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:496
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:564
#define CRM_ASSERT(expr)
Definition results.h:42
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition results.c:488
@ CRM_EX_PROTOCOL
Protocol violated.
Definition results.h:263
@ CRM_EX_OK
Success.
Definition results.h:237
@ CRM_EX_INDETERMINATE
Could not determine status.
Definition results.h:280
@ pcmk_rc_ok
Definition results.h:151
@ pcmk_rc_error
Definition results.h:147
enum crm_exit_e crm_exit_t
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
Definition strings.c:97
@ pcmk__str_none
@ pcmk__str_casei
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:957
int(* new_data)(pcmk_ipc_api_t *api)
void(* free_data)(void *api_data)
bool(* dispatch)(pcmk_ipc_api_t *api, xmlNode *msg)
void(* post_disconnect)(pcmk_ipc_api_t *api)
bool(* reply_expected)(pcmk_ipc_api_t *api, xmlNode *request)
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.
void free_xml(xmlNode *child)
Definition xml.c:813
xmlNode * get_message_xml(const xmlNode *msg, const char *field)
Definition messages.c:154