This source file includes following definitions.
- quit_main_loop
- admin_message_timeout
- start_main_loop
- event_done
- controld_event_reply
- controller_status_event_cb
- designated_controller_event_cb
- pacemakerd_event_cb
- ipc_connect
- pcmk__controller_status
- pcmk_controller_status
- pcmk__designated_controller
- pcmk_designated_controller
- pcmk__pacemakerd_status
- pcmk_pacemakerd_status
- remote_node_print_helper
- pcmk__list_nodes
- pcmk_list_nodes
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <glib.h>
13 #include <libxml/tree.h>
14
15 #include <pacemaker.h>
16 #include <pacemaker-internal.h>
17
18 #include <crm/crm.h>
19 #include <crm/cib.h>
20 #include <crm/cib/internal.h>
21 #include <crm/msg_xml.h>
22 #include <crm/common/output_internal.h>
23 #include <crm/common/xml.h>
24 #include <crm/common/xml_internal.h>
25 #include <crm/common/iso8601.h>
26 #include <crm/common/ipc_controld.h>
27 #include <crm/common/ipc_pacemakerd.h>
28 #include <crm/common/mainloop.h>
29
30 #define DEFAULT_MESSAGE_TIMEOUT_MS 30000
31
32
33 typedef struct {
34 pcmk__output_t *out;
35 GMainLoop *mainloop;
36 int rc;
37 guint message_timer_id;
38 guint message_timeout_ms;
39 enum pcmk_pacemakerd_state pcmkd_state;
40 } data_t;
41
42 static void
43 quit_main_loop(data_t *data)
44 {
45 if (data->mainloop != NULL) {
46 GMainLoop *mloop = data->mainloop;
47
48 data->mainloop = NULL;
49 pcmk_quit_main_loop(mloop, 10);
50 g_main_loop_unref(mloop);
51 }
52 }
53
54 static gboolean
55 admin_message_timeout(gpointer user_data)
56 {
57 data_t *data = user_data;
58 pcmk__output_t *out = data->out;
59
60 out->err(out, "error: No reply received from controller before timeout (%dms)",
61 data->message_timeout_ms);
62 data->message_timer_id = 0;
63 data->rc = ETIMEDOUT;
64 quit_main_loop(data);
65 return FALSE;
66 }
67
68 static void
69 start_main_loop(data_t *data)
70 {
71 if (data->message_timeout_ms < 1) {
72 data->message_timeout_ms = DEFAULT_MESSAGE_TIMEOUT_MS;
73 }
74
75 data->rc = ECONNRESET;
76 data->mainloop = g_main_loop_new(NULL, FALSE);
77 data->message_timer_id = g_timeout_add(data->message_timeout_ms,
78 admin_message_timeout,
79 data);
80 g_main_loop_run(data->mainloop);
81 }
82
83 static void
84 event_done(data_t *data, pcmk_ipc_api_t *api)
85 {
86 pcmk_disconnect_ipc(api);
87 quit_main_loop(data);
88 }
89
90 static pcmk_controld_api_reply_t *
91 controld_event_reply(data_t *data, pcmk_ipc_api_t *controld_api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data)
92 {
93 pcmk__output_t *out = data->out;
94 pcmk_controld_api_reply_t *reply = event_data;
95
96 switch (event_type) {
97 case pcmk_ipc_event_disconnect:
98 if (data->rc == ECONNRESET) {
99 out->err(out, "error: Lost connection to controller");
100 }
101 event_done(data, controld_api);
102 return NULL;
103
104 case pcmk_ipc_event_reply:
105 break;
106
107 default:
108 return NULL;
109 }
110
111 if (data->message_timer_id != 0) {
112 g_source_remove(data->message_timer_id);
113 data->message_timer_id = 0;
114 }
115
116 if (status != CRM_EX_OK) {
117 out->err(out, "error: Bad reply from controller: %s",
118 crm_exit_str(status));
119 data->rc = EBADMSG;
120 event_done(data, controld_api);
121 return NULL;
122 }
123
124 if (reply->reply_type != pcmk_controld_reply_ping) {
125 out->err(out, "error: Unknown reply type %d from controller",
126 reply->reply_type);
127 data->rc = EBADMSG;
128 event_done(data, controld_api);
129 return NULL;
130 }
131
132 return reply;
133 }
134
135 static void
136 controller_status_event_cb(pcmk_ipc_api_t *controld_api,
137 enum pcmk_ipc_event event_type, crm_exit_t status,
138 void *event_data, void *user_data)
139 {
140 data_t *data = user_data;
141 pcmk__output_t *out = data->out;
142 pcmk_controld_api_reply_t *reply = controld_event_reply(data, controld_api,
143 event_type, status, event_data);
144
145 if (reply != NULL) {
146 out->message(out, "health",
147 reply->data.ping.sys_from,
148 reply->host_from,
149 reply->data.ping.fsa_state,
150 reply->data.ping.result);
151 data->rc = pcmk_rc_ok;
152 }
153
154 event_done(data, controld_api);
155 }
156
157 static void
158 designated_controller_event_cb(pcmk_ipc_api_t *controld_api,
159 enum pcmk_ipc_event event_type, crm_exit_t status,
160 void *event_data, void *user_data)
161 {
162 data_t *data = user_data;
163 pcmk__output_t *out = data->out;
164 pcmk_controld_api_reply_t *reply = controld_event_reply(data, controld_api,
165 event_type, status, event_data);
166
167 if (reply != NULL) {
168 out->message(out, "dc", reply->host_from);
169 data->rc = pcmk_rc_ok;
170 }
171
172 event_done(data, controld_api);
173 }
174
175 static void
176 pacemakerd_event_cb(pcmk_ipc_api_t *pacemakerd_api,
177 enum pcmk_ipc_event event_type, crm_exit_t status,
178 void *event_data, void *user_data)
179 {
180 data_t *data = user_data;
181 pcmk__output_t *out = data->out;
182 pcmk_pacemakerd_api_reply_t *reply = event_data;
183
184 switch (event_type) {
185 case pcmk_ipc_event_disconnect:
186 if (data->rc == ECONNRESET) {
187 out->err(out, "error: Lost connection to pacemakerd");
188 }
189 event_done(data, pacemakerd_api);
190 return;
191
192 case pcmk_ipc_event_reply:
193 break;
194
195 default:
196 return;
197 }
198
199 if (data->message_timer_id != 0) {
200 g_source_remove(data->message_timer_id);
201 data->message_timer_id = 0;
202 }
203
204 if (status != CRM_EX_OK) {
205 out->err(out, "error: Bad reply from pacemakerd: %s",
206 crm_exit_str(status));
207 event_done(data, pacemakerd_api);
208 data->rc = EBADMSG;
209 return;
210 }
211
212 if (reply->reply_type != pcmk_pacemakerd_reply_ping) {
213 out->err(out, "error: Unknown reply type %d from pacemakerd",
214 reply->reply_type);
215 event_done(data, pacemakerd_api);
216 data->rc = EBADMSG;
217 return;
218 }
219
220
221 data->pcmkd_state = reply->data.ping.state;
222 if (reply->data.ping.status == pcmk_rc_ok) {
223 crm_time_t *when = crm_time_new(NULL);
224 char *when_s = NULL;
225
226 crm_time_set_timet(when, &reply->data.ping.last_good);
227 when_s = crm_time_as_string(when,
228 crm_time_log_date
229 |crm_time_log_timeofday
230 |crm_time_log_with_timezone);
231
232 out->message(out, "pacemakerd-health",
233 reply->data.ping.sys_from, reply->data.ping.state, NULL,
234 when_s);
235
236 crm_time_free(when);
237 free(when_s);
238
239 } else {
240 out->message(out, "pacemakerd-health",
241 reply->data.ping.sys_from, reply->data.ping.state,
242 "query failed", NULL);
243 }
244 data->rc = pcmk_rc_ok;
245 event_done(data, pacemakerd_api);
246 }
247
248 static pcmk_ipc_api_t *
249 ipc_connect(data_t *data, enum pcmk_ipc_server server, pcmk_ipc_callback_t cb,
250 enum pcmk_ipc_dispatch dispatch_type, bool eremoteio_ok)
251 {
252 int rc;
253 pcmk__output_t *out = data->out;
254 pcmk_ipc_api_t *api = NULL;
255
256 rc = pcmk_new_ipc_api(&api, server);
257 if (api == NULL) {
258 out->err(out, "error: Could not connect to %s: %s",
259 pcmk_ipc_name(api, true),
260 pcmk_rc_str(rc));
261 data->rc = rc;
262 return NULL;
263 }
264 if (cb != NULL) {
265 pcmk_register_ipc_callback(api, cb, data);
266 }
267
268 rc = pcmk_connect_ipc(api, dispatch_type);
269 if (rc != pcmk_rc_ok) {
270 if ((rc == EREMOTEIO) && eremoteio_ok) {
271
272
273
274
275 } else {
276 out->err(out, "error: Could not connect to %s: %s",
277 pcmk_ipc_name(api, true), pcmk_rc_str(rc));
278 }
279 data->rc = rc;
280 pcmk_free_ipc_api(api);
281 return NULL;
282 }
283
284 return api;
285 }
286
287 int
288 pcmk__controller_status(pcmk__output_t *out, char *dest_node, guint message_timeout_ms)
289 {
290 data_t data = {
291 .out = out,
292 .mainloop = NULL,
293 .rc = pcmk_rc_ok,
294 .message_timer_id = 0,
295 .message_timeout_ms = message_timeout_ms,
296 .pcmkd_state = pcmk_pacemakerd_state_invalid,
297 };
298 enum pcmk_ipc_dispatch dispatch_type = pcmk_ipc_dispatch_main;
299 pcmk_ipc_api_t *controld_api = NULL;
300
301 if (message_timeout_ms == 0) {
302 dispatch_type = pcmk_ipc_dispatch_sync;
303 }
304 controld_api = ipc_connect(&data, pcmk_ipc_controld,
305 controller_status_event_cb, dispatch_type,
306 false);
307
308 if (controld_api != NULL) {
309 int rc = pcmk_controld_api_ping(controld_api, dest_node);
310 if (rc != pcmk_rc_ok) {
311 out->err(out, "error: Could not ping controller API: %s",
312 pcmk_rc_str(rc));
313 data.rc = rc;
314 }
315
316 if (dispatch_type == pcmk_ipc_dispatch_main) {
317 start_main_loop(&data);
318 }
319
320 pcmk_free_ipc_api(controld_api);
321 }
322
323 return data.rc;
324 }
325
326 int
327 pcmk_controller_status(xmlNodePtr *xml, char *dest_node, unsigned int message_timeout_ms)
328 {
329 pcmk__output_t *out = NULL;
330 int rc = pcmk_rc_ok;
331
332 rc = pcmk__xml_output_new(&out, xml);
333 if (rc != pcmk_rc_ok) {
334 return rc;
335 }
336
337 pcmk__register_lib_messages(out);
338
339 rc = pcmk__controller_status(out, dest_node, (guint) message_timeout_ms);
340 pcmk__xml_output_finish(out, xml);
341 return rc;
342 }
343
344 int
345 pcmk__designated_controller(pcmk__output_t *out, guint message_timeout_ms)
346 {
347 data_t data = {
348 .out = out,
349 .mainloop = NULL,
350 .rc = pcmk_rc_ok,
351 .message_timer_id = 0,
352 .message_timeout_ms = message_timeout_ms,
353 .pcmkd_state = pcmk_pacemakerd_state_invalid,
354 };
355 enum pcmk_ipc_dispatch dispatch_type = pcmk_ipc_dispatch_main;
356 pcmk_ipc_api_t *controld_api = NULL;
357
358 if (message_timeout_ms == 0) {
359 dispatch_type = pcmk_ipc_dispatch_sync;
360 }
361 controld_api = ipc_connect(&data, pcmk_ipc_controld,
362 designated_controller_event_cb, dispatch_type,
363 false);
364
365 if (controld_api != NULL) {
366 int rc = pcmk_controld_api_ping(controld_api, NULL);
367 if (rc != pcmk_rc_ok) {
368 out->err(out, "error: Could not ping controller API: %s",
369 pcmk_rc_str(rc));
370 data.rc = rc;
371 }
372
373 if (dispatch_type == pcmk_ipc_dispatch_main) {
374 start_main_loop(&data);
375 }
376
377 pcmk_free_ipc_api(controld_api);
378 }
379
380 return data.rc;
381 }
382
383 int
384 pcmk_designated_controller(xmlNodePtr *xml, unsigned int message_timeout_ms)
385 {
386 pcmk__output_t *out = NULL;
387 int rc = pcmk_rc_ok;
388
389 rc = pcmk__xml_output_new(&out, xml);
390 if (rc != pcmk_rc_ok) {
391 return rc;
392 }
393
394 pcmk__register_lib_messages(out);
395
396 rc = pcmk__designated_controller(out, (guint) message_timeout_ms);
397 pcmk__xml_output_finish(out, xml);
398 return rc;
399 }
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424 int
425 pcmk__pacemakerd_status(pcmk__output_t *out, const char *ipc_name,
426 guint message_timeout_ms,
427 enum pcmk_pacemakerd_state *state)
428 {
429 data_t data = {
430 .out = out,
431 .mainloop = NULL,
432 .rc = pcmk_rc_ipc_unresponsive,
433 .message_timer_id = 0,
434 .message_timeout_ms = message_timeout_ms,
435 .pcmkd_state = pcmk_pacemakerd_state_invalid,
436 };
437 enum pcmk_ipc_dispatch dispatch_type = pcmk_ipc_dispatch_main;
438 pcmk_ipc_api_t *pacemakerd_api = NULL;
439
440 if (message_timeout_ms == 0) {
441 dispatch_type = pcmk_ipc_dispatch_sync;
442 }
443 pacemakerd_api = ipc_connect(&data, pcmk_ipc_pacemakerd,
444 pacemakerd_event_cb, dispatch_type, true);
445
446 if (pacemakerd_api != NULL) {
447 int rc = pcmk_pacemakerd_api_ping(pacemakerd_api, ipc_name);
448 if (rc != pcmk_rc_ok) {
449 out->err(out, "error: Could not ping launcher API: %s",
450 pcmk_rc_str(rc));
451 data.rc = rc;
452 }
453
454 if (dispatch_type == pcmk_ipc_dispatch_main) {
455 start_main_loop(&data);
456 }
457 pcmk_free_ipc_api(pacemakerd_api);
458 }
459
460 if (state != NULL) {
461 *state = data.pcmkd_state;
462 }
463 return data.rc;
464 }
465
466
467 int
468 pcmk_pacemakerd_status(xmlNodePtr *xml, const char *ipc_name,
469 unsigned int message_timeout_ms)
470 {
471 pcmk__output_t *out = NULL;
472 int rc = pcmk_rc_ok;
473
474 rc = pcmk__xml_output_new(&out, xml);
475 if (rc != pcmk_rc_ok) {
476 return rc;
477 }
478
479 pcmk__register_lib_messages(out);
480
481 rc = pcmk__pacemakerd_status(out, ipc_name, (guint) message_timeout_ms,
482 NULL);
483 pcmk__xml_output_finish(out, xml);
484 return rc;
485 }
486
487
488 struct node_data {
489 pcmk__output_t *out;
490 int found;
491 const char *field;
492 const char *type;
493 gboolean bash_export;
494 };
495
496 static void
497 remote_node_print_helper(xmlNode *result, void *user_data)
498 {
499 struct node_data *data = user_data;
500 pcmk__output_t *out = data->out;
501 const char *name = crm_element_value(result, XML_ATTR_UNAME);
502 const char *id = crm_element_value(result, data->field);
503
504
505 out->message(out, "crmadmin-node", data->type,
506 name ? name : id,
507 id,
508 data->bash_export);
509 data->found++;
510 }
511
512
513 int
514 pcmk__list_nodes(pcmk__output_t *out, char *node_types, gboolean bash_export)
515 {
516 xmlNode *xml_node = NULL;
517 int rc;
518
519 rc = cib__signon_query(NULL, &xml_node);
520
521 if (rc == pcmk_rc_ok) {
522 struct node_data data = {
523 .out = out,
524 .found = 0,
525 .bash_export = bash_export
526 };
527
528 out->begin_list(out, NULL, NULL, "nodes");
529
530 if (!pcmk__str_empty(node_types) && strstr(node_types, "all")) {
531 node_types = NULL;
532 }
533
534 if (pcmk__str_empty(node_types) || strstr(node_types, "cluster")) {
535 data.field = "id";
536 data.type = "cluster";
537 crm_foreach_xpath_result(xml_node, PCMK__XP_MEMBER_NODE_CONFIG,
538 remote_node_print_helper, &data);
539 }
540
541 if (pcmk__str_empty(node_types) || strstr(node_types, "guest")) {
542 data.field = "value";
543 data.type = "guest";
544 crm_foreach_xpath_result(xml_node, PCMK__XP_GUEST_NODE_CONFIG,
545 remote_node_print_helper, &data);
546 }
547
548 if (pcmk__str_empty(node_types) || !pcmk__strcmp(node_types, ",|^remote", pcmk__str_regex)) {
549 data.field = "id";
550 data.type = "remote";
551 crm_foreach_xpath_result(xml_node, PCMK__XP_REMOTE_NODE_CONFIG,
552 remote_node_print_helper, &data);
553 }
554
555 out->end_list(out);
556
557 if (data.found == 0) {
558 out->info(out, "No nodes configured");
559 }
560
561 free_xml(xml_node);
562 }
563
564 return rc;
565 }
566
567 int
568 pcmk_list_nodes(xmlNodePtr *xml, char *node_types)
569 {
570 pcmk__output_t *out = NULL;
571 int rc = pcmk_rc_ok;
572
573 rc = pcmk__xml_output_new(&out, xml);
574 if (rc != pcmk_rc_ok) {
575 return rc;
576 }
577
578 pcmk__register_lib_messages(out);
579
580 rc = pcmk__list_nodes(out, node_types, FALSE);
581 pcmk__xml_output_finish(out, xml);
582 return rc;
583 }