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/common/xml.h>
17 #include <crm/common/ipc.h>
18 #include <crm/common/ipc_internal.h>
19 #include <crm/common/ipc_pacemakerd.h>
20 #include "crmcommon_private.h"
21
22 typedef struct pacemakerd_api_private_s {
23 enum pcmk_pacemakerd_state state;
24 char *client_uuid;
25 } pacemakerd_api_private_t;
26
27 static const char *pacemakerd_state_str[] = {
28 PCMK__VALUE_INIT,
29 PCMK__VALUE_STARTING_DAEMONS,
30 PCMK__VALUE_WAIT_FOR_PING,
31 PCMK__VALUE_RUNNING,
32 PCMK__VALUE_SHUTTING_DOWN,
33 PCMK__VALUE_SHUTDOWN_COMPLETE,
34 PCMK_VALUE_REMOTE,
35 };
36
37 enum pcmk_pacemakerd_state
38 pcmk_pacemakerd_api_daemon_state_text2enum(const char *state)
39 {
40 int i;
41
42 if (state == NULL) {
43 return pcmk_pacemakerd_state_invalid;
44 }
45 for (i=pcmk_pacemakerd_state_init; i <= pcmk_pacemakerd_state_max;
46 i++) {
47 if (pcmk__str_eq(state, pacemakerd_state_str[i], pcmk__str_none)) {
48 return i;
49 }
50 }
51 return pcmk_pacemakerd_state_invalid;
52 }
53
54 const char *
55 pcmk_pacemakerd_api_daemon_state_enum2text(
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
65
66
67
68
69
70
71
72
73
74 const char *
75 pcmk__pcmkd_state_enum2friendly(enum pcmk_pacemakerd_state state)
76 {
77 switch (state) {
78 case pcmk_pacemakerd_state_init:
79 return "Initializing pacemaker";
80 case pcmk_pacemakerd_state_starting_daemons:
81 return "Pacemaker daemons are starting";
82 case pcmk_pacemakerd_state_wait_for_ping:
83 return "Waiting for startup trigger from SBD";
84 case pcmk_pacemakerd_state_running:
85 return "Pacemaker is running";
86 case pcmk_pacemakerd_state_shutting_down:
87 return "Pacemaker daemons are shutting down";
88 case pcmk_pacemakerd_state_shutdown_complete:
89
90
91
92 return "Pacemaker daemons are shut down (reporting to SBD)";
93 case pcmk_pacemakerd_state_remote:
94 return "pacemaker-remoted is running (on a Pacemaker Remote node)";
95 default:
96 return "Invalid pacemakerd state";
97 }
98 }
99
100
101
102
103
104
105
106
107
108 const char *
109 pcmk__pcmkd_api_reply2str(enum pcmk_pacemakerd_api_reply reply)
110 {
111 switch (reply) {
112 case pcmk_pacemakerd_reply_ping:
113 return "ping";
114 case pcmk_pacemakerd_reply_shutdown:
115 return "shutdown";
116 default:
117 return "unknown";
118 }
119 }
120
121
122 static int
123 new_data(pcmk_ipc_api_t *api)
124 {
125 struct pacemakerd_api_private_s *private = NULL;
126
127 api->api_data = calloc(1, sizeof(struct pacemakerd_api_private_s));
128
129 if (api->api_data == NULL) {
130 return errno;
131 }
132
133 private = api->api_data;
134 private->state = pcmk_pacemakerd_state_invalid;
135
136
137
138 private->client_uuid = pcmk__getpid_s();
139
140 return pcmk_rc_ok;
141 }
142
143 static void
144 free_data(void *data)
145 {
146 free(((struct pacemakerd_api_private_s *) data)->client_uuid);
147 free(data);
148 }
149
150
151 static int
152 post_connect(pcmk_ipc_api_t *api)
153 {
154 struct pacemakerd_api_private_s *private = NULL;
155
156 if (api->api_data == NULL) {
157 return EINVAL;
158 }
159 private = api->api_data;
160 private->state = pcmk_pacemakerd_state_invalid;
161
162 return pcmk_rc_ok;
163 }
164
165 static void
166 post_disconnect(pcmk_ipc_api_t *api)
167 {
168 struct pacemakerd_api_private_s *private = NULL;
169
170 if (api->api_data == NULL) {
171 return;
172 }
173 private = api->api_data;
174 private->state = pcmk_pacemakerd_state_invalid;
175
176 return;
177 }
178
179 static bool
180 reply_expected(pcmk_ipc_api_t *api, const xmlNode *request)
181 {
182 const char *command = crm_element_value(request, PCMK__XA_CRM_TASK);
183
184 if (command == NULL) {
185 return false;
186 }
187
188
189 return pcmk__str_any_of(command, CRM_OP_PING, CRM_OP_QUIT, NULL);
190 }
191
192 static bool
193 dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
194 {
195 crm_exit_t status = CRM_EX_OK;
196 xmlNode *wrapper = NULL;
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__xe_is(reply, PCMK__XE_ACK)) {
205 long long int ack_status = 0;
206 const char *status = crm_element_value(reply, PCMK_XA_STATUS);
207 int rc = pcmk__scan_ll(status, &ack_status, CRM_EX_OK);
208
209 if (rc != pcmk_rc_ok) {
210 crm_warn("Ack reply from %s has invalid " PCMK_XA_STATUS
211 " '%s' (bug?)",
212 pcmk_ipc_name(api, true), pcmk__s(status, ""));
213 }
214 return ack_status == CRM_EX_INDETERMINATE;
215 }
216
217 value = crm_element_value(reply, PCMK__XA_SUBT);
218 if (!pcmk__str_eq(value, PCMK__VALUE_RESPONSE, pcmk__str_none)) {
219 crm_info("Unrecognizable message from %s: "
220 "message type '%s' not '" PCMK__VALUE_RESPONSE "'",
221 pcmk_ipc_name(api, true), pcmk__s(value, ""));
222 status = CRM_EX_PROTOCOL;
223 goto done;
224 }
225
226 if (pcmk__str_empty(crm_element_value(reply, PCMK_XA_REFERENCE))) {
227 crm_info("Unrecognizable message from %s: no reference",
228 pcmk_ipc_name(api, true));
229 status = CRM_EX_PROTOCOL;
230 goto done;
231 }
232
233 value = crm_element_value(reply, PCMK__XA_CRM_TASK);
234
235
236 wrapper = pcmk__xe_first_child(reply, PCMK__XE_CRM_XML, NULL, NULL);
237 msg_data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
238
239 crm_element_value_ll(msg_data, PCMK_XA_CRM_TIMESTAMP, &value_ll);
240
241 if (pcmk__str_eq(value, CRM_OP_PING, pcmk__str_none)) {
242 reply_data.reply_type = pcmk_pacemakerd_reply_ping;
243 reply_data.data.ping.state =
244 pcmk_pacemakerd_api_daemon_state_text2enum(
245 crm_element_value(msg_data, PCMK__XA_PACEMAKERD_STATE));
246 reply_data.data.ping.status =
247 pcmk__str_eq(crm_element_value(msg_data, PCMK_XA_RESULT), "ok",
248 pcmk__str_casei)?pcmk_rc_ok:pcmk_rc_error;
249 reply_data.data.ping.last_good = (value_ll < 0)? 0 : (time_t) value_ll;
250 reply_data.data.ping.sys_from =
251 crm_element_value(msg_data, PCMK__XA_CRM_SUBSYSTEM);
252 } else if (pcmk__str_eq(value, CRM_OP_QUIT, pcmk__str_none)) {
253 const char *op_status = crm_element_value(msg_data, PCMK__XA_OP_STATUS);
254
255 reply_data.reply_type = pcmk_pacemakerd_reply_shutdown;
256 reply_data.data.shutdown.status = atoi(op_status);
257 } else {
258 crm_info("Unrecognizable message from %s: unknown command '%s'",
259 pcmk_ipc_name(api, true), pcmk__s(value, ""));
260 status = CRM_EX_PROTOCOL;
261 goto done;
262 }
263
264 done:
265 pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
266 return false;
267 }
268
269 pcmk__ipc_methods_t *
270 pcmk__pacemakerd_api_methods(void)
271 {
272 pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
273
274 if (cmds != NULL) {
275 cmds->new_data = new_data;
276 cmds->free_data = free_data;
277 cmds->post_connect = post_connect;
278 cmds->reply_expected = reply_expected;
279 cmds->dispatch = dispatch;
280 cmds->post_disconnect = post_disconnect;
281 }
282 return cmds;
283 }
284
285 static int
286 do_pacemakerd_api_call(pcmk_ipc_api_t *api, const char *ipc_name, const char *task)
287 {
288 pacemakerd_api_private_t *private;
289 xmlNode *cmd;
290 int rc;
291
292 if (api == NULL) {
293 return EINVAL;
294 }
295
296 private = api->api_data;
297 pcmk__assert(private != NULL);
298
299 cmd = create_request(task, NULL, NULL, CRM_SYSTEM_MCP,
300 pcmk__ipc_sys_name(ipc_name, "client"),
301 private->client_uuid);
302
303 if (cmd) {
304 rc = pcmk__send_ipc_request(api, cmd);
305 if (rc != pcmk_rc_ok) {
306 crm_debug("Couldn't send request to %s: %s rc=%d",
307 pcmk_ipc_name(api, true), pcmk_rc_str(rc), rc);
308 }
309 free_xml(cmd);
310 } else {
311 rc = ENOMSG;
312 }
313
314 return rc;
315 }
316
317 int
318 pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
319 {
320 return do_pacemakerd_api_call(api, ipc_name, CRM_OP_PING);
321 }
322
323 int
324 pcmk_pacemakerd_api_shutdown(pcmk_ipc_api_t *api, const char *ipc_name)
325 {
326 return do_pacemakerd_api_call(api, ipc_name, CRM_OP_QUIT);
327 }