This source file includes following definitions.
- main
- do_work
- crmadmin_ipc_connection_destroy
- do_init
- validate_crm_message
- admin_msg_callback
- admin_message_timeout
- is_node_online
- do_find_node_list
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <crm_internal.h>
21
22 #include <sys/param.h>
23
24 #include <stdio.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <libgen.h>
32
33 #include <crm/crm.h>
34 #include <crm/msg_xml.h>
35 #include <crm/common/xml.h>
36
37 #include <crm/common/mainloop.h>
38
39 #include <crm/cib.h>
40
41 int message_timer_id = -1;
42 int message_timeout_ms = 30 * 1000;
43
44 GMainLoop *mainloop = NULL;
45 crm_ipc_t *crmd_channel = NULL;
46 char *admin_uuid = NULL;
47
48 void usage(const char *cmd, int exit_status);
49 gboolean do_init(void);
50 int do_work(void);
51 void crmadmin_ipc_connection_destroy(gpointer user_data);
52
53 int admin_msg_callback(const char *buffer, ssize_t length, gpointer userdata);
54 char *pluralSection(const char *a_section);
55 xmlNode *handleCibMod(void);
56 int do_find_node_list(xmlNode * xml_node);
57 gboolean admin_message_timeout(gpointer data);
58 gboolean is_node_online(xmlNode * node_state);
59
60 enum debug {
61 debug_none,
62 debug_dec,
63 debug_inc
64 };
65
66 gboolean BE_VERBOSE = FALSE;
67 int expected_responses = 1;
68
69 gboolean BASH_EXPORT = FALSE;
70 gboolean DO_HEALTH = FALSE;
71 gboolean DO_RESET = FALSE;
72 gboolean DO_RESOURCE = FALSE;
73 gboolean DO_ELECT_DC = FALSE;
74 gboolean DO_WHOIS_DC = FALSE;
75 gboolean DO_NODE_LIST = FALSE;
76 gboolean BE_SILENT = FALSE;
77 gboolean DO_RESOURCE_LIST = FALSE;
78 enum debug DO_DEBUG = debug_none;
79 const char *crmd_operation = NULL;
80
81 xmlNode *msg_options = NULL;
82
83 const char *standby_on_off = "on";
84 const char *admin_verbose = XML_BOOLEAN_FALSE;
85 char *id = NULL;
86 char *disconnect = NULL;
87 char *dest_node = NULL;
88 char *rsc_name = NULL;
89 char *crm_option = NULL;
90
91 int operation_status = 0;
92 const char *sys_to = NULL;
93
94
95 static struct crm_option long_options[] = {
96
97 {"help", 0, 0, '?', "\tThis text"},
98 {"version", 0, 0, '$', "\tVersion information" },
99 {"quiet", 0, 0, 'q', "\tDisplay only the essential query information"},
100 {"verbose", 0, 0, 'V', "\tIncrease debug output"},
101
102 {"-spacer-", 1, 0, '-', "\nCommands:"},
103
104 {"debug_inc", 1, 0, 'i', "Increase the crmd's debug level on the specified host"},
105 {"debug_dec", 1, 0, 'd', "Decrease the crmd's debug level on the specified host"},
106 {"status", 1, 0, 'S', "Display the status of the specified node." },
107 {"-spacer-", 1, 0, '-', "\n\tResult is the node's internal FSM state which can be useful for debugging\n"},
108 {"dc_lookup", 0, 0, 'D', "Display the uname of the node co-ordinating the cluster."},
109 {"-spacer-", 1, 0, '-', "\n\tThis is an internal detail and is rarely useful to administrators except when deciding on which node to examine the logs.\n"},
110 {"nodes", 0, 0, 'N', "\tDisplay the uname of all member nodes"},
111 {"election", 0, 0, 'E', "(Advanced) Start an election for the cluster co-ordinator"},
112 {"kill", 1, 0, 'K', "(Advanced) Shut down the crmd (not the rest of the clusterstack ) on the specified node"},
113 {"health", 0, 0, 'H', NULL, 1},
114
115 {"-spacer-", 1, 0, '-', "\nAdditional Options:"},
116 {XML_ATTR_TIMEOUT, 1, 0, 't', "Time (in milliseconds) to wait before declaring the operation failed"},
117 {"bash-export", 0, 0, 'B', "Create Bash export entries of the form 'export uname=uuid'\n"},
118
119 {"-spacer-", 1, 0, '-', "Notes:"},
120 {"-spacer-", 1, 0, '-', " The -i,-d,-K and -E commands are rarely used and may be removed in future versions."},
121
122 {0, 0, 0, 0}
123 };
124
125
126 int
127 main(int argc, char **argv)
128 {
129 int option_index = 0;
130 int argerr = 0;
131 int flag;
132
133 crm_log_cli_init("crmadmin");
134 crm_set_options(NULL, "command [options]", long_options,
135 "Development tool for performing some crmd-specific commands."
136 "\n Likely to be replaced by crm_node in the future");
137 if (argc < 2) {
138 crm_help('?', EX_USAGE);
139 }
140
141 while (1) {
142 flag = crm_get_option(argc, argv, &option_index);
143 if (flag == -1)
144 break;
145
146 switch (flag) {
147 case 'V':
148 BE_VERBOSE = TRUE;
149 admin_verbose = XML_BOOLEAN_TRUE;
150 crm_bump_log_level(argc, argv);
151 break;
152 case 't':
153 message_timeout_ms = atoi(optarg);
154 if (message_timeout_ms < 1) {
155 message_timeout_ms = 30 * 1000;
156 }
157 break;
158
159 case '$':
160 case '?':
161 crm_help(flag, EX_OK);
162 break;
163 case 'D':
164 DO_WHOIS_DC = TRUE;
165 break;
166 case 'B':
167 BASH_EXPORT = TRUE;
168 break;
169 case 'K':
170 DO_RESET = TRUE;
171 crm_trace("Option %c => %s", flag, optarg);
172 dest_node = strdup(optarg);
173 crmd_operation = CRM_OP_LOCAL_SHUTDOWN;
174 break;
175 case 'q':
176 BE_SILENT = TRUE;
177 break;
178 case 'i':
179 DO_DEBUG = debug_inc;
180 crm_trace("Option %c => %s", flag, optarg);
181 dest_node = strdup(optarg);
182 break;
183 case 'd':
184 DO_DEBUG = debug_dec;
185 crm_trace("Option %c => %s", flag, optarg);
186 dest_node = strdup(optarg);
187 break;
188 case 'S':
189 DO_HEALTH = TRUE;
190 crm_trace("Option %c => %s", flag, optarg);
191 dest_node = strdup(optarg);
192 break;
193 case 'E':
194 DO_ELECT_DC = TRUE;
195 break;
196 case 'N':
197 DO_NODE_LIST = TRUE;
198 break;
199 case 'H':
200 DO_HEALTH = TRUE;
201 break;
202 default:
203 printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag);
204 ++argerr;
205 break;
206 }
207 }
208
209 if (optind < argc) {
210 printf("non-option ARGV-elements: ");
211 while (optind < argc)
212 printf("%s ", argv[optind++]);
213 printf("\n");
214 }
215
216 if (optind > argc) {
217 ++argerr;
218 }
219
220 if (argerr) {
221 crm_help('?', EX_USAGE);
222 }
223
224 if (do_init()) {
225 int res = 0;
226
227 res = do_work();
228 if (res > 0) {
229
230
231
232 mainloop = g_main_new(FALSE);
233 crm_trace("Waiting for %d replies from the local CRM", expected_responses);
234
235 message_timer_id = g_timeout_add(message_timeout_ms, admin_message_timeout, NULL);
236
237 g_main_run(mainloop);
238
239 } else if (res < 0) {
240 crm_err("No message to send");
241 operation_status = -1;
242 }
243 } else {
244 crm_warn("Init failed, could not perform requested operations");
245 operation_status = -2;
246 }
247
248 crm_trace("%s exiting normally", crm_system_name);
249 return operation_status;
250 }
251
252 int
253 do_work(void)
254 {
255 int ret = 1;
256
257
258 xmlNode *msg_data = NULL;
259 gboolean all_is_good = TRUE;
260
261 msg_options = create_xml_node(NULL, XML_TAG_OPTIONS);
262 crm_xml_add(msg_options, XML_ATTR_VERBOSE, admin_verbose);
263 crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
264
265 if (DO_HEALTH == TRUE) {
266 crm_trace("Querying the system");
267
268 sys_to = CRM_SYSTEM_DC;
269
270 if (dest_node != NULL) {
271 sys_to = CRM_SYSTEM_CRMD;
272 crmd_operation = CRM_OP_PING;
273
274 if (BE_VERBOSE) {
275 expected_responses = 1;
276 }
277
278 crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
279
280 } else {
281 crm_info("Cluster-wide health not available yet");
282 all_is_good = FALSE;
283 }
284
285 } else if (DO_ELECT_DC) {
286
287
288 dest_node = NULL;
289 sys_to = CRM_SYSTEM_CRMD;
290 crmd_operation = CRM_OP_VOTE;
291
292 crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
293 ret = 0;
294
295 } else if (DO_WHOIS_DC) {
296 dest_node = NULL;
297 sys_to = CRM_SYSTEM_DC;
298 crmd_operation = CRM_OP_PING;
299 crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
300
301 } else if (DO_NODE_LIST) {
302
303 cib_t *the_cib = cib_new();
304 xmlNode *output = NULL;
305
306 int rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command);
307
308 if (rc != pcmk_ok) {
309 return -1;
310 }
311
312 rc = the_cib->cmds->query(the_cib, NULL, &output, cib_scope_local | cib_sync_call);
313 if(rc == pcmk_ok) {
314 do_find_node_list(output);
315
316 free_xml(output);
317 }
318 the_cib->cmds->signoff(the_cib);
319 crm_exit(rc);
320
321 } else if (DO_RESET) {
322
323
324
325
326
327 sys_to = CRM_SYSTEM_CRMD;
328 crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
329
330 ret = 0;
331
332 } else if (DO_DEBUG == debug_inc) {
333
334
335
336
337
338 sys_to = CRM_SYSTEM_CRMD;
339 crmd_operation = CRM_OP_DEBUG_UP;
340
341 ret = 0;
342
343 } else if (DO_DEBUG == debug_dec) {
344
345
346
347
348
349 sys_to = CRM_SYSTEM_CRMD;
350 crmd_operation = CRM_OP_DEBUG_DOWN;
351
352 ret = 0;
353
354 } else {
355 crm_err("Unknown options");
356 all_is_good = FALSE;
357 }
358
359 if (all_is_good == FALSE) {
360 crm_err("Creation of request failed. No message to send");
361 return -1;
362 }
363
364
365 if (crmd_channel == NULL) {
366 crm_err("The IPC connection is not valid, cannot send anything");
367 return -1;
368 }
369
370 if (sys_to == NULL) {
371 if (dest_node != NULL) {
372 sys_to = CRM_SYSTEM_CRMD;
373 } else {
374 sys_to = CRM_SYSTEM_DC;
375 }
376 }
377
378 {
379 xmlNode *cmd = create_request(crmd_operation, msg_data, dest_node, sys_to,
380 crm_system_name, admin_uuid);
381
382 crm_ipc_send(crmd_channel, cmd, 0, 0, NULL);
383 free_xml(cmd);
384 }
385
386 return ret;
387 }
388
389 void
390 crmadmin_ipc_connection_destroy(gpointer user_data)
391 {
392 crm_err("Connection to CRMd was terminated");
393 if (mainloop) {
394 g_main_quit(mainloop);
395 } else {
396 crm_exit(ENOTCONN);
397 }
398 }
399
400 struct ipc_client_callbacks crm_callbacks = {
401 .dispatch = admin_msg_callback,
402 .destroy = crmadmin_ipc_connection_destroy
403 };
404
405 gboolean
406 do_init(void)
407 {
408 mainloop_io_t *source =
409 mainloop_add_ipc_client(CRM_SYSTEM_CRMD, G_PRIORITY_DEFAULT, 0, NULL, &crm_callbacks);
410
411 admin_uuid = crm_getpid_s();
412
413 crmd_channel = mainloop_get_ipc_client(source);
414
415 if (DO_RESOURCE || DO_RESOURCE_LIST || DO_NODE_LIST) {
416 return TRUE;
417
418 } else if (crmd_channel != NULL) {
419 xmlNode *xml = create_hello_message(admin_uuid, crm_system_name, "0", "1");
420
421 crm_ipc_send(crmd_channel, xml, 0, 0, NULL);
422 return TRUE;
423 }
424 return FALSE;
425 }
426
427 static bool
428 validate_crm_message(xmlNode * msg, const char *sys, const char *uuid, const char *msg_type)
429 {
430 const char *type = NULL;
431 const char *crm_msg_reference = NULL;
432
433 if (msg == NULL) {
434 return FALSE;
435 }
436
437 type = crm_element_value(msg, F_CRM_MSG_TYPE);
438 crm_msg_reference = crm_element_value(msg, XML_ATTR_REFERENCE);
439
440 if (type == NULL) {
441 crm_info("No message type defined.");
442 return FALSE;
443
444 } else if (msg_type != NULL && strcasecmp(msg_type, type) != 0) {
445 crm_info("Expecting a (%s) message but received a (%s).", msg_type, type);
446 return FALSE;
447 }
448
449 if (crm_msg_reference == NULL) {
450 crm_info("No message crm_msg_reference defined.");
451 return FALSE;
452 }
453
454 return TRUE;
455 }
456
457 int
458 admin_msg_callback(const char *buffer, ssize_t length, gpointer userdata)
459 {
460 static int received_responses = 0;
461 xmlNode *xml = string2xml(buffer);
462
463 received_responses++;
464 g_source_remove(message_timer_id);
465
466 crm_log_xml_trace(xml, "ipc");
467
468 if (xml == NULL) {
469 crm_info("XML in IPC message was not valid... " "discarding.");
470
471 } else if (validate_crm_message(xml, crm_system_name, admin_uuid, XML_ATTR_RESPONSE) == FALSE) {
472 crm_trace("Message was not a CRM response. Discarding.");
473
474 } else if (DO_HEALTH) {
475 xmlNode *data = get_message_xml(xml, F_CRM_DATA);
476 const char *state = crm_element_value(data, "crmd_state");
477
478 printf("Status of %s@%s: %s (%s)\n",
479 crm_element_value(data, XML_PING_ATTR_SYSFROM),
480 crm_element_value(xml, F_CRM_HOST_FROM),
481 state, crm_element_value(data, XML_PING_ATTR_STATUS));
482
483 if (BE_SILENT && state != NULL) {
484 fprintf(stderr, "%s\n", state);
485 }
486
487 } else if (DO_WHOIS_DC) {
488 const char *dc = crm_element_value(xml, F_CRM_HOST_FROM);
489
490 printf("Designated Controller is: %s\n", dc);
491 if (BE_SILENT && dc != NULL) {
492 fprintf(stderr, "%s\n", dc);
493 }
494 crm_exit(pcmk_ok);
495 }
496
497 free_xml(xml);
498
499 if (received_responses >= expected_responses) {
500 crm_trace("Received expected number (%d) of messages from Heartbeat."
501 " Exiting normally.", expected_responses);
502 crm_exit(pcmk_ok);
503 }
504
505 message_timer_id = g_timeout_add(message_timeout_ms, admin_message_timeout, NULL);
506 return 0;
507 }
508
509 gboolean
510 admin_message_timeout(gpointer data)
511 {
512 fprintf(stderr, "No messages received in %d seconds.. aborting\n",
513 (int)message_timeout_ms / 1000);
514 crm_err("No messages received in %d seconds", (int)message_timeout_ms / 1000);
515 operation_status = -3;
516 g_main_quit(mainloop);
517 return FALSE;
518 }
519
520 gboolean
521 is_node_online(xmlNode * node_state)
522 {
523 const char *uname = crm_element_value(node_state, XML_ATTR_UNAME);
524 const char *join_state = crm_element_value(node_state, XML_NODE_JOIN_STATE);
525 const char *exp_state = crm_element_value(node_state, XML_NODE_EXPECTED);
526 const char *crm_state = crm_element_value(node_state, XML_NODE_IS_PEER);
527 const char *ccm_state = crm_element_value(node_state, XML_NODE_IN_CLUSTER);
528
529 if (safe_str_neq(join_state, CRMD_JOINSTATE_DOWN)
530 && crm_is_true(ccm_state)
531 && safe_str_eq(crm_state, "online")) {
532 crm_trace("Node %s is online", uname);
533 return TRUE;
534 }
535 crm_trace("Node %s: ccm=%s join=%s exp=%s crm=%s",
536 uname, crm_str(ccm_state),
537 crm_str(join_state), crm_str(exp_state), crm_str(crm_state));
538 crm_trace("Node %s is offline", uname);
539 return FALSE;
540 }
541
542 int
543 do_find_node_list(xmlNode * xml_node)
544 {
545 int found = 0;
546 xmlNode *node = NULL;
547 xmlNode *nodes = get_object_root(XML_CIB_TAG_NODES, xml_node);
548
549 for (node = __xml_first_child(nodes); node != NULL; node = __xml_next(node)) {
550 if (crm_str_eq((const char *)node->name, XML_CIB_TAG_NODE, TRUE)) {
551
552 if (BASH_EXPORT) {
553 printf("export %s=%s\n",
554 crm_element_value(node, XML_ATTR_UNAME),
555 crm_element_value(node, XML_ATTR_ID));
556 } else {
557 printf("%s node: %s (%s)\n",
558 crm_element_value(node, XML_ATTR_TYPE),
559 crm_element_value(node, XML_ATTR_UNAME),
560 crm_element_value(node, XML_ATTR_ID));
561 }
562 found++;
563 }
564 }
565
566 if (found == 0) {
567 printf("NO nodes configured\n");
568 }
569
570 return found;
571 }