This source file includes following definitions.
- validate_reply_event
- validate_controld_reply
- validate_pcmkd_reply
- controller_status_event_cb
- designated_controller_event_cb
- node_info_event_cb
- pacemakerd_event_cb
- ipc_connect
- poll_until_reply
- pcmk__controller_status
- pcmk_controller_status
- pcmk__designated_controller
- pcmk_designated_controller
- pcmk__query_node_info
- pcmk_query_node_info
- 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 <libxml/tree.h>
13
14 #include <pacemaker.h>
15 #include <pacemaker-internal.h>
16
17 #include <crm/crm.h>
18 #include <crm/cib.h>
19 #include <crm/cib/internal.h>
20 #include <crm/msg_xml.h>
21 #include <crm/common/output_internal.h>
22 #include <crm/common/xml.h>
23 #include <crm/common/xml_internal.h>
24 #include <crm/common/iso8601.h>
25 #include <crm/common/ipc_controld.h>
26 #include <crm/common/ipc_pacemakerd.h>
27
28
29 typedef struct {
30
31
32
33
34 uint32_t id;
35 char **node_name;
36 char **uuid;
37 char **state;
38 bool have_quorum;
39 bool is_remote;
40 } node_info_t;
41
42
43 typedef struct {
44 pcmk__output_t *out;
45 bool show_output;
46 int rc;
47 unsigned int message_timeout_ms;
48 enum pcmk_pacemakerd_state pcmkd_state;
49 node_info_t node_info;
50 } data_t;
51
52
53
54
55
56
57
58
59
60
61
62
63 static int
64 validate_reply_event(data_t *data, const pcmk_ipc_api_t *api,
65 enum pcmk_ipc_event event_type, crm_exit_t status)
66 {
67 pcmk__output_t *out = data->out;
68
69 switch (event_type) {
70 case pcmk_ipc_event_reply:
71 break;
72
73 case pcmk_ipc_event_disconnect:
74 if (data->rc == ECONNRESET) {
75 out->err(out, "error: Lost connection to %s",
76 pcmk_ipc_name(api, true));
77 }
78
79 return ENOTSUP;
80
81 default:
82
83 return ENOTSUP;
84 }
85
86 if (status != CRM_EX_OK) {
87 out->err(out, "error: Bad reply from %s: %s",
88 pcmk_ipc_name(api, true), crm_exit_str(status));
89 data->rc = EBADMSG;
90 return data->rc;
91 }
92 return pcmk_rc_ok;
93 }
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 static int
109 validate_controld_reply(data_t *data, const pcmk_ipc_api_t *api,
110 enum pcmk_ipc_event event_type, crm_exit_t status,
111 const void *event_data,
112 enum pcmk_controld_api_reply expected_type)
113 {
114 pcmk__output_t *out = data->out;
115 int rc = pcmk_rc_ok;
116 const pcmk_controld_api_reply_t *reply = NULL;
117
118 rc = validate_reply_event(data, api, event_type, status);
119 if (rc != pcmk_rc_ok) {
120 return rc;
121 }
122
123 reply = (const pcmk_controld_api_reply_t *) event_data;
124
125 if (reply->reply_type != expected_type) {
126 out->err(out, "error: Unexpected reply type '%s' from controller",
127 pcmk__controld_api_reply2str(reply->reply_type));
128 data->rc = EBADMSG;
129 return data->rc;
130 }
131
132 return pcmk_rc_ok;
133 }
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149 static int
150 validate_pcmkd_reply(data_t *data, const pcmk_ipc_api_t *api,
151 enum pcmk_ipc_event event_type, crm_exit_t status,
152 const void *event_data,
153 enum pcmk_pacemakerd_api_reply expected_type)
154 {
155 pcmk__output_t *out = data->out;
156 const pcmk_pacemakerd_api_reply_t *reply = NULL;
157 int rc = validate_reply_event(data, api, event_type, status);
158
159 if (rc != pcmk_rc_ok) {
160 return rc;
161 }
162
163 reply = (const pcmk_pacemakerd_api_reply_t *) event_data;
164
165 if (reply->reply_type != expected_type) {
166 out->err(out, "error: Unexpected reply type '%s' from pacemakerd",
167 pcmk__pcmkd_api_reply2str(reply->reply_type));
168 data->rc = EBADMSG;
169 return data->rc;
170 }
171
172 return pcmk_rc_ok;
173 }
174
175
176
177
178
179
180
181
182
183
184
185
186 static void
187 controller_status_event_cb(pcmk_ipc_api_t *controld_api,
188 enum pcmk_ipc_event event_type, crm_exit_t status,
189 void *event_data, void *user_data)
190 {
191 data_t *data = (data_t *) user_data;
192 pcmk__output_t *out = data->out;
193 const pcmk_controld_api_reply_t *reply = NULL;
194
195 int rc = validate_controld_reply(data, controld_api, event_type, status,
196 event_data, pcmk_controld_reply_ping);
197
198 if (rc != pcmk_rc_ok) {
199 return;
200 }
201
202 reply = (const pcmk_controld_api_reply_t *) event_data;
203 out->message(out, "health",
204 reply->data.ping.sys_from, reply->host_from,
205 reply->data.ping.fsa_state, reply->data.ping.result);
206 data->rc = pcmk_rc_ok;
207 }
208
209
210
211
212
213
214
215
216
217
218
219
220 static void
221 designated_controller_event_cb(pcmk_ipc_api_t *controld_api,
222 enum pcmk_ipc_event event_type,
223 crm_exit_t status, void *event_data,
224 void *user_data)
225 {
226 data_t *data = (data_t *) user_data;
227 pcmk__output_t *out = data->out;
228 const pcmk_controld_api_reply_t *reply = NULL;
229
230 int rc = validate_controld_reply(data, controld_api, event_type, status,
231 event_data, pcmk_controld_reply_ping);
232
233 if (rc != pcmk_rc_ok) {
234 return;
235 }
236
237 reply = (const pcmk_controld_api_reply_t *) event_data;
238 out->message(out, "dc", reply->host_from);
239 data->rc = pcmk_rc_ok;
240 }
241
242
243
244
245
246
247
248
249
250
251
252
253 static void
254 node_info_event_cb(pcmk_ipc_api_t *controld_api, enum pcmk_ipc_event event_type,
255 crm_exit_t status, void *event_data, void *user_data)
256 {
257 data_t *data = (data_t *) user_data;
258 pcmk__output_t *out = data->out;
259
260 const pcmk_controld_api_reply_t *reply = NULL;
261
262 int rc = validate_controld_reply(data, controld_api, event_type, status,
263 event_data, pcmk_controld_reply_info);
264
265 if (rc != pcmk_rc_ok) {
266 return;
267 }
268
269 reply = (const pcmk_controld_api_reply_t *) event_data;
270
271 if (reply->data.node_info.uname == NULL) {
272 out->err(out, "Node is not known to cluster");
273 data->rc = pcmk_rc_node_unknown;
274 return;
275 }
276
277 data->node_info.have_quorum = reply->data.node_info.have_quorum;
278 data->node_info.is_remote = reply->data.node_info.is_remote;
279 data->node_info.id = (uint32_t) reply->data.node_info.id;
280
281 pcmk__str_update(data->node_info.node_name, reply->data.node_info.uname);
282 pcmk__str_update(data->node_info.uuid, reply->data.node_info.uuid);
283 pcmk__str_update(data->node_info.state, reply->data.node_info.state);
284
285 if (data->show_output) {
286 out->message(out, "node-info",
287 reply->data.node_info.id, reply->data.node_info.uname,
288 reply->data.node_info.uuid, reply->data.node_info.state,
289 reply->data.node_info.have_quorum,
290 reply->data.node_info.is_remote);
291 }
292
293 data->rc = pcmk_rc_ok;
294 }
295
296
297
298
299
300
301
302
303
304
305
306
307 static void
308 pacemakerd_event_cb(pcmk_ipc_api_t *pacemakerd_api,
309 enum pcmk_ipc_event event_type, crm_exit_t status,
310 void *event_data, void *user_data)
311 {
312 data_t *data = user_data;
313 pcmk__output_t *out = data->out;
314 const pcmk_pacemakerd_api_reply_t *reply = NULL;
315
316 int rc = validate_pcmkd_reply(data, pacemakerd_api, event_type, status,
317 event_data, pcmk_pacemakerd_reply_ping);
318
319 if (rc != pcmk_rc_ok) {
320 return;
321 }
322
323
324 reply = (const pcmk_pacemakerd_api_reply_t *) event_data;
325
326 data->pcmkd_state = reply->data.ping.state;
327 data->rc = pcmk_rc_ok;
328
329 if (!data->show_output) {
330 return;
331 }
332
333 if (reply->data.ping.status == pcmk_rc_ok) {
334 out->message(out, "pacemakerd-health",
335 reply->data.ping.sys_from, reply->data.ping.state, NULL,
336 reply->data.ping.last_good);
337 } else {
338 out->message(out, "pacemakerd-health",
339 reply->data.ping.sys_from, reply->data.ping.state,
340 "query failed", time(NULL));
341 }
342 }
343
344 static pcmk_ipc_api_t *
345 ipc_connect(data_t *data, enum pcmk_ipc_server server, pcmk_ipc_callback_t cb,
346 enum pcmk_ipc_dispatch dispatch_type, bool eremoteio_ok)
347 {
348 int rc;
349 pcmk__output_t *out = data->out;
350 pcmk_ipc_api_t *api = NULL;
351
352 rc = pcmk_new_ipc_api(&api, server);
353 if (api == NULL) {
354 out->err(out, "error: Could not connect to %s: %s",
355 pcmk_ipc_name(api, true),
356 pcmk_rc_str(rc));
357 data->rc = rc;
358 return NULL;
359 }
360 if (cb != NULL) {
361 pcmk_register_ipc_callback(api, cb, data);
362 }
363
364 rc = pcmk__connect_ipc(api, dispatch_type, 5);
365 if (rc != pcmk_rc_ok) {
366 if (rc == EREMOTEIO) {
367 data->pcmkd_state = pcmk_pacemakerd_state_remote;
368 if (eremoteio_ok) {
369
370
371
372 crm_debug("Ignoring %s connection failure: No "
373 "Pacemaker Remote connection",
374 pcmk_ipc_name(api, true));
375 rc = pcmk_rc_ok;
376 } else {
377 out->err(out, "error: Could not connect to %s: %s",
378 pcmk_ipc_name(api, true), pcmk_rc_str(rc));
379 }
380 }
381 data->rc = rc;
382 pcmk_free_ipc_api(api);
383 return NULL;
384 }
385
386 return api;
387 }
388
389
390
391
392
393
394
395
396
397
398
399
400 static void
401 poll_until_reply(data_t *data, pcmk_ipc_api_t *api, const char *on_node)
402 {
403 pcmk__output_t *out = data->out;
404
405 uint64_t start_nsec = qb_util_nano_current_get();
406 uint64_t end_nsec = 0;
407 uint64_t elapsed_ms = 0;
408 uint64_t remaining_ms = data->message_timeout_ms;
409
410 while (remaining_ms > 0) {
411 int rc = pcmk_poll_ipc(api, remaining_ms);
412
413 if (rc == EAGAIN) {
414
415 break;
416 }
417
418 if (rc != pcmk_rc_ok) {
419 out->err(out, "error: Failed to poll %s API%s%s: %s",
420 pcmk_ipc_name(api, true), (on_node != NULL)? " on " : "",
421 pcmk__s(on_node, ""), pcmk_rc_str(rc));
422 data->rc = rc;
423 return;
424 }
425
426 pcmk_dispatch_ipc(api);
427
428 if (data->rc != EAGAIN) {
429
430 return;
431 }
432 end_nsec = qb_util_nano_current_get();
433 elapsed_ms = (end_nsec - start_nsec) / QB_TIME_NS_IN_MSEC;
434 remaining_ms = data->message_timeout_ms - elapsed_ms;
435 }
436
437 out->err(out,
438 "error: Timed out after %ums waiting for reply from %s API%s%s",
439 data->message_timeout_ms, pcmk_ipc_name(api, true),
440 (on_node != NULL)? " on " : "", pcmk__s(on_node, ""));
441 data->rc = EAGAIN;
442 }
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459 int
460 pcmk__controller_status(pcmk__output_t *out, const char *node_name,
461 unsigned int message_timeout_ms)
462 {
463 data_t data = {
464 .out = out,
465 .rc = EAGAIN,
466 .message_timeout_ms = message_timeout_ms,
467 };
468 enum pcmk_ipc_dispatch dispatch_type = pcmk_ipc_dispatch_poll;
469 pcmk_ipc_api_t *controld_api = NULL;
470
471 if (message_timeout_ms == 0) {
472 dispatch_type = pcmk_ipc_dispatch_sync;
473 }
474 controld_api = ipc_connect(&data, pcmk_ipc_controld,
475 controller_status_event_cb, dispatch_type,
476 false);
477
478 if (controld_api != NULL) {
479 int rc = pcmk_controld_api_ping(controld_api, node_name);
480 if (rc != pcmk_rc_ok) {
481 out->err(out, "error: Could not ping controller API on %s: %s",
482 pcmk__s(node_name, "DC"), pcmk_rc_str(rc));
483 data.rc = rc;
484 }
485
486 if (dispatch_type == pcmk_ipc_dispatch_poll) {
487 poll_until_reply(&data, controld_api, pcmk__s(node_name, "DC"));
488 }
489 pcmk_free_ipc_api(controld_api);
490 }
491
492 return data.rc;
493 }
494
495
496
497 int
498 pcmk_controller_status(xmlNodePtr *xml, const char *node_name,
499 unsigned int message_timeout_ms)
500 {
501 pcmk__output_t *out = NULL;
502 int rc = pcmk_rc_ok;
503
504 rc = pcmk__xml_output_new(&out, xml);
505 if (rc != pcmk_rc_ok) {
506 return rc;
507 }
508
509 pcmk__register_lib_messages(out);
510
511 rc = pcmk__controller_status(out, node_name, message_timeout_ms);
512 pcmk__xml_output_finish(out, xml);
513 return rc;
514 }
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529 int
530 pcmk__designated_controller(pcmk__output_t *out,
531 unsigned int message_timeout_ms)
532 {
533 data_t data = {
534 .out = out,
535 .rc = EAGAIN,
536 .message_timeout_ms = message_timeout_ms,
537 };
538 enum pcmk_ipc_dispatch dispatch_type = pcmk_ipc_dispatch_poll;
539 pcmk_ipc_api_t *controld_api = NULL;
540
541 if (message_timeout_ms == 0) {
542 dispatch_type = pcmk_ipc_dispatch_sync;
543 }
544 controld_api = ipc_connect(&data, pcmk_ipc_controld,
545 designated_controller_event_cb, dispatch_type,
546 false);
547
548 if (controld_api != NULL) {
549 int rc = pcmk_controld_api_ping(controld_api, NULL);
550 if (rc != pcmk_rc_ok) {
551 out->err(out, "error: Could not ping controller API on DC: %s",
552 pcmk_rc_str(rc));
553 data.rc = rc;
554 }
555
556 if (dispatch_type == pcmk_ipc_dispatch_poll) {
557 poll_until_reply(&data, controld_api, "DC");
558 }
559 pcmk_free_ipc_api(controld_api);
560 }
561
562 return data.rc;
563 }
564
565
566 int
567 pcmk_designated_controller(xmlNodePtr *xml, unsigned int message_timeout_ms)
568 {
569 pcmk__output_t *out = NULL;
570 int rc = pcmk_rc_ok;
571
572 rc = pcmk__xml_output_new(&out, xml);
573 if (rc != pcmk_rc_ok) {
574 return rc;
575 }
576
577 pcmk__register_lib_messages(out);
578
579 rc = pcmk__designated_controller(out, message_timeout_ms);
580 pcmk__xml_output_finish(out, xml);
581 return rc;
582 }
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616 int
617 pcmk__query_node_info(pcmk__output_t *out, uint32_t *node_id, char **node_name,
618 char **uuid, char **state, bool *have_quorum,
619 bool *is_remote, bool show_output,
620 unsigned int message_timeout_ms)
621 {
622 data_t data = {
623 .out = out,
624 .show_output = show_output,
625 .rc = EAGAIN,
626 .message_timeout_ms = message_timeout_ms,
627 .node_info = {
628 .id = (node_id == NULL)? 0 : *node_id,
629 .node_name = node_name,
630 .uuid = uuid,
631 .state = state,
632 },
633 };
634 enum pcmk_ipc_dispatch dispatch_type = pcmk_ipc_dispatch_poll;
635 pcmk_ipc_api_t *controld_api = NULL;
636
637 if (node_name != NULL) {
638 *node_name = NULL;
639 }
640 if (uuid != NULL) {
641 *uuid = NULL;
642 }
643 if (state != NULL) {
644 *state = NULL;
645 }
646
647 if (message_timeout_ms == 0) {
648 dispatch_type = pcmk_ipc_dispatch_sync;
649 }
650 controld_api = ipc_connect(&data, pcmk_ipc_controld, node_info_event_cb,
651 dispatch_type, false);
652
653 if (controld_api != NULL) {
654 int rc = pcmk_controld_api_node_info(controld_api,
655 (node_id != NULL)? *node_id : 0);
656
657 if (rc != pcmk_rc_ok) {
658 out->err(out,
659 "error: Could not send request to controller API on local "
660 "node: %s", pcmk_rc_str(rc));
661 data.rc = rc;
662 }
663
664 if (dispatch_type == pcmk_ipc_dispatch_poll) {
665 poll_until_reply(&data, controld_api, "local node");
666 }
667 pcmk_free_ipc_api(controld_api);
668 }
669
670 if (data.rc != pcmk_rc_ok) {
671 return data.rc;
672 }
673
674
675 if (node_id != NULL) {
676 *node_id = data.node_info.id;
677 }
678 if (have_quorum != NULL) {
679 *have_quorum = data.node_info.have_quorum;
680 }
681 if (is_remote != NULL) {
682 *is_remote = data.node_info.is_remote;
683 }
684
685 return data.rc;
686 }
687
688
689 int
690 pcmk_query_node_info(xmlNodePtr *xml, uint32_t *node_id, char **node_name,
691 char **uuid, char **state, bool *have_quorum,
692 bool *is_remote, bool show_output,
693 unsigned int message_timeout_ms)
694 {
695 pcmk__output_t *out = NULL;
696 int rc = pcmk_rc_ok;
697
698 CRM_ASSERT(node_name != NULL);
699
700 rc = pcmk__xml_output_new(&out, xml);
701 if (rc != pcmk_rc_ok) {
702 return rc;
703 }
704
705 pcmk__register_lib_messages(out);
706
707 rc = pcmk__query_node_info(out, node_id, node_name, uuid, state,
708 have_quorum, is_remote, show_output,
709 message_timeout_ms);
710 pcmk__xml_output_finish(out, xml);
711 return rc;
712 }
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737 int
738 pcmk__pacemakerd_status(pcmk__output_t *out, const char *ipc_name,
739 unsigned int message_timeout_ms, bool show_output,
740 enum pcmk_pacemakerd_state *state)
741 {
742 data_t data = {
743 .out = out,
744 .show_output = show_output,
745 .rc = EAGAIN,
746 .message_timeout_ms = message_timeout_ms,
747 .pcmkd_state = pcmk_pacemakerd_state_invalid,
748 };
749 enum pcmk_ipc_dispatch dispatch_type = pcmk_ipc_dispatch_poll;
750 pcmk_ipc_api_t *pacemakerd_api = NULL;
751
752 if (message_timeout_ms == 0) {
753 dispatch_type = pcmk_ipc_dispatch_sync;
754 }
755 pacemakerd_api = ipc_connect(&data, pcmk_ipc_pacemakerd,
756 pacemakerd_event_cb, dispatch_type, true);
757
758 if (pacemakerd_api != NULL) {
759 int rc = pcmk_pacemakerd_api_ping(pacemakerd_api, ipc_name);
760 if (rc != pcmk_rc_ok) {
761 out->err(out, "error: Could not ping launcher API: %s",
762 pcmk_rc_str(rc));
763 data.rc = rc;
764 }
765
766 if (dispatch_type == pcmk_ipc_dispatch_poll) {
767 poll_until_reply(&data, pacemakerd_api, NULL);
768 }
769 pcmk_free_ipc_api(pacemakerd_api);
770
771 } else if ((data.pcmkd_state == pcmk_pacemakerd_state_remote)
772 && show_output) {
773
774 out->message(out, "pacemakerd-health",
775 NULL, data.pcmkd_state, NULL, time(NULL));
776 }
777
778 if (state != NULL) {
779 *state = data.pcmkd_state;
780 }
781 return data.rc;
782 }
783
784
785 int
786 pcmk_pacemakerd_status(xmlNodePtr *xml, const char *ipc_name,
787 unsigned int message_timeout_ms)
788 {
789 pcmk__output_t *out = NULL;
790 int rc = pcmk_rc_ok;
791
792 rc = pcmk__xml_output_new(&out, xml);
793 if (rc != pcmk_rc_ok) {
794 return rc;
795 }
796
797 pcmk__register_lib_messages(out);
798
799 rc = pcmk__pacemakerd_status(out, ipc_name, message_timeout_ms, true, NULL);
800 pcmk__xml_output_finish(out, xml);
801 return rc;
802 }
803
804
805 struct node_data {
806 pcmk__output_t *out;
807 int found;
808 const char *field;
809 const char *type;
810 bool bash_export;
811 };
812
813 static void
814 remote_node_print_helper(xmlNode *result, void *user_data)
815 {
816 struct node_data *data = user_data;
817 pcmk__output_t *out = data->out;
818 const char *name = crm_element_value(result, XML_ATTR_UNAME);
819 const char *id = crm_element_value(result, data->field);
820
821
822 out->message(out, "crmadmin-node", data->type,
823 pcmk__s(name, id), id, data->bash_export);
824 data->found++;
825 }
826
827
828 int
829 pcmk__list_nodes(pcmk__output_t *out, const char *node_types, bool bash_export)
830 {
831 xmlNode *xml_node = NULL;
832 int rc;
833
834 rc = cib__signon_query(out, NULL, &xml_node);
835
836 if (rc == pcmk_rc_ok) {
837 struct node_data data = {
838 .out = out,
839 .found = 0,
840 .bash_export = bash_export
841 };
842
843 out->begin_list(out, NULL, NULL, "nodes");
844
845 if (!pcmk__str_empty(node_types) && strstr(node_types, "all")) {
846 node_types = NULL;
847 }
848
849 if (pcmk__str_empty(node_types) || strstr(node_types, "cluster")) {
850 data.field = "id";
851 data.type = "cluster";
852 crm_foreach_xpath_result(xml_node, PCMK__XP_MEMBER_NODE_CONFIG,
853 remote_node_print_helper, &data);
854 }
855
856 if (pcmk__str_empty(node_types) || strstr(node_types, "guest")) {
857 data.field = "value";
858 data.type = "guest";
859 crm_foreach_xpath_result(xml_node, PCMK__XP_GUEST_NODE_CONFIG,
860 remote_node_print_helper, &data);
861 }
862
863 if (pcmk__str_empty(node_types)
864 || pcmk__str_eq(node_types, ",|^remote", pcmk__str_regex)) {
865 data.field = "id";
866 data.type = "remote";
867 crm_foreach_xpath_result(xml_node, PCMK__XP_REMOTE_NODE_CONFIG,
868 remote_node_print_helper, &data);
869 }
870
871 out->end_list(out);
872
873 if (data.found == 0) {
874 out->info(out, "No nodes configured");
875 }
876
877 free_xml(xml_node);
878 }
879
880 return rc;
881 }
882
883 int
884 pcmk_list_nodes(xmlNodePtr *xml, const char *node_types)
885 {
886 pcmk__output_t *out = NULL;
887 int rc = pcmk_rc_ok;
888
889 rc = pcmk__xml_output_new(&out, xml);
890 if (rc != pcmk_rc_ok) {
891 return rc;
892 }
893
894 pcmk__register_lib_messages(out);
895
896 rc = pcmk__list_nodes(out, node_types, FALSE);
897 pcmk__xml_output_finish(out, xml);
898 return rc;
899 }