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