root/mcp/corosync.c

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

DEFINITIONS

This source file includes following definitions.
  1. cfg_shutdown_callback
  2. pcmk_cfg_dispatch
  3. cfg_connection_destroy
  4. cluster_disconnect_cfg
  5. cluster_connect_cfg
  6. get_config_opt
  7. config_find_init
  8. config_find_next
  9. get_config_opt
  10. mcp_read_config

   1 /*
   2  * Copyright (C) 2010 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 #include <crm_internal.h>
  19 #include <pacemaker.h>
  20 
  21 #include <sys/utsname.h>
  22 #include <sys/stat.h>           /* for calls to stat() */
  23 #include <libgen.h>             /* For basename() and dirname() */
  24 
  25 #include <sys/types.h>
  26 #include <pwd.h>                /* For getpwname() */
  27 
  28 #include <corosync/hdb.h>
  29 #include <corosync/cfg.h>
  30 #include <corosync/cpg.h>
  31 #if HAVE_CONFDB
  32 #  include <corosync/confdb.h>
  33 #endif
  34 
  35 #include <crm/cluster/internal.h>
  36 #include <crm/common/mainloop.h>
  37 
  38 #if SUPPORT_CMAN
  39 #  include <libcman.h>
  40 #endif
  41 
  42 #if HAVE_CMAP
  43 #  include <corosync/cmap.h>
  44 #endif
  45 
  46 enum cluster_type_e stack = pcmk_cluster_unknown;
  47 static corosync_cfg_handle_t cfg_handle;
  48 
  49 /* =::=::=::= CFG - Shutdown stuff =::=::=::= */
  50 
  51 static void
  52 cfg_shutdown_callback(corosync_cfg_handle_t h, corosync_cfg_shutdown_flags_t flags)
     /* [previous][next][first][last][top][bottom][index][help] */
  53 {
  54     crm_info("Corosync wants to shut down: %s",
  55              (flags == COROSYNC_CFG_SHUTDOWN_FLAG_IMMEDIATE) ? "immediate" :
  56              (flags == COROSYNC_CFG_SHUTDOWN_FLAG_REGARDLESS) ? "forced" : "optional");
  57 
  58     /* Never allow corosync to shut down while we're running */
  59     corosync_cfg_replyto_shutdown(h, COROSYNC_CFG_SHUTDOWN_FLAG_NO);
  60 }
  61 
  62 static corosync_cfg_callbacks_t cfg_callbacks = {
  63     .corosync_cfg_shutdown_callback = cfg_shutdown_callback,
  64 };
  65 
  66 static int
  67 pcmk_cfg_dispatch(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
  68 {
  69     corosync_cfg_handle_t *handle = (corosync_cfg_handle_t *) user_data;
  70     cs_error_t rc = corosync_cfg_dispatch(*handle, CS_DISPATCH_ALL);
  71 
  72     if (rc != CS_OK) {
  73         return -1;
  74     }
  75     return 0;
  76 }
  77 
  78 static void
  79 cfg_connection_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
  80 {
  81     crm_err("Connection destroyed");
  82     cfg_handle = 0;
  83 
  84     pcmk_shutdown(SIGTERM);
  85 }
  86 
  87 gboolean
  88 cluster_disconnect_cfg(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90     if (cfg_handle) {
  91         corosync_cfg_finalize(cfg_handle);
  92         cfg_handle = 0;
  93     }
  94 
  95     pcmk_shutdown(SIGTERM);
  96     return TRUE;
  97 }
  98 
  99 #define cs_repeat(counter, max, code) do {              \
 100         code;                                           \
 101         if(rc == CS_ERR_TRY_AGAIN || rc == CS_ERR_QUEUE_FULL) {  \
 102             counter++;                                  \
 103             crm_debug("Retrying operation after %ds", counter); \
 104             sleep(counter);                             \
 105         } else {                                        \
 106             break;                                      \
 107         }                                               \
 108     } while(counter < max)
 109 
 110 gboolean
 111 cluster_connect_cfg(uint32_t * nodeid)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113     cs_error_t rc;
 114     int fd = 0, retries = 0;
 115 
 116     static struct mainloop_fd_callbacks cfg_fd_callbacks = {
 117         .dispatch = pcmk_cfg_dispatch,
 118         .destroy = cfg_connection_destroy,
 119     };
 120 
 121     cs_repeat(retries, 30, rc = corosync_cfg_initialize(&cfg_handle, &cfg_callbacks));
 122 
 123     if (rc != CS_OK) {
 124         crm_err("corosync cfg init error %d", rc);
 125         return FALSE;
 126     }
 127 
 128     rc = corosync_cfg_fd_get(cfg_handle, &fd);
 129     if (rc != CS_OK) {
 130         crm_err("corosync cfg fd_get error %d", rc);
 131         goto bail;
 132     }
 133 
 134     retries = 0;
 135     cs_repeat(retries, 30, rc = corosync_cfg_local_get(cfg_handle, nodeid));
 136 
 137     if (rc != CS_OK) {
 138         crm_err("corosync cfg local_get error %d", rc);
 139         goto bail;
 140     }
 141 
 142     crm_debug("Our nodeid: %d", *nodeid);
 143     mainloop_add_fd("corosync-cfg", G_PRIORITY_DEFAULT, fd, &cfg_handle, &cfg_fd_callbacks);
 144 
 145     return TRUE;
 146 
 147   bail:
 148     corosync_cfg_finalize(cfg_handle);
 149     return FALSE;
 150 }
 151 
 152 /* =::=::=::= Configuration =::=::=::= */
 153 #if HAVE_CONFDB
 154 static int
 155 get_config_opt(confdb_handle_t config,
     /* [previous][next][first][last][top][bottom][index][help] */
 156                hdb_handle_t object_handle, const char *key, char **value, const char *fallback)
 157 {
 158     size_t len = 0;
 159     char *env_key = NULL;
 160     const char *env_value = NULL;
 161     char buffer[256];
 162 
 163     if (*value) {
 164         free(*value);
 165         *value = NULL;
 166     }
 167 
 168     if (object_handle > 0) {
 169         if (CS_OK == confdb_key_get(config, object_handle, key, strlen(key), &buffer, &len)) {
 170             *value = strdup(buffer);
 171         }
 172     }
 173 
 174     if (*value) {
 175         crm_info("Found '%s' for option: %s", *value, key);
 176         return 0;
 177     }
 178 
 179     env_key = crm_concat("HA", key, '_');
 180     env_value = getenv(env_key);
 181     free(env_key);
 182 
 183     if (*value) {
 184         crm_info("Found '%s' in ENV for option: %s", *value, key);
 185         *value = strdup(env_value);
 186         return 0;
 187     }
 188 
 189     if (fallback) {
 190         crm_info("Defaulting to '%s' for option: %s", fallback, key);
 191         *value = strdup(fallback);
 192 
 193     } else {
 194         crm_info("No default for option: %s", key);
 195     }
 196 
 197     return -1;
 198 }
 199 
 200 static confdb_handle_t
 201 config_find_init(confdb_handle_t config)
     /* [previous][next][first][last][top][bottom][index][help] */
 202 {
 203     cs_error_t rc = CS_OK;
 204     confdb_handle_t local_handle = OBJECT_PARENT_HANDLE;
 205 
 206     rc = confdb_object_find_start(config, local_handle);
 207     if (rc == CS_OK) {
 208         return local_handle;
 209     } else {
 210         crm_err("Couldn't create search context: %d", rc);
 211     }
 212     return 0;
 213 }
 214 
 215 static hdb_handle_t
 216 config_find_next(confdb_handle_t config, const char *name, confdb_handle_t top_handle)
     /* [previous][next][first][last][top][bottom][index][help] */
 217 {
 218     cs_error_t rc = CS_OK;
 219     hdb_handle_t local_handle = 0;
 220 
 221     if (top_handle == 0) {
 222         crm_err("Couldn't search for %s: no valid context", name);
 223         return 0;
 224     }
 225 
 226     crm_trace("Searching for %s in " HDB_X_FORMAT, name, top_handle);
 227     rc = confdb_object_find(config, top_handle, name, strlen(name), &local_handle);
 228     if (rc != CS_OK) {
 229         crm_info("No additional configuration supplied for: %s", name);
 230         local_handle = 0;
 231     } else {
 232         crm_info("Processing additional %s options...", name);
 233     }
 234     return local_handle;
 235 }
 236 #else
 237 static int
 238 get_config_opt(uint64_t unused, cmap_handle_t object_handle, const char *key, char **value,
     /* [previous][next][first][last][top][bottom][index][help] */
 239                const char *fallback)
 240 {
 241     int rc = 0, retries = 0;
 242 
 243     cs_repeat(retries, 5, rc = cmap_get_string(object_handle, key, value));
 244     if (rc != CS_OK) {
 245         crm_trace("Search for %s failed %d, defaulting to %s", key, rc, fallback);
 246         if (fallback) {
 247             *value = strdup(fallback);
 248         } else {
 249             *value = NULL;
 250         }
 251     }
 252     crm_trace("%s: %s", key, *value);
 253     return rc;
 254 }
 255 
 256 #endif
 257 
 258 #if HAVE_CONFDB
 259 #  define KEY_PREFIX ""
 260 #elif HAVE_CMAP
 261 #  define KEY_PREFIX "logging."
 262 #endif
 263 
 264 gboolean
 265 mcp_read_config(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 266 {
 267     int rc = CS_OK;
 268     int retries = 0;
 269 
 270     const char *const_value = NULL;
 271 
 272 #if HAVE_CONFDB
 273     char *value = NULL;
 274     confdb_handle_t config = 0;
 275     confdb_handle_t top_handle = 0;
 276     hdb_handle_t local_handle;
 277     static confdb_callbacks_t callbacks = { };
 278 
 279     do {
 280         rc = confdb_initialize(&config, &callbacks);
 281         if (rc != CS_OK) {
 282             retries++;
 283             printf("confdb connection setup failed: %s.  Retrying in %ds\n", ais_error2text(rc), retries);
 284             crm_info("confdb connection setup failed: %s.  Retrying in %ds", ais_error2text(rc), retries);
 285             sleep(retries);
 286 
 287         } else {
 288             break;
 289         }
 290 
 291     } while (retries < 5);
 292 #elif HAVE_CMAP
 293     cmap_handle_t local_handle;
 294     uint64_t config = 0;
 295 
 296     /* There can be only one (possibility if confdb isn't around) */
 297     do {
 298         rc = cmap_initialize(&local_handle);
 299         if (rc != CS_OK) {
 300             retries++;
 301             printf("cmap connection setup failed: %s.  Retrying in %ds\n", cs_strerror(rc), retries);
 302             crm_info("cmap connection setup failed: %s.  Retrying in %ds", cs_strerror(rc), retries);
 303             sleep(retries);
 304 
 305         } else {
 306             break;
 307         }
 308 
 309     } while (retries < 5);
 310 #endif
 311 
 312     if (rc != CS_OK) {
 313         printf("Could not connect to Cluster Configuration Database API, error %d\n", rc);
 314         crm_warn("Could not connect to Cluster Configuration Database API, error %d", rc);
 315         return FALSE;
 316     }
 317 
 318     stack = get_cluster_type();
 319     crm_info("Reading configure for stack: %s", name_for_cluster_type(stack));
 320 
 321     /* =::=::= Should we be here =::=::= */
 322     if (stack == pcmk_cluster_corosync) {
 323         set_daemon_option("cluster_type", "corosync");
 324         set_daemon_option("quorum_type", "corosync");
 325 
 326 #if HAVE_CONFDB
 327     } else if (stack == pcmk_cluster_cman) {
 328         set_daemon_option("cluster_type", "cman");
 329         set_daemon_option("quorum_type", "cman");
 330         enable_crmd_as_root(TRUE);
 331 
 332     } else if (stack == pcmk_cluster_classic_ais) {
 333         set_daemon_option("cluster_type", "openais");
 334         set_daemon_option("quorum_type", "pcmk");
 335 
 336         /* Look for a service block to indicate our plugin is loaded */
 337         top_handle = config_find_init(config);
 338         local_handle = config_find_next(config, "service", top_handle);
 339 
 340         while (local_handle) {
 341             get_config_opt(config, local_handle, "name", &value, NULL);
 342             if (safe_str_eq("pacemaker", value)) {
 343                 get_config_opt(config, local_handle, "ver", &value, "0");
 344                 if (safe_str_eq(value, "1")) {
 345                     get_config_opt(config, local_handle, "use_logd", &value, "no");
 346                     set_daemon_option("use_logd", value);
 347                     set_daemon_option("LOGD", value);
 348 
 349                     get_config_opt(config, local_handle, "use_mgmtd", &value, "no");
 350                     enable_mgmtd(crm_is_true(value));
 351 
 352                 } else {
 353                     crm_err("We can only start Pacemaker from init if using version 1"
 354                             " of the Pacemaker plugin for Corosync.  Terminating.");
 355                     crm_exit(DAEMON_RESPAWN_STOP);
 356                 }
 357                 break;
 358             }
 359             local_handle = config_find_next(config, "service", top_handle);
 360         }
 361         free(value);
 362 
 363 #endif
 364     } else {
 365         crm_err("Unsupported stack type: %s", name_for_cluster_type(stack));
 366         return FALSE;
 367     }
 368 
 369 #if HAVE_CONFDB
 370     top_handle = config_find_init(config);
 371     local_handle = config_find_next(config, "logging", top_handle);
 372 #endif
 373 
 374     /* =::=::= Logging =::=::= */
 375     if (daemon_option("debug")) {
 376         /* Syslog logging is already setup by crm_log_init() */
 377 
 378     } else {
 379         /* Check corosync */
 380         char *debug_enabled = NULL;
 381 
 382         get_config_opt(config, local_handle, KEY_PREFIX "debug", &debug_enabled, "off");
 383 
 384         if (crm_is_true(debug_enabled)) {
 385             set_daemon_option("debug", "1");
 386             if (get_crm_log_level() < LOG_DEBUG) {
 387                 set_crm_log_level(LOG_DEBUG);
 388             }
 389 
 390         } else {
 391             set_daemon_option("debug", "0");
 392         }
 393 
 394         free(debug_enabled);
 395     }
 396 
 397     /* If the user didn't explicitly configure a Pacemaker log file, check
 398      * whether they configured a heartbeat or corosync log file, and use that.
 399      *
 400      * @COMPAT This should all go away, and we should just rely on the logging
 401      * set up by crm_log_init(). We aren't doing this yet because it is a
 402      * significant user-visible change that will need to be publicized.
 403      */
 404     const_value = daemon_option("debugfile");
 405     if (daemon_option("logfile")) {
 406         /* File logging is already setup by crm_log_init() */
 407 
 408     } else if(const_value) {
 409         /* From when we cared what options heartbeat used */
 410         set_daemon_option("logfile", const_value);
 411         crm_add_logfile(const_value);
 412 
 413     } else {
 414         /* Check corosync */
 415         char *logfile = NULL;
 416         char *logfile_enabled = NULL;
 417 
 418         get_config_opt(config, local_handle, KEY_PREFIX "to_logfile", &logfile_enabled, "on");
 419         get_config_opt(config, local_handle, KEY_PREFIX "logfile", &logfile, "/var/log/pacemaker.log");
 420 
 421         if (crm_is_true(logfile_enabled) == FALSE) {
 422             crm_trace("File logging disabled in corosync");
 423 
 424         } else if (crm_add_logfile(logfile)) {
 425             set_daemon_option("logfile", logfile);
 426 
 427         } else {
 428             crm_err("Couldn't create logfile: %s", logfile);
 429             set_daemon_option("logfile", "none");
 430         }
 431 
 432         free(logfile);
 433         free(logfile_enabled);
 434     }
 435 
 436     if (daemon_option("logfacility")) {
 437         /* Syslog logging is already setup by crm_log_init() */
 438 
 439     } else {
 440         /* Check corosync */
 441         char *syslog_enabled = NULL;
 442         char *syslog_facility = NULL;
 443 
 444         get_config_opt(config, local_handle, KEY_PREFIX "to_syslog", &syslog_enabled, "on");
 445         get_config_opt(config, local_handle, KEY_PREFIX "syslog_facility", &syslog_facility, "daemon");
 446 
 447         if (crm_is_true(syslog_enabled) == FALSE) {
 448             qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
 449             set_daemon_option("logfacility", "none");
 450 
 451         } else {
 452             qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_FACILITY, qb_log_facility2int(syslog_facility));
 453             qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_TRUE);
 454             set_daemon_option("logfacility", syslog_facility);
 455         }
 456 
 457         free(syslog_enabled);
 458         free(syslog_facility);
 459     }
 460 
 461     const_value = daemon_option("logfacility");
 462     if (const_value) {
 463         /* cluster-glue module needs HA_LOGFACILITY */
 464         setenv("HA_LOGFACILITY", const_value, 1);
 465     }
 466 
 467 #if HAVE_CONFDB
 468     confdb_finalize(config);
 469 #elif HAVE_CMAP
 470     if(local_handle){
 471         gid_t gid = 0;
 472         if (crm_user_lookup(CRM_DAEMON_USER, NULL, &gid) < 0) {
 473             crm_warn("Could not authorize group with corosync " CRM_XS
 474                      " No group found for user %s", CRM_DAEMON_USER);
 475 
 476         } else {
 477             char key[PATH_MAX];
 478             snprintf(key, PATH_MAX, "uidgid.gid.%u", gid);
 479             rc = cmap_set_uint8(local_handle, key, 1);
 480             if (rc != CS_OK) {
 481                 crm_warn("Could not authorize group with corosync "CRM_XS
 482                          " group=%u rc=%d (%s)", gid, rc, ais_error2text(rc));
 483             }
 484         }
 485     }
 486     cmap_finalize(local_handle);
 487 #endif
 488 
 489     return TRUE;
 490 }

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