root/tools/crm_node.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cib_remove_node
  2. tools_remove_node_cache
  3. compare_node_uname
  4. node_mcp_dispatch
  5. node_mcp_destroy
  6. try_pacemaker
  7. read_local_hb_uuid
  8. ccm_age_callback
  9. ccm_age_connect
  10. try_heartbeat
  11. valid_cman_name
  12. try_cman
  13. ais_membership_destroy
  14. member_sort
  15. crm_add_member
  16. ais_membership_dispatch
  17. try_corosync
  18. try_openais
  19. main

   1 /* 
   2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
   3  * 
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) any later version.
   8  * 
   9  * This software is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * General Public License for more details.
  13  * 
  14  * You should have received a copy of the GNU General Public
  15  * License along with this library; if not, write to the Free Software
  16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  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>             /* for basename() */
  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 /* *INDENT-OFF* */
  49 static struct crm_option long_options[] = {
  50     /* Top-level Options */
  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 /* *INDENT-ON* */
  87 
  88 static int
  89 cib_remove_node(uint32_t id, const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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         /* Argument was not a nodeid */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 289 {
 290     crm_exit(ENOTCONN);
 291 }
 292 
 293 static gboolean
 294 try_pacemaker(int command, enum cluster_type_e stack)
     /* [previous][next][first][last][top][bottom][index][help] */
 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         /* Nothing to do for them */
 303         return FALSE;
 304     }
 305 
 306     switch (command) {
 307         case 'e':
 308             /* Age only applies to heartbeat clusters */
 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             /* Go to pacemakerd */
 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                     /* Sending anything will get us a list of nodes */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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     /* see how big the file is */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /*don't care */ );
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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) 
     /* [previous][next][first][last][top][bottom][index][help] */
 567 {
 568     bool rc = TRUE;
 569 
 570     /* Yes, %d, because that's what CMAN does */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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             /* Age makes no sense (yet?) in a cman cluster */
 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                     /* The name was invented, but we need to print something, make it the id instead */
 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                     /* Never allow node ID 0 to be considered a member #315711 */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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             /* Go direct to the Quorum API */
 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             /* Go direct to the CPG API */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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                 /* Age makes no sense (yet) in an AIS cluster */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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     /* Only an option if we're using the plugins */
 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 }

/* [previous][next][first][last][top][bottom][index][help] */