root/tools/crmadmin.c

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

DEFINITIONS

This source file includes following definitions.
  1. main
  2. do_work
  3. crmadmin_ipc_connection_destroy
  4. do_init
  5. validate_crm_message
  6. admin_msg_callback
  7. admin_message_timeout
  8. is_node_online
  9. do_find_node_list

   1 
   2 /* 
   3  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
   4  * 
   5  * This program is free software; you can redistribute it and/or
   6  * modify it under the terms of the GNU General Public
   7  * License as published by the Free Software Foundation; either
   8  * version 2 of the License, or (at your option) any later version.
   9  * 
  10  * This software is distributed in the hope that it will be useful,
  11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13  * General Public License for more details.
  14  * 
  15  * You should have received a copy of the GNU General Public
  16  * License along with this library; if not, write to the Free Software
  17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  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 /* *INDENT-OFF* */
  95 static struct crm_option long_options[] = {
  96     /* Top-level Options */
  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     /* daemon options */
 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 /* *INDENT-ON* */
 125 
 126 int
 127 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 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             /* wait for the reply by creating a mainloop and running it until
 230              * the callbacks are invoked...
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 254 {
 255     int ret = 1;
 256 
 257     /* construct the request */
 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         /* tell the local node to initiate an election */
 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;                /* no return message */
 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         /* tell dest_node to initiate the shutdown procedure
 323          *
 324          * if dest_node is NULL, the request will be sent to the
 325          *   local node
 326          */
 327         sys_to = CRM_SYSTEM_CRMD;
 328         crm_xml_add(msg_options, XML_ATTR_TIMEOUT, "0");
 329 
 330         ret = 0;                /* no return message */
 331 
 332     } else if (DO_DEBUG == debug_inc) {
 333         /* tell dest_node to increase its debug level
 334          *
 335          * if dest_node is NULL, the request will be sent to the
 336          *   local node
 337          */
 338         sys_to = CRM_SYSTEM_CRMD;
 339         crmd_operation = CRM_OP_DEBUG_UP;
 340 
 341         ret = 0;                /* no return message */
 342 
 343     } else if (DO_DEBUG == debug_dec) {
 344         /* tell dest_node to increase its debug level
 345          *
 346          * if dest_node is NULL, the request will be sent to the
 347          *   local node
 348          */
 349         sys_to = CRM_SYSTEM_CRMD;
 350         crmd_operation = CRM_OP_DEBUG_DOWN;
 351 
 352         ret = 0;                /* no return message */
 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 /* send it */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

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