This source file includes following definitions.
- pcmk_pacemakerd_api_daemon_state_text2enum
- pcmk_pacemakerd_api_daemon_state_enum2text
- pcmk__pcmkd_state_enum2friendly
- pcmk__pcmkd_api_reply2str
- new_data
- free_data
- post_connect
- post_disconnect
- reply_expected
- dispatch
- pcmk__pacemakerd_api_methods
- do_pacemakerd_api_call
- pcmk_pacemakerd_api_ping
- pcmk_pacemakerd_api_shutdown
1
2
3
4
5
6
7
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>
19 #include <crm/common/ipc_internal.h>
20 #include <crm/common/ipc_pacemakerd.h>
21 #include "crmcommon_private.h"
22
23 typedef struct pacemakerd_api_private_s {
24 enum pcmk_pacemakerd_state state;
25 char *client_uuid;
26 } pacemakerd_api_private_t;
27
28 static const char *pacemakerd_state_str[] = {
29 XML_PING_ATTR_PACEMAKERDSTATE_INIT,
30 XML_PING_ATTR_PACEMAKERDSTATE_STARTINGDAEMONS,
31 XML_PING_ATTR_PACEMAKERDSTATE_WAITPING,
32 XML_PING_ATTR_PACEMAKERDSTATE_RUNNING,
33 XML_PING_ATTR_PACEMAKERDSTATE_SHUTTINGDOWN,
34 XML_PING_ATTR_PACEMAKERDSTATE_SHUTDOWNCOMPLETE,
35 XML_PING_ATTR_PACEMAKERDSTATE_REMOTE,
36 };
37
38 enum pcmk_pacemakerd_state
39 pcmk_pacemakerd_api_daemon_state_text2enum(const char *state)
40 {
41 int i;
42
43 if (state == NULL) {
44 return pcmk_pacemakerd_state_invalid;
45 }
46 for (i=pcmk_pacemakerd_state_init; i <= pcmk_pacemakerd_state_max;
47 i++) {
48 if (pcmk__str_eq(state, pacemakerd_state_str[i], pcmk__str_none)) {
49 return i;
50 }
51 }
52 return pcmk_pacemakerd_state_invalid;
53 }
54
55 const char *
56 pcmk_pacemakerd_api_daemon_state_enum2text(
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
66
67
68
69
70
71
72
73
74
75 const char *
76 pcmk__pcmkd_state_enum2friendly(enum pcmk_pacemakerd_state state)
77 {
78 switch (state) {
79 case pcmk_pacemakerd_state_init:
80 return "Initializing pacemaker";
81 case pcmk_pacemakerd_state_starting_daemons:
82 return "Pacemaker daemons are starting";
83 case pcmk_pacemakerd_state_wait_for_ping:
84 return "Waiting for startup trigger from SBD";
85 case pcmk_pacemakerd_state_running:
86 return "Pacemaker is running";
87 case pcmk_pacemakerd_state_shutting_down:
88 return "Pacemaker daemons are shutting down";
89 case pcmk_pacemakerd_state_shutdown_complete:
90
91
92
93 return "Pacemaker daemons are shut down (reporting to SBD)";
94 case pcmk_pacemakerd_state_remote:
95 return "pacemaker-remoted is running (on a Pacemaker Remote node)";
96 default:
97 return "Invalid pacemakerd state";
98 }
99 }
100
101
102
103
104
105
106
107
108
109 const char *
110 pcmk__pcmkd_api_reply2str(enum pcmk_pacemakerd_api_reply reply)
111 {
112 switch (reply) {
113 case pcmk_pacemakerd_reply_ping:
114 return "ping";
115 case pcmk_pacemakerd_reply_shutdown:
116 return "shutdown";
117 default:
118 return "unknown";
119 }
120 }
121
122
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
137
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
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
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 = {
199 pcmk_pacemakerd_reply_unknown
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
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)) {
233 reply_data.reply_type = pcmk_pacemakerd_reply_ping;
234 reply_data.data.ping.state =
235 pcmk_pacemakerd_api_daemon_state_text2enum(
236 crm_element_value(msg_data, XML_PING_ATTR_PACEMAKERDSTATE));
237 reply_data.data.ping.status =
238 pcmk__str_eq(crm_element_value(msg_data, XML_PING_ATTR_STATUS), "ok",
239 pcmk__str_casei)?pcmk_rc_ok:pcmk_rc_error;
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,
242 XML_PING_ATTR_SYSFROM);
243 } else if (pcmk__str_eq(value, CRM_OP_QUIT, pcmk__str_none)) {
244 reply_data.reply_type = pcmk_pacemakerd_reply_shutdown;
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
258 pcmk__ipc_methods_t *
259 pcmk__pacemakerd_api_methods(void)
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 }