This source file includes following definitions.
- cib_remove_node
- tools_remove_node_cache
- compare_node_uname
- node_mcp_dispatch
- node_mcp_destroy
- try_pacemaker
- read_local_hb_uuid
- ccm_age_callback
- ccm_age_connect
- try_heartbeat
- valid_cman_name
- try_cman
- ais_membership_destroy
- member_sort
- crm_add_member
- ais_membership_dispatch
- try_corosync
- try_openais
- main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <crm_internal.h>
20
21 #include <sys/param.h>
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <fcntl.h>
29
30 #include <libgen.h>
31
32 #include <crm/crm.h>
33 #include <crm/cluster/internal.h>
34 #include <crm/common/mainloop.h>
35 #include <crm/msg_xml.h>
36 #include <crm/cib.h>
37 #include <crm/attrd.h>
38
39 int command = 0;
40 int ccm_fd = 0;
41 gboolean do_quiet = FALSE;
42
43 char *target_uuid = NULL;
44 char *target_uname = NULL;
45 const char *standby_value = NULL;
46 const char *standby_scope = NULL;
47
48
49 static struct crm_option long_options[] = {
50
51 {"help", 0, 0, '?', "\tThis text"},
52 {"version", 0, 0, '$', "\tVersion information" },
53 {"verbose", 0, 0, 'V', "\tIncrease debug output"},
54 {"quiet", 0, 0, 'Q', "\tEssential output only"},
55
56 {"-spacer-", 1, 0, '-', "\nStack:"},
57 #if SUPPORT_CMAN
58 {"cman", 0, 0, 'c', "\tOnly try connecting to a cman-based cluster"},
59 #endif
60 #if SUPPORT_COROSYNC
61 {"openais", 0, 0, 'A', "\tOnly try connecting to an OpenAIS-based cluster"},
62 #endif
63 #ifdef SUPPORT_CS_QUORUM
64 {"corosync", 0, 0, 'C', "\tOnly try connecting to an Corosync-based cluster"},
65 #endif
66 #ifdef SUPPORT_HEARTBEAT
67 {"heartbeat", 0, 0, 'H', "Only try connecting to a Heartbeat-based cluster"},
68 #endif
69
70 {"-spacer-", 1, 0, '-', "\nCommands:"},
71 {"name", 0, 0, 'n', "\tDisplay the name used by the cluster for this node"},
72 {"name-for-id", 1, 0, 'N', "\tDisplay the name used by the cluster for the node with the specified id"},
73 {"epoch", 0, 0, 'e', "\tDisplay the epoch during which this node joined the cluster"},
74 {"quorum", 0, 0, 'q', "\tDisplay a 1 if our partition has quorum, 0 if not"},
75 {"list", 0, 0, 'l', "\tDisplay all known members (past and present) of this cluster (Not available for heartbeat clusters)"},
76 {"partition", 0, 0, 'p', "Display the members of this partition"},
77 {"cluster-id", 0, 0, 'i', "Display this node's cluster id"},
78 {"remove", 1, 0, 'R', "(Advanced) Remove the (stopped) node with the specified name from Pacemaker's configuration and caches"},
79 {"-spacer-", 1, 0, '-', "In the case of Heartbeat, CMAN and Corosync 2.0, requires that the node has already been removed from the underlying cluster"},
80
81 {"-spacer-", 1, 0, '-', "\nAdditional Options:"},
82 {"force", 0, 0, 'f'},
83
84 {0, 0, 0, 0}
85 };
86
87
88 static int
89 cib_remove_node(uint32_t id, const char *name)
90 {
91 int rc;
92 cib_t *cib = NULL;
93 xmlNode *node = NULL;
94 xmlNode *node_state = NULL;
95
96 crm_trace("Removing %s from the CIB", name);
97
98 if(name == NULL && id == 0) {
99 return -ENOTUNIQ;
100 }
101
102 node = create_xml_node(NULL, XML_CIB_TAG_NODE);
103 node_state = create_xml_node(NULL, XML_CIB_TAG_STATE);
104
105 crm_xml_add(node, XML_ATTR_UNAME, name);
106 crm_xml_add(node_state, XML_ATTR_UNAME, name);
107 if(id) {
108 crm_xml_set_id(node, "%u", id);
109 crm_xml_add(node_state, XML_ATTR_ID, ID(node));
110 }
111
112 cib = cib_new();
113 cib->cmds->signon(cib, crm_system_name, cib_command);
114
115 rc = cib->cmds->delete(cib, XML_CIB_TAG_NODES, node, cib_sync_call);
116 if (rc != pcmk_ok) {
117 printf("Could not remove %s/%u from " XML_CIB_TAG_NODES ": %s", name, id, pcmk_strerror(rc));
118 }
119 rc = cib->cmds->delete(cib, XML_CIB_TAG_STATUS, node_state, cib_sync_call);
120 if (rc != pcmk_ok) {
121 printf("Could not remove %s/%u from " XML_CIB_TAG_STATUS ": %s", name, id, pcmk_strerror(rc));
122 }
123
124 cib->cmds->signoff(cib);
125 cib_delete(cib);
126 return rc;
127 }
128
129 int tools_remove_node_cache(const char *node, const char *target);
130
131 int tools_remove_node_cache(const char *node, const char *target)
132 {
133 int n = 0;
134 int rc = -1;
135 char *name = NULL;
136 char *admin_uuid = NULL;
137 crm_ipc_t *conn = crm_ipc_new(target, 0);
138 xmlNode *cmd = NULL;
139 xmlNode *hello = NULL;
140 char *endptr = NULL;
141
142 if (!conn) {
143 return -ENOTCONN;
144 }
145
146 if (!crm_ipc_connect(conn)) {
147 crm_perror(LOG_ERR, "Connection to %s failed", target);
148 crm_ipc_destroy(conn);
149 return -ENOTCONN;
150 }
151
152 if(safe_str_eq(target, CRM_SYSTEM_CRMD)) {
153 admin_uuid = crm_getpid_s();
154
155 hello = create_hello_message(admin_uuid, "crm_node", "0", "1");
156 rc = crm_ipc_send(conn, hello, 0, 0, NULL);
157
158 free_xml(hello);
159 if (rc < 0) {
160 free(admin_uuid);
161 return rc;
162 }
163 }
164
165
166 errno = 0;
167 n = strtol(node, &endptr, 10);
168 if (errno != 0 || endptr == node || *endptr != '\0') {
169
170 n = 0;
171 name = strdup(node);
172 } else {
173 name = get_node_name(n);
174 }
175
176 crm_trace("Removing %s aka. %s (%u) from the membership cache", name, node, n);
177
178 if(safe_str_eq(target, T_ATTRD)) {
179 cmd = create_xml_node(NULL, __FUNCTION__);
180
181 crm_xml_add(cmd, F_TYPE, T_ATTRD);
182 crm_xml_add(cmd, F_ORIG, crm_system_name);
183
184 crm_xml_add(cmd, F_ATTRD_TASK, ATTRD_OP_PEER_REMOVE);
185 crm_xml_add(cmd, F_ATTRD_HOST, name);
186
187 if (n) {
188 char buffer[64];
189 if(snprintf(buffer, 63, "%u", n) > 0) {
190 crm_xml_add(cmd, F_ATTRD_HOST_ID, buffer);
191 }
192 }
193
194 } else {
195 cmd = create_request(CRM_OP_RM_NODE_CACHE,
196 NULL, NULL, target, crm_system_name, admin_uuid);
197 if (n) {
198 crm_xml_set_id(cmd, "%u", n);
199 }
200 crm_xml_add(cmd, XML_ATTR_UNAME, name);
201 }
202
203 rc = crm_ipc_send(conn, cmd, 0, 0, NULL);
204 crm_debug("%s peer cache cleanup for %s (%u): %d", target, name, n, rc);
205
206 if (rc > 0) {
207 rc = cib_remove_node(n, name);
208 }
209
210 if (conn) {
211 crm_ipc_close(conn);
212 crm_ipc_destroy(conn);
213 }
214 free(admin_uuid);
215 free_xml(cmd);
216 free(name);
217 return rc > 0 ? 0 : rc;
218 }
219
220 static gint
221 compare_node_uname(gconstpointer a, gconstpointer b)
222 {
223 const crm_node_t *a_node = a;
224 const crm_node_t *b_node = b;
225 return strcmp(a_node->uname?a_node->uname:"", b_node->uname?b_node->uname:"");
226 }
227
228 static int
229 node_mcp_dispatch(const char *buffer, ssize_t length, gpointer userdata)
230 {
231 xmlNode *msg = string2xml(buffer);
232
233 if (msg) {
234 xmlNode *node = NULL;
235 GListPtr nodes = NULL;
236 GListPtr iter = NULL;
237 const char *quorate = crm_element_value(msg, "quorate");
238
239 crm_log_xml_trace(msg, "message");
240 if (command == 'q' && quorate != NULL) {
241 fprintf(stdout, "%s\n", quorate);
242 crm_exit(pcmk_ok);
243
244 } else if(command == 'q') {
245 crm_exit(1);
246 }
247
248 for (node = __xml_first_child(msg); node != NULL; node = __xml_next(node)) {
249 crm_node_t *peer = calloc(1, sizeof(crm_node_t));
250
251 nodes = g_list_insert_sorted(nodes, peer, compare_node_uname);
252 peer->uname = (char*)crm_element_value_copy(node, "uname");
253 peer->state = (char*)crm_element_value_copy(node, "state");
254 crm_element_value_int(node, "id", (int*)&peer->id);
255 }
256
257 for(iter = nodes; iter; iter = iter->next) {
258 crm_node_t *peer = iter->data;
259 if (command == 'l') {
260 fprintf(stdout, "%u %s %s\n", peer->id, peer->uname, peer->state?peer->state:"");
261
262 } else if (command == 'p') {
263 if(safe_str_eq(peer->state, CRM_NODE_MEMBER)) {
264 fprintf(stdout, "%s ", peer->uname);
265 }
266
267 } else if (command == 'i') {
268 if(safe_str_eq(peer->state, CRM_NODE_MEMBER)) {
269 fprintf(stdout, "%u ", peer->id);
270 }
271 }
272 }
273
274 g_list_free_full(nodes, free);
275 free_xml(msg);
276
277 if (command == 'p') {
278 fprintf(stdout, "\n");
279 }
280
281 crm_exit(pcmk_ok);
282 }
283
284 return 0;
285 }
286
287 static void
288 node_mcp_destroy(gpointer user_data)
289 {
290 crm_exit(ENOTCONN);
291 }
292
293 static gboolean
294 try_pacemaker(int command, enum cluster_type_e stack)
295 {
296 struct ipc_client_callbacks node_callbacks = {
297 .dispatch = node_mcp_dispatch,
298 .destroy = node_mcp_destroy
299 };
300
301 if (stack == pcmk_cluster_heartbeat) {
302
303 return FALSE;
304 }
305
306 switch (command) {
307 case 'e':
308
309 fprintf(stdout, "1\n");
310 crm_exit(pcmk_ok);
311
312 case 'R':
313 {
314 int lpc = 0;
315 const char *daemons[] = {
316 CRM_SYSTEM_CRMD,
317 "stonith-ng",
318 T_ATTRD,
319 CRM_SYSTEM_MCP,
320 };
321
322 for(lpc = 0; lpc < DIMOF(daemons); lpc++) {
323 if (tools_remove_node_cache(target_uname, daemons[lpc])) {
324 crm_err("Failed to connect to %s to remove node '%s'", daemons[lpc], target_uname);
325 crm_exit(pcmk_err_generic);
326 }
327 }
328 crm_exit(pcmk_ok);
329 }
330 break;
331
332 case 'i':
333 case 'l':
334 case 'q':
335 case 'p':
336
337 {
338 GMainLoop *amainloop = g_main_loop_new(NULL, FALSE);
339 mainloop_io_t *ipc =
340 mainloop_add_ipc_client(CRM_SYSTEM_MCP, G_PRIORITY_DEFAULT, 0, NULL, &node_callbacks);
341 if (ipc != NULL) {
342
343 xmlNode *poke = create_xml_node(NULL, "poke");
344
345 crm_ipc_send(mainloop_get_ipc_client(ipc), poke, 0, 0, NULL);
346 free_xml(poke);
347 g_main_run(amainloop);
348 }
349 }
350 break;
351 }
352 return FALSE;
353 }
354
355 #if SUPPORT_HEARTBEAT
356 # include <ocf/oc_event.h>
357 # include <ocf/oc_membership.h>
358 # include <clplumbing/cl_uuid.h>
359
360 # define UUID_LEN 16
361
362 oc_ev_t *ccm_token = NULL;
363 static void *ccm_library = NULL;
364 void oc_ev_special(const oc_ev_t *, oc_ev_class_t, int);
365
366 static gboolean
367 read_local_hb_uuid(void)
368 {
369 cl_uuid_t uuid;
370 char *buffer = NULL;
371 long start = 0, read_len = 0;
372
373 FILE *input = fopen(UUID_FILE, "r");
374
375 if (input == NULL) {
376 crm_info("Could not open UUID file %s", UUID_FILE);
377 return FALSE;
378 }
379
380
381 start = ftell(input);
382 fseek(input, 0L, SEEK_END);
383 if (UUID_LEN != ftell(input)) {
384 fprintf(stderr, "%s must contain exactly %d bytes\n", UUID_FILE, UUID_LEN);
385 abort();
386 }
387
388 fseek(input, 0L, start);
389 if (start != ftell(input)) {
390 fprintf(stderr, "fseek not behaving: %ld vs. %ld\n", start, ftell(input));
391 crm_exit(pcmk_err_generic);
392 }
393
394 buffer = malloc(50);
395 read_len = fread(uuid.uuid, 1, UUID_LEN, input);
396 fclose(input);
397
398 if (read_len != UUID_LEN) {
399 fprintf(stderr, "Expected and read bytes differ: %d vs. %ld\n", UUID_LEN, read_len);
400 crm_exit(pcmk_err_generic);
401
402 } else if (buffer != NULL) {
403 cl_uuid_unparse(&uuid, buffer);
404 fprintf(stdout, "%s\n", buffer);
405 return TRUE;
406
407 } else {
408 fprintf(stderr, "No buffer to unparse\n");
409 crm_exit(ENODATA);
410 }
411
412 free(buffer);
413 return FALSE;
414 }
415
416 static void
417 ccm_age_callback(oc_ed_t event, void *cookie, size_t size, const void *data)
418 {
419 int lpc;
420 int node_list_size;
421 const oc_ev_membership_t *oc = (const oc_ev_membership_t *)data;
422
423 int (*ccm_api_callback_done) (void *cookie) =
424 find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_callback_done", 1);
425
426 node_list_size = oc->m_n_member;
427 if (command == 'q') {
428 crm_debug("Processing \"%s\" event.",
429 event == OC_EV_MS_NEW_MEMBERSHIP ? "NEW MEMBERSHIP" :
430 event == OC_EV_MS_NOT_PRIMARY ? "NOT PRIMARY" :
431 event == OC_EV_MS_PRIMARY_RESTORED ? "PRIMARY RESTORED" :
432 event == OC_EV_MS_EVICTED ? "EVICTED" : "NO QUORUM MEMBERSHIP");
433 if (ccm_have_quorum(event)) {
434 fprintf(stdout, "1\n");
435 } else {
436 fprintf(stdout, "0\n");
437 }
438
439 } else if (command == 'e') {
440 crm_debug("Searching %d members for our birth", oc->m_n_member);
441 }
442 for (lpc = 0; lpc < node_list_size; lpc++) {
443 if (command == 'p') {
444 fprintf(stdout, "%s ", oc->m_array[oc->m_memb_idx + lpc].node_uname);
445
446 } else if (command == 'e') {
447 int (*ccm_api_is_my_nodeid) (const oc_ev_t * token, const oc_node_t * node) =
448 find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_is_my_nodeid", 1);
449 if ((*ccm_api_is_my_nodeid) (ccm_token, &(oc->m_array[lpc]))) {
450 crm_debug("MATCH: nodeid=%d, uname=%s, born=%d",
451 oc->m_array[oc->m_memb_idx + lpc].node_id,
452 oc->m_array[oc->m_memb_idx + lpc].node_uname,
453 oc->m_array[oc->m_memb_idx + lpc].node_born_on);
454 fprintf(stdout, "%d\n", oc->m_array[oc->m_memb_idx + lpc].node_born_on);
455 }
456 }
457 }
458
459 (*ccm_api_callback_done) (cookie);
460
461 if (command == 'p') {
462 fprintf(stdout, "\n");
463 }
464 fflush(stdout);
465 crm_exit(pcmk_ok);
466 }
467
468 static gboolean
469 ccm_age_connect(int *ccm_fd)
470 {
471 gboolean did_fail = FALSE;
472 int ret = 0;
473
474 int (*ccm_api_register) (oc_ev_t ** token) =
475 find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_register", 1);
476
477 int (*ccm_api_set_callback) (const oc_ev_t * token,
478 oc_ev_class_t class,
479 oc_ev_callback_t * fn,
480 oc_ev_callback_t ** prev_fn) =
481 find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_set_callback", 1);
482
483 void (*ccm_api_special) (const oc_ev_t *, oc_ev_class_t, int) =
484 find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_special", 1);
485 int (*ccm_api_activate) (const oc_ev_t * token, int *fd) =
486 find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_activate", 1);
487
488 crm_debug("Registering with CCM");
489 ret = (*ccm_api_register) (&ccm_token);
490 if (ret != 0) {
491 crm_info("CCM registration failed: %d", ret);
492 did_fail = TRUE;
493 }
494
495 if (did_fail == FALSE) {
496 crm_debug("Setting up CCM callbacks");
497 ret = (*ccm_api_set_callback) (ccm_token, OC_EV_MEMB_CLASS, ccm_age_callback, NULL);
498 if (ret != 0) {
499 crm_warn("CCM callback not set: %d", ret);
500 did_fail = TRUE;
501 }
502 }
503 if (did_fail == FALSE) {
504 (*ccm_api_special) (ccm_token, OC_EV_MEMB_CLASS, 0 );
505
506 crm_debug("Activating CCM token");
507 ret = (*ccm_api_activate) (ccm_token, ccm_fd);
508 if (ret != 0) {
509 crm_warn("CCM Activation failed: %d", ret);
510 did_fail = TRUE;
511 }
512 }
513
514 return !did_fail;
515 }
516
517 static gboolean
518 try_heartbeat(int command, enum cluster_type_e stack)
519 {
520 crm_debug("Attempting to process %c command", command);
521
522 if (command == 'i') {
523 if (read_local_hb_uuid()) {
524 crm_exit(pcmk_ok);
525 }
526
527 } else if (command == 'R') {
528 if (tools_remove_node_cache(target_uname, CRM_SYSTEM_CRMD)) {
529 crm_err("Failed to connect to "CRM_SYSTEM_CRMD" to remove node '%s'", target_uname);
530 crm_exit(pcmk_err_generic);
531 }
532 crm_exit(pcmk_ok);
533
534 } else if (ccm_age_connect(&ccm_fd)) {
535 int rc = 0;
536 fd_set rset;
537 int (*ccm_api_handle_event) (const oc_ev_t * token) =
538 find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_handle_event", 1);
539
540 while (1) {
541
542 sleep(1);
543 FD_ZERO(&rset);
544 FD_SET(ccm_fd, &rset);
545
546 errno = 0;
547 rc = select(ccm_fd + 1, &rset, NULL, NULL, NULL);
548
549 if (rc > 0 && (*ccm_api_handle_event) (ccm_token) != 0) {
550 crm_err("oc_ev_handle_event failed");
551 return FALSE;
552
553 } else if (rc < 0 && errno != EINTR) {
554 crm_perror(LOG_ERR, "select failed: %d", rc);
555 return FALSE;
556 }
557 }
558 }
559 return FALSE;
560 }
561 #endif
562
563 #if SUPPORT_CMAN
564 # include <libcman.h>
565 # define MAX_NODES 256
566 static bool valid_cman_name(const char *name, uint32_t nodeid)
567 {
568 bool rc = TRUE;
569
570
571 char *fakename = crm_strdup_printf("Node%d", nodeid);
572
573 if(crm_str_eq(fakename, name, TRUE)) {
574 rc = FALSE;
575 crm_notice("Ignoring inferred name from cman: %s", fakename);
576 }
577 free(fakename);
578 return rc;
579 }
580
581 static gboolean
582 try_cman(int command, enum cluster_type_e stack)
583 {
584
585 int rc = -1, lpc = 0, node_count = 0;
586 cman_node_t node;
587 cman_cluster_t cluster;
588 cman_handle_t cman_handle = NULL;
589 cman_node_t cman_nodes[MAX_NODES];
590
591 memset(&cluster, 0, sizeof(cluster));
592
593 cman_handle = cman_init(NULL);
594 if (cman_handle == NULL || cman_is_active(cman_handle) == FALSE) {
595 crm_info("Couldn't connect to cman");
596 return FALSE;
597 }
598
599 switch (command) {
600 case 'R':
601 try_pacemaker(command, stack);
602 break;
603
604 case 'e':
605
606 fprintf(stdout, "1\n");
607 break;
608
609 case 'q':
610 fprintf(stdout, "%d\n", cman_is_quorate(cman_handle));
611 break;
612
613 case 'l':
614 case 'p':
615 memset(cman_nodes, 0, MAX_NODES * sizeof(cman_node_t));
616 rc = cman_get_nodes(cman_handle, MAX_NODES, &node_count, cman_nodes);
617 if (rc != 0) {
618 fprintf(stderr, "Couldn't query cman node list: %d %d", rc, errno);
619 goto cman_bail;
620 }
621
622 for (lpc = 0; lpc < node_count; lpc++) {
623 if(valid_cman_name(cman_nodes[lpc].cn_name, cman_nodes[lpc].cn_nodeid) == FALSE) {
624
625 printf("%u ", cman_nodes[lpc].cn_nodeid);
626
627 } if (command == 'l') {
628 printf("%s ", cman_nodes[lpc].cn_name);
629
630 } else if (cman_nodes[lpc].cn_nodeid != 0 && cman_nodes[lpc].cn_member) {
631
632 printf("%s ", cman_nodes[lpc].cn_name);
633 }
634 }
635 printf("\n");
636 break;
637
638 case 'i':
639 memset(&node, 0, sizeof(cman_node_t));
640 rc = cman_get_node(cman_handle, CMAN_NODEID_US, &node);
641 if (rc != 0) {
642 fprintf(stderr, "Couldn't query cman node id: %d %d", rc, errno);
643 goto cman_bail;
644 }
645 fprintf(stdout, "%u\n", node.cn_nodeid);
646 break;
647
648 default:
649 fprintf(stderr, "Unknown option '%c'\n", command);
650 crm_help('?', EX_USAGE);
651 }
652 cman_finish(cman_handle);
653 crm_exit(pcmk_ok);
654
655 cman_bail:
656 cman_finish(cman_handle);
657 return crm_exit(EINVAL);
658 }
659 #endif
660
661 #if HAVE_CONFDB
662 static void
663 ais_membership_destroy(gpointer user_data)
664 {
665 crm_err("AIS connection terminated");
666 ais_fd_sync = -1;
667 crm_exit(ENOTCONN);
668 }
669
670 static gint
671 member_sort(gconstpointer a, gconstpointer b)
672 {
673 const crm_node_t *node_a = a;
674 const crm_node_t *node_b = b;
675
676 return strcmp(node_a->uname, node_b->uname);
677 }
678
679 static void
680 crm_add_member(gpointer key, gpointer value, gpointer user_data)
681 {
682 GList **list = user_data;
683 crm_node_t *node = value;
684
685 if (node->uname != NULL) {
686 *list = g_list_insert_sorted(*list, node, member_sort);
687 }
688 }
689
690 static void
691 ais_membership_dispatch(cpg_handle_t handle,
692 const struct cpg_name *groupName,
693 uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
694 {
695 uint32_t kind = 0;
696 const char *from = NULL;
697 char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from);
698
699 switch (kind) {
700 case crm_class_members:
701 case crm_class_notify:
702 case crm_class_quorum:
703 break;
704 default:
705 free(data);
706 return;
707
708 break;
709 }
710
711 if (command == 'q') {
712 if (crm_have_quorum) {
713 fprintf(stdout, "1\n");
714 } else {
715 fprintf(stdout, "0\n");
716 }
717
718 } else if (command == 'l') {
719 GList *nodes = NULL;
720 GListPtr lpc = NULL;
721
722 g_hash_table_foreach(crm_peer_cache, crm_add_member, &nodes);
723 for (lpc = nodes; lpc != NULL; lpc = lpc->next) {
724 crm_node_t *node = (crm_node_t *) lpc->data;
725
726 fprintf(stdout, "%u %s %s\n", node->id, node->uname, node->state);
727 }
728 fprintf(stdout, "\n");
729
730 } else if (command == 'p') {
731 GList *nodes = NULL;
732 GListPtr lpc = NULL;
733
734 g_hash_table_foreach(crm_peer_cache, crm_add_member, &nodes);
735 for (lpc = nodes; lpc != NULL; lpc = lpc->next) {
736 crm_node_t *node = (crm_node_t *) lpc->data;
737
738 if (node->uname && safe_str_eq(node->state, CRM_NODE_MEMBER)) {
739 fprintf(stdout, "%s ", node->uname);
740 }
741 }
742 fprintf(stdout, "\n");
743 }
744
745 free(data);
746 crm_exit(pcmk_ok);
747
748 return;
749 }
750 #endif
751
752 #ifdef SUPPORT_CS_QUORUM
753 # include <corosync/quorum.h>
754 # include <corosync/cpg.h>
755
756 static gboolean
757 try_corosync(int command, enum cluster_type_e stack)
758 {
759 int rc = 0;
760 int quorate = 0;
761 uint32_t quorum_type = 0;
762 unsigned int nodeid = 0;
763 cpg_handle_t c_handle = 0;
764 quorum_handle_t q_handle = 0;
765
766 switch (command) {
767 case 'q':
768
769 rc = quorum_initialize(&q_handle, NULL, &quorum_type);
770 if (rc != CS_OK) {
771 crm_err("Could not connect to the Quorum API: %d", rc);
772 return FALSE;
773 }
774
775 rc = quorum_getquorate(q_handle, &quorate);
776 if (rc != CS_OK) {
777 crm_err("Could not obtain the current Quorum API state: %d", rc);
778 return FALSE;
779 }
780
781 if (quorate) {
782 fprintf(stdout, "1\n");
783 } else {
784 fprintf(stdout, "0\n");
785 }
786 quorum_finalize(q_handle);
787 crm_exit(pcmk_ok);
788
789 case 'i':
790
791 rc = cpg_initialize(&c_handle, NULL);
792 if (rc != CS_OK) {
793 crm_err("Could not connect to the Cluster Process Group API: %d", rc);
794 return FALSE;
795 }
796
797 rc = cpg_local_get(c_handle, &nodeid);
798 if (rc != CS_OK) {
799 crm_err("Could not get local node id from the CPG API");
800 return FALSE;
801 }
802
803 fprintf(stdout, "%u\n", nodeid);
804 cpg_finalize(c_handle);
805 crm_exit(pcmk_ok);
806
807 default:
808 try_pacemaker(command, stack);
809 break;
810 }
811 return FALSE;
812 }
813 #endif
814
815 #if HAVE_CONFDB
816 static gboolean
817 try_openais(int command, enum cluster_type_e stack)
818 {
819 static crm_cluster_t cluster;
820
821 cluster.destroy = ais_membership_destroy;
822 cluster.cpg.cpg_deliver_fn = ais_membership_dispatch;
823 cluster.cpg.cpg_confchg_fn = NULL;
824
825 if (init_cs_connection_once(&cluster)) {
826
827 GMainLoop *amainloop = NULL;
828
829 switch (command) {
830 case 'R':
831 send_cluster_text(crm_class_rmpeer, target_uname, TRUE, NULL, crm_msg_ais);
832 cib_remove_node(0, target_uname);
833 crm_exit(pcmk_ok);
834
835 case 'e':
836
837 fprintf(stdout, "1\n");
838 crm_exit(pcmk_ok);
839
840 case 'q':
841 send_cluster_text(crm_class_quorum, NULL, TRUE, NULL, crm_msg_ais);
842 break;
843
844 case 'l':
845 case 'p':
846 crm_info("Requesting the list of configured nodes");
847 send_cluster_text(crm_class_members, __FUNCTION__, TRUE, NULL, crm_msg_ais);
848 break;
849
850 case 'i':
851 printf("%u\n", cluster.nodeid);
852 crm_exit(pcmk_ok);
853
854 default:
855 fprintf(stderr, "Unknown option '%c'\n", command);
856 crm_help('?', EX_USAGE);
857 }
858 amainloop = g_main_new(FALSE);
859 g_main_run(amainloop);
860 }
861 return FALSE;
862 }
863 #endif
864
865 int set_cluster_type(enum cluster_type_e type);
866
867 int
868 main(int argc, char **argv)
869 {
870 int flag = 0;
871 int argerr = 0;
872 uint32_t nodeid = 0;
873 gboolean force_flag = FALSE;
874 gboolean dangerous_cmd = FALSE;
875 enum cluster_type_e try_stack = pcmk_cluster_unknown;
876
877 int option_index = 0;
878
879 crm_peer_init();
880 crm_log_cli_init("crm_node");
881 crm_set_options(NULL, "command [options]", long_options,
882 "Tool for displaying low-level node information");
883
884 while (flag >= 0) {
885 flag = crm_get_option(argc, argv, &option_index);
886 switch (flag) {
887 case -1:
888 break;
889 case 'V':
890 crm_bump_log_level(argc, argv);
891 break;
892 case '$':
893 case '?':
894 crm_help(flag, EX_OK);
895 break;
896 case 'Q':
897 do_quiet = TRUE;
898 break;
899 case 'H':
900 set_cluster_type(pcmk_cluster_heartbeat);
901 break;
902 case 'A':
903 set_cluster_type(pcmk_cluster_classic_ais);
904 break;
905 case 'C':
906 set_cluster_type(pcmk_cluster_corosync);
907 break;
908 case 'c':
909 set_cluster_type(pcmk_cluster_cman);
910 break;
911 case 'f':
912 force_flag = TRUE;
913 break;
914 case 'R':
915 command = flag;
916 dangerous_cmd = TRUE;
917 target_uname = optarg;
918 break;
919 case 'N':
920 command = flag;
921 nodeid = crm_parse_int(optarg, NULL);
922 break;
923 case 'p':
924 case 'e':
925 case 'q':
926 case 'i':
927 case 'l':
928 case 'n':
929 command = flag;
930 break;
931 default:
932 ++argerr;
933 break;
934 }
935 }
936
937 if (optind > argc) {
938 ++argerr;
939 }
940
941 if (argerr) {
942 crm_help('?', EX_USAGE);
943 }
944
945 if (command == 'n') {
946 const char *name = getenv("OCF_RESKEY_" CRM_META "_" XML_LRM_ATTR_TARGET);
947 if(name == NULL) {
948 name = get_local_node_name();
949 }
950 fprintf(stdout, "%s\n", name);
951 crm_exit(pcmk_ok);
952
953 } else if (command == 'N') {
954 fprintf(stdout, "%s\n", get_node_name(nodeid));
955 crm_exit(pcmk_ok);
956 }
957
958 if (dangerous_cmd && force_flag == FALSE) {
959 fprintf(stderr, "The supplied command is considered dangerous."
960 " To prevent accidental destruction of the cluster,"
961 " the --force flag is required in order to proceed.\n");
962 fflush(stderr);
963 crm_exit(EINVAL);
964 }
965
966 try_stack = get_cluster_type();
967 crm_debug("Attempting to process -%c command for cluster type: %s", command,
968 name_for_cluster_type(try_stack));
969
970 #if SUPPORT_CMAN
971 if (try_stack == pcmk_cluster_cman) {
972 try_cman(command, try_stack);
973 }
974 #endif
975
976 #ifdef SUPPORT_CS_QUORUM
977 if (try_stack == pcmk_cluster_corosync) {
978 try_corosync(command, try_stack);
979 }
980 #endif
981
982 #if HAVE_CONFDB
983
984 if (try_stack == pcmk_cluster_classic_ais) {
985 try_openais(command, try_stack);
986 }
987 #endif
988
989 #if SUPPORT_HEARTBEAT
990 if (try_stack == pcmk_cluster_heartbeat) {
991 try_heartbeat(command, try_stack);
992 }
993 #endif
994
995 try_pacemaker(command, try_stack);
996
997 return (1);
998 }