root/cib/main.c

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

DEFINITIONS

This source file includes following definitions.
  1. cib_enable_writes
  2. log_cib_client
  3. main
  4. cib_cleanup
  5. ccm_connection_destroy
  6. ccm_connect
  7. cib_cs_dispatch
  8. cib_cs_destroy
  9. cib_peer_update_callback
  10. cib_ha_connection_destroy
  11. cib_init
  12. startCib

   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 <sys/stat.h>
  25 #include <unistd.h>
  26 #include <sys/utsname.h>
  27 
  28 #include <stdlib.h>
  29 #include <errno.h>
  30 #include <fcntl.h>
  31 
  32 #include <crm/crm.h>
  33 #include <crm/cib/internal.h>
  34 #include <crm/msg_xml.h>
  35 #include <crm/cluster/internal.h>
  36 
  37 #include <crm/common/xml.h>
  38 
  39 #include <crm/common/mainloop.h>
  40 
  41 #include <cibio.h>
  42 #include <callbacks.h>
  43 #include <pwd.h>
  44 #include <grp.h>
  45 #include "common.h"
  46 
  47 #if HAVE_LIBXML2
  48 #  include <libxml/parser.h>
  49 #endif
  50 
  51 #ifdef HAVE_GETOPT_H
  52 #  include <getopt.h>
  53 #endif
  54 
  55 #if HAVE_BZLIB_H
  56 #  include <bzlib.h>
  57 #endif
  58 
  59 extern int init_remote_listener(int port, gboolean encrypted);
  60 gboolean cib_shutdown_flag = FALSE;
  61 int cib_status = pcmk_ok;
  62 
  63 crm_cluster_t crm_cluster;
  64 
  65 #if SUPPORT_HEARTBEAT
  66 oc_ev_t *cib_ev_token;
  67 ll_cluster_t *hb_conn = NULL;
  68 extern void oc_ev_special(const oc_ev_t *, oc_ev_class_t, int);
  69 gboolean cib_register_ha(ll_cluster_t * hb_cluster, const char *client_name);
  70 #else
  71 void *hb_conn = NULL;
  72 #endif
  73 
  74 GMainLoop *mainloop = NULL;
  75 const char *cib_root = NULL;
  76 char *cib_our_uname = NULL;
  77 gboolean preserve_status = FALSE;
  78 
  79 /* volatile because it may be changed in a signal handler */
  80 volatile gboolean cib_writes_enabled = TRUE;
  81 
  82 int remote_fd = 0;
  83 int remote_tls_fd = 0;
  84 
  85 int cib_init(void);
  86 void cib_shutdown(int nsig);
  87 gboolean startCib(const char *filename);
  88 extern int write_cib_contents(gpointer p);
  89 
  90 GHashTable *config_hash = NULL;
  91 GHashTable *local_notify_queue = NULL;
  92 
  93 char *channel1 = NULL;
  94 char *channel2 = NULL;
  95 char *channel3 = NULL;
  96 char *channel4 = NULL;
  97 char *channel5 = NULL;
  98 
  99 #define OPTARGS "maswr:V?"
 100 void cib_cleanup(void);
 101 
 102 static void
 103 cib_enable_writes(int nsig)
     /* [previous][next][first][last][top][bottom][index][help] */
 104 {
 105     crm_info("(Re)enabling disk writes");
 106     cib_writes_enabled = TRUE;
 107 }
 108 
 109 static void
 110 log_cib_client(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 111 {
 112     crm_info("Client %s", crm_client_name(value));
 113 }
 114 
 115 /* *INDENT-OFF* */
 116 static struct crm_option long_options[] = {
 117     /* Top-level Options */
 118     {"help",    0, 0, '?', "\tThis text"},
 119     {"verbose", 0, 0, 'V', "\tIncrease debug output"},
 120 
 121     {"per-action-cib", 0, 0, 'a', "\tAdvanced use only"},
 122     {"stand-alone",    0, 0, 's', "\tAdvanced use only"},
 123     {"disk-writes",    0, 0, 'w', "\tAdvanced use only"},
 124     {"cib-root",       1, 0, 'r', "\tAdvanced use only"},
 125 
 126     {0, 0, 0, 0}
 127 };
 128 /* *INDENT-ON* */
 129 
 130 int
 131 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 132 {
 133     int flag;
 134     int rc = 0;
 135     int index = 0;
 136     int argerr = 0;
 137     struct passwd *pwentry = NULL;
 138 
 139     crm_log_preinit(NULL, argc, argv);
 140     crm_set_options(NULL, "[options]",
 141                     long_options, "Daemon for storing and replicating the cluster configuration");
 142 
 143     crm_peer_init();
 144 
 145     mainloop_add_signal(SIGTERM, cib_shutdown);
 146     mainloop_add_signal(SIGPIPE, cib_enable_writes);
 147 
 148     cib_writer = mainloop_add_trigger(G_PRIORITY_LOW, write_cib_contents, NULL);
 149 
 150     while (1) {
 151         flag = crm_get_option(argc, argv, &index);
 152         if (flag == -1)
 153             break;
 154 
 155         switch (flag) {
 156             case 'V':
 157                 crm_bump_log_level(argc, argv);
 158                 break;
 159             case 's':
 160                 stand_alone = TRUE;
 161                 preserve_status = TRUE;
 162                 cib_writes_enabled = FALSE;
 163 
 164                 pwentry = getpwnam(CRM_DAEMON_USER);
 165                 CRM_CHECK(pwentry != NULL,
 166                           crm_perror(LOG_ERR, "Invalid uid (%s) specified", CRM_DAEMON_USER);
 167                           return 100);
 168 
 169                 rc = setgid(pwentry->pw_gid);
 170                 if (rc < 0) {
 171                     crm_perror(LOG_ERR, "Could not set group to %d", pwentry->pw_gid);
 172                     return 100;
 173                 }
 174 
 175                 rc = initgroups(CRM_DAEMON_GROUP, pwentry->pw_gid);
 176                 if (rc < 0) {
 177                     crm_perror(LOG_ERR, "Could not setup groups for user %d", pwentry->pw_uid);
 178                     return 100;
 179                 }
 180 
 181                 rc = setuid(pwentry->pw_uid);
 182                 if (rc < 0) {
 183                     crm_perror(LOG_ERR, "Could not set user to %d", pwentry->pw_uid);
 184                     return 100;
 185                 }
 186                 break;
 187             case '?':          /* Help message */
 188                 crm_help(flag, EX_OK);
 189                 break;
 190             case 'w':
 191                 cib_writes_enabled = TRUE;
 192                 break;
 193             case 'r':
 194                 cib_root = optarg;
 195                 break;
 196             case 'm':
 197                 cib_metadata();
 198                 return 0;
 199             default:
 200                 ++argerr;
 201                 break;
 202         }
 203     }
 204     if (argc - optind == 1 && safe_str_eq("metadata", argv[optind])) {
 205         cib_metadata();
 206         return 0;
 207     }
 208 
 209     if (optind > argc) {
 210         ++argerr;
 211     }
 212 
 213     if (argerr) {
 214         crm_help('?', EX_USAGE);
 215     }
 216 
 217     crm_log_init(NULL, LOG_INFO, TRUE, FALSE, argc, argv, FALSE);
 218 
 219     if (cib_root == NULL) {
 220         if ((g_file_test(CRM_CONFIG_DIR "/cib.xml", G_FILE_TEST_EXISTS) == FALSE)
 221             && (g_file_test(CRM_LEGACY_CONFIG_DIR "/cib.xml", G_FILE_TEST_EXISTS) == TRUE)) {
 222 
 223             crm_notice("Using legacy config location: " CRM_LEGACY_CONFIG_DIR);
 224             cib_root = CRM_LEGACY_CONFIG_DIR;
 225 
 226         } else {
 227             cib_root = CRM_CONFIG_DIR;
 228         }
 229     } else {
 230         crm_notice("Using custom config location: %s", cib_root);
 231     }
 232 
 233     if (crm_is_writable(cib_root, NULL, CRM_DAEMON_USER, CRM_DAEMON_GROUP, FALSE) == FALSE) {
 234         crm_err("Bad permissions on %s. Terminating", cib_root);
 235         fprintf(stderr, "ERROR: Bad permissions on %s. See logs for details\n", cib_root);
 236         fflush(stderr);
 237         return 100;
 238     }
 239 
 240     /* read local config file */
 241     rc = cib_init();
 242 
 243     CRM_CHECK(crm_hash_table_size(client_connections) == 0,
 244               crm_warn("Not all clients gone at exit"));
 245     g_hash_table_foreach(client_connections, log_cib_client, NULL);
 246     cib_cleanup();
 247 
 248 #if SUPPORT_HEARTBEAT
 249     if (hb_conn) {
 250         hb_conn->llc_ops->delete(hb_conn);
 251     }
 252 #endif
 253 
 254     crm_info("Done");
 255     return rc;
 256 }
 257 
 258 void
 259 cib_cleanup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 260 {
 261     crm_peer_destroy();
 262     if (local_notify_queue) {
 263         g_hash_table_destroy(local_notify_queue);
 264     }
 265     crm_client_cleanup();
 266     g_hash_table_destroy(config_hash);
 267     free(cib_our_uname);
 268     free(channel1);
 269     free(channel2);
 270     free(channel3);
 271     free(channel4);
 272     free(channel5);
 273 }
 274 
 275 unsigned long cib_num_ops = 0;
 276 const char *cib_stat_interval = "10min";
 277 unsigned long cib_num_local = 0, cib_num_updates = 0, cib_num_fail = 0;
 278 unsigned long cib_bad_connects = 0, cib_num_timeouts = 0;
 279 
 280 #if SUPPORT_HEARTBEAT
 281 gboolean ccm_connect(void);
 282 
 283 static void
 284 ccm_connection_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 285 {
 286     crm_err("CCM connection failed... blocking while we reconnect");
 287     CRM_ASSERT(ccm_connect());
 288     return;
 289 }
 290 
 291 static void *ccm_library = NULL;
 292 
 293 gboolean
 294 ccm_connect(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 295 {
 296     gboolean did_fail = TRUE;
 297     int num_ccm_fails = 0;
 298     int max_ccm_fails = 30;
 299     int ret;
 300     int cib_ev_fd;
 301 
 302     int (*ccm_api_register) (oc_ev_t ** token) =
 303         find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_register", 1);
 304 
 305     int (*ccm_api_set_callback) (const oc_ev_t * token,
 306                                  oc_ev_class_t class,
 307                                  oc_ev_callback_t * fn,
 308                                  oc_ev_callback_t ** prev_fn) =
 309         find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_set_callback", 1);
 310 
 311     void (*ccm_api_special) (const oc_ev_t *, oc_ev_class_t, int) =
 312         find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_special", 1);
 313     int (*ccm_api_activate) (const oc_ev_t * token, int *fd) =
 314         find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_activate", 1);
 315     int (*ccm_api_unregister) (oc_ev_t * token) =
 316         find_library_function(&ccm_library, CCM_LIBRARY, "oc_ev_unregister", 1);
 317 
 318     static struct mainloop_fd_callbacks ccm_fd_callbacks = {
 319         .dispatch = cib_ccm_dispatch,
 320         .destroy = ccm_connection_destroy,
 321     };
 322 
 323     while (did_fail) {
 324         did_fail = FALSE;
 325         crm_info("Registering with CCM...");
 326         ret = (*ccm_api_register) (&cib_ev_token);
 327         if (ret != 0) {
 328             did_fail = TRUE;
 329         }
 330 
 331         if (did_fail == FALSE) {
 332             crm_trace("Setting up CCM callbacks");
 333             ret = (*ccm_api_set_callback) (cib_ev_token, OC_EV_MEMB_CLASS,
 334                                            cib_ccm_msg_callback, NULL);
 335             if (ret != 0) {
 336                 crm_warn("CCM callback not set");
 337                 did_fail = TRUE;
 338             }
 339         }
 340         if (did_fail == FALSE) {
 341             (*ccm_api_special) (cib_ev_token, OC_EV_MEMB_CLASS, 0);
 342 
 343             crm_trace("Activating CCM token");
 344             ret = (*ccm_api_activate) (cib_ev_token, &cib_ev_fd);
 345             if (ret != 0) {
 346                 crm_warn("CCM Activation failed");
 347                 did_fail = TRUE;
 348             }
 349         }
 350 
 351         if (did_fail) {
 352             num_ccm_fails++;
 353             (*ccm_api_unregister) (cib_ev_token);
 354 
 355             if (num_ccm_fails < max_ccm_fails) {
 356                 crm_warn("CCM Connection failed %d times (%d max)", num_ccm_fails, max_ccm_fails);
 357                 sleep(3);
 358 
 359             } else {
 360                 crm_err("CCM Activation failed %d (max) times", num_ccm_fails);
 361                 return FALSE;
 362             }
 363         }
 364     }
 365 
 366     crm_debug("CCM Activation passed... all set to go!");
 367     mainloop_add_fd("heartbeat-ccm", G_PRIORITY_MEDIUM, cib_ev_fd, cib_ev_token, &ccm_fd_callbacks);
 368 
 369     return TRUE;
 370 }
 371 #endif
 372 
 373 #if SUPPORT_COROSYNC
 374 static void
 375 cib_cs_dispatch(cpg_handle_t handle,
     /* [previous][next][first][last][top][bottom][index][help] */
 376                  const struct cpg_name *groupName,
 377                  uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
 378 {
 379     uint32_t kind = 0;
 380     xmlNode *xml = NULL;
 381     const char *from = NULL;
 382     char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from);
 383 
 384     if(data == NULL) {
 385         return;
 386     }
 387     if (kind == crm_class_cluster) {
 388         xml = string2xml(data);
 389         if (xml == NULL) {
 390             crm_err("Invalid XML: '%.120s'", data);
 391             free(data);
 392             return;
 393         }
 394         crm_xml_add(xml, F_ORIG, from);
 395         /* crm_xml_add_int(xml, F_SEQ, wrapper->id); */
 396         cib_peer_callback(xml, NULL);
 397     }
 398 
 399     free_xml(xml);
 400     free(data);
 401 }
 402 
 403 static void
 404 cib_cs_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 405 {
 406     if (cib_shutdown_flag) {
 407         crm_info("Corosync disconnection complete");
 408     } else {
 409         crm_err("Corosync connection lost!  Exiting.");
 410         terminate_cib(__FUNCTION__, -1);
 411     }
 412 }
 413 #endif
 414 
 415 static void
 416 cib_peer_update_callback(enum crm_status_type type, crm_node_t * node, const void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 417 {
 418     switch (type) {
 419         case crm_status_processes:
 420 #if !SUPPORT_PLUGIN
 421             if (cib_legacy_mode()
 422                 && is_not_set(node->processes, crm_get_cluster_proc())) {
 423 
 424                 uint32_t old = data? *(const uint32_t *)data : 0;
 425 
 426                 if ((node->processes ^ old) & crm_proc_cpg) {
 427                     crm_info("Attempting to disable legacy mode after %s left the cluster",
 428                              node->uname);
 429                     legacy_mode = FALSE;
 430                 }
 431             }
 432 #endif
 433             break;
 434 
 435         case crm_status_uname:
 436         case crm_status_rstate:
 437         case crm_status_nstate:
 438             if (cib_shutdown_flag && (crm_active_peers() < 2)
 439                 && crm_hash_table_size(client_connections) == 0) {
 440 
 441                 crm_info("No more peers");
 442                 terminate_cib(__FUNCTION__, 1);
 443             }
 444             break;
 445     }
 446 }
 447 
 448 #if SUPPORT_HEARTBEAT
 449 static void
 450 cib_ha_connection_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 451 {
 452     if (cib_shutdown_flag) {
 453         crm_info("Heartbeat disconnection complete... exiting");
 454         terminate_cib(__FUNCTION__, 0);
 455     } else {
 456         crm_err("Heartbeat connection lost!  Exiting.");
 457         terminate_cib(__FUNCTION__, -1);
 458     }
 459 }
 460 #endif
 461 
 462 int
 463 cib_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 464 {
 465     if (is_openais_cluster()) {
 466 #if SUPPORT_COROSYNC
 467         crm_cluster.destroy = cib_cs_destroy;
 468         crm_cluster.cpg.cpg_deliver_fn = cib_cs_dispatch;
 469         crm_cluster.cpg.cpg_confchg_fn = pcmk_cpg_membership;
 470 #endif
 471     } else if (is_heartbeat_cluster()) {
 472 #if SUPPORT_HEARTBEAT
 473         crm_cluster.hb_dispatch = cib_ha_peer_callback;
 474         crm_cluster.destroy = cib_ha_connection_destroy;
 475 #endif
 476     }
 477 
 478     config_hash = crm_str_table_new();
 479 
 480     if (startCib("cib.xml") == FALSE) {
 481         crm_crit("Cannot start CIB... terminating");
 482         crm_exit(ENODATA);
 483     }
 484 
 485     if (stand_alone == FALSE) {
 486         if (is_openais_cluster()) {
 487             crm_set_status_callback(&cib_peer_update_callback);
 488         }
 489 
 490         if (crm_cluster_connect(&crm_cluster) == FALSE) {
 491             crm_crit("Cannot sign in to the cluster... terminating");
 492             crm_exit(DAEMON_RESPAWN_STOP);
 493         }
 494         cib_our_uname = crm_cluster.uname;
 495 
 496 #if SUPPORT_HEARTBEAT
 497         if (is_heartbeat_cluster()) {
 498 
 499             gboolean was_error = FALSE;
 500 
 501             hb_conn = crm_cluster.hb_conn;
 502             if (was_error == FALSE) {
 503                 if (HA_OK !=
 504                     hb_conn->llc_ops->set_cstatus_callback(hb_conn, cib_client_status_callback,
 505                                                            hb_conn)) {
 506 
 507                     crm_err("Cannot set cstatus callback: %s", hb_conn->llc_ops->errmsg(hb_conn));
 508                     was_error = TRUE;
 509                 }
 510             }
 511 
 512             if (was_error == FALSE) {
 513                 was_error = (ccm_connect() == FALSE);
 514             }
 515 
 516             if (was_error == FALSE) {
 517                 /* Async get client status information in the cluster */
 518                 crm_info("Requesting the list of configured nodes");
 519                 hb_conn->llc_ops->client_status(hb_conn, NULL, CRM_SYSTEM_CIB, -1);
 520             }
 521         }
 522 #endif
 523 
 524     } else {
 525         cib_our_uname = strdup("localhost");
 526     }
 527 
 528     cib_ipc_servers_init(&ipcs_ro,
 529                          &ipcs_rw,
 530                          &ipcs_shm,
 531                          &ipc_ro_callbacks,
 532                          &ipc_rw_callbacks);
 533 
 534     if (stand_alone) {
 535         cib_is_master = TRUE;
 536     }
 537 
 538     /* Create the mainloop and run it... */
 539     mainloop = g_main_new(FALSE);
 540     crm_info("Starting %s mainloop", crm_system_name);
 541     g_main_run(mainloop);
 542 
 543     /* If main loop returned, clean up and exit. We disconnect in case
 544      * terminate_cib() was called with fast=1.
 545      */
 546     crm_cluster_disconnect(&crm_cluster);
 547     cib_ipc_servers_destroy(ipcs_ro, ipcs_rw, ipcs_shm);
 548 
 549     return crm_exit(pcmk_ok);
 550 }
 551 
 552 gboolean
 553 startCib(const char *filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 554 {
 555     gboolean active = FALSE;
 556     xmlNode *cib = readCibXmlFile(cib_root, filename, !preserve_status);
 557 
 558     CRM_ASSERT(cib != NULL);
 559 
 560     if (activateCibXml(cib, TRUE, "start") == 0) {
 561         int port = 0;
 562         const char *port_s = NULL;
 563 
 564         active = TRUE;
 565 
 566         cib_read_config(config_hash, cib);
 567 
 568         port_s = crm_element_value(cib, "remote-tls-port");
 569         if (port_s) {
 570             port = crm_parse_int(port_s, "0");
 571             remote_tls_fd = init_remote_listener(port, TRUE);
 572         }
 573 
 574         port_s = crm_element_value(cib, "remote-clear-port");
 575         if (port_s) {
 576             port = crm_parse_int(port_s, "0");
 577             remote_fd = init_remote_listener(port, FALSE);
 578         }
 579 
 580         crm_info("CIB Initialization completed successfully");
 581     }
 582 
 583     return active;
 584 }

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