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