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