root/daemons/pacemakerd/pcmkd_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. pcmkd_shutdown_corosync
  7. get_config_opt
  8. mcp_read_config

   1 /*
   2  * Copyright 2010-2020 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 #include "pacemakerd.h"
  12 
  13 #include <sys/utsname.h>
  14 #include <sys/stat.h>           /* for calls to stat() */
  15 #include <libgen.h>             /* For basename() and dirname() */
  16 
  17 #include <sys/types.h>
  18 #include <pwd.h>                /* For getpwname() */
  19 
  20 #include <corosync/hdb.h>
  21 #include <corosync/cfg.h>
  22 #include <corosync/cpg.h>
  23 #include <corosync/cmap.h>
  24 
  25 #include <crm/cluster/internal.h>
  26 #include <crm/common/ipc.h>     /* for crm_ipc_is_authentic_process */
  27 #include <crm/common/mainloop.h>
  28 
  29 #include <crm/common/ipc_internal.h>  /* PCMK__SPECIAL_PID* */
  30 
  31 static corosync_cfg_handle_t cfg_handle = 0;
  32 
  33 /* =::=::=::= CFG - Shutdown stuff =::=::=::= */
  34 
  35 static void
  36 cfg_shutdown_callback(corosync_cfg_handle_t h, corosync_cfg_shutdown_flags_t flags)
     /* [previous][next][first][last][top][bottom][index][help] */
  37 {
  38     crm_info("Corosync wants to shut down: %s",
  39              (flags == COROSYNC_CFG_SHUTDOWN_FLAG_IMMEDIATE) ? "immediate" :
  40              (flags == COROSYNC_CFG_SHUTDOWN_FLAG_REGARDLESS) ? "forced" : "optional");
  41 
  42     /* Never allow corosync to shut down while we're running */
  43     corosync_cfg_replyto_shutdown(h, COROSYNC_CFG_SHUTDOWN_FLAG_NO);
  44 }
  45 
  46 static corosync_cfg_callbacks_t cfg_callbacks = {
  47     .corosync_cfg_shutdown_callback = cfg_shutdown_callback,
  48 };
  49 
  50 static int
  51 pcmk_cfg_dispatch(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
  52 {
  53     corosync_cfg_handle_t *handle = (corosync_cfg_handle_t *) user_data;
  54     cs_error_t rc = corosync_cfg_dispatch(*handle, CS_DISPATCH_ALL);
  55 
  56     if (rc != CS_OK) {
  57         return -1;
  58     }
  59     return 0;
  60 }
  61 
  62 static void
  63 cfg_connection_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
  64 {
  65     crm_err("Lost connection to cluster layer");
  66     corosync_cfg_finalize(cfg_handle);
  67     cfg_handle = 0;
  68     pcmk_shutdown(SIGTERM);
  69 }
  70 
  71 gboolean
  72 cluster_disconnect_cfg(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  73 {
  74     if (cfg_handle) {
  75         corosync_cfg_finalize(cfg_handle);
  76         cfg_handle = 0;
  77     }
  78 
  79     pcmk_shutdown(SIGTERM);
  80     return TRUE;
  81 }
  82 
  83 #define cs_repeat(counter, max, code) do {              \
  84         code;                                           \
  85         if(rc == CS_ERR_TRY_AGAIN || rc == CS_ERR_QUEUE_FULL) {  \
  86             counter++;                                  \
  87             crm_debug("Retrying Corosync operation after %ds", counter);    \
  88             sleep(counter);                             \
  89         } else {                                        \
  90             break;                                      \
  91         }                                               \
  92     } while(counter < max)
  93 
  94 gboolean
  95 cluster_connect_cfg(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  96 {
  97     cs_error_t rc;
  98     int fd = -1, retries = 0, rv;
  99     uid_t found_uid = 0;
 100     gid_t found_gid = 0;
 101     pid_t found_pid = 0;
 102     uint32_t nodeid;
 103 
 104     static struct mainloop_fd_callbacks cfg_fd_callbacks = {
 105         .dispatch = pcmk_cfg_dispatch,
 106         .destroy = cfg_connection_destroy,
 107     };
 108 
 109     cs_repeat(retries, 30, rc = corosync_cfg_initialize(&cfg_handle, &cfg_callbacks));
 110 
 111     if (rc != CS_OK) {
 112         crm_crit("Could not connect to Corosync CFG: %s " CRM_XS " rc=%d",
 113                  cs_strerror(rc), rc);
 114         return FALSE;
 115     }
 116 
 117     rc = corosync_cfg_fd_get(cfg_handle, &fd);
 118     if (rc != CS_OK) {
 119         crm_crit("Could not get Corosync CFG descriptor: %s " CRM_XS " rc=%d",
 120                  cs_strerror(rc), rc);
 121         goto bail;
 122     }
 123 
 124     /* CFG provider run as root (in given user namespace, anyway)? */
 125     if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
 126                                             &found_uid, &found_gid))) {
 127         crm_crit("Rejecting Corosync CFG provider because process %lld "
 128                  "is running as uid %lld gid %lld, not root",
 129                   (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
 130                  (long long) found_uid, (long long) found_gid);
 131         goto bail;
 132     } else if (rv < 0) {
 133         crm_crit("Could not authenticate Corosync CFG provider: %s "
 134                  CRM_XS " rc=%d", strerror(-rv), -rv);
 135         goto bail;
 136     }
 137 
 138     retries = 0;
 139     cs_repeat(retries, 30, rc = corosync_cfg_local_get(cfg_handle, &nodeid));
 140     if (rc != CS_OK) {
 141         crm_crit("Could not get local node ID from Corosync: %s "
 142                  CRM_XS " rc=%d", cs_strerror(rc), rc);
 143         goto bail;
 144     }
 145     crm_debug("Corosync reports local node ID is %lu", (unsigned long) nodeid);
 146 
 147     mainloop_add_fd("corosync-cfg", G_PRIORITY_DEFAULT, fd, &cfg_handle, &cfg_fd_callbacks);
 148     return TRUE;
 149 
 150   bail:
 151     corosync_cfg_finalize(cfg_handle);
 152     return FALSE;
 153 }
 154 
 155 void
 156 pcmkd_shutdown_corosync(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 157 {
 158     cs_error_t rc;
 159 
 160     if (cfg_handle == 0) {
 161         crm_warn("Unable to shut down Corosync: No connection");
 162         return;
 163     }
 164     crm_info("Asking Corosync to shut down");
 165     rc = corosync_cfg_try_shutdown(cfg_handle,
 166                                     COROSYNC_CFG_SHUTDOWN_FLAG_IMMEDIATE);
 167     if (rc == CS_OK) {
 168         corosync_cfg_finalize(cfg_handle);
 169         cfg_handle = 0;
 170     } else {
 171         crm_warn("Corosync shutdown failed: %s " CRM_XS " rc=%d",
 172                  cs_strerror(rc), rc);
 173     }
 174 }
 175 
 176 
 177 /* =::=::=::= Configuration =::=::=::= */
 178 static int
 179 get_config_opt(uint64_t unused, cmap_handle_t object_handle, const char *key, char **value,
     /* [previous][next][first][last][top][bottom][index][help] */
 180                const char *fallback)
 181 {
 182     int rc = 0, retries = 0;
 183 
 184     cs_repeat(retries, 5, rc = cmap_get_string(object_handle, key, value));
 185     if (rc != CS_OK) {
 186         crm_trace("Search for %s failed %d, defaulting to %s", key, rc, fallback);
 187         if (fallback) {
 188             *value = strdup(fallback);
 189         } else {
 190             *value = NULL;
 191         }
 192     }
 193     crm_trace("%s: %s", key, *value);
 194     return rc;
 195 }
 196 
 197 gboolean
 198 mcp_read_config(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 199 {
 200     cs_error_t rc = CS_OK;
 201     int retries = 0;
 202     cmap_handle_t local_handle;
 203     uint64_t config = 0;
 204     int fd = -1;
 205     uid_t found_uid = 0;
 206     gid_t found_gid = 0;
 207     pid_t found_pid = 0;
 208     int rv;
 209     enum cluster_type_e stack;
 210 
 211     // There can be only one possibility
 212     do {
 213         rc = cmap_initialize(&local_handle);
 214         if (rc != CS_OK) {
 215             retries++;
 216             crm_info("Could not connect to Corosync CMAP: %s (retrying in %ds) "
 217                      CRM_XS " rc=%d", cs_strerror(rc), retries, rc);
 218             sleep(retries);
 219 
 220         } else {
 221             break;
 222         }
 223 
 224     } while (retries < 5);
 225 
 226     if (rc != CS_OK) {
 227         crm_crit("Could not connect to Corosync CMAP: %s "
 228                  CRM_XS " rc=%d", cs_strerror(rc), rc);
 229         return FALSE;
 230     }
 231 
 232     rc = cmap_fd_get(local_handle, &fd);
 233     if (rc != CS_OK) {
 234         crm_crit("Could not get Corosync CMAP descriptor: %s " CRM_XS " rc=%d",
 235                  cs_strerror(rc), rc);
 236         cmap_finalize(local_handle);
 237         return FALSE;
 238     }
 239 
 240     /* CMAP provider run as root (in given user namespace, anyway)? */
 241     if (!(rv = crm_ipc_is_authentic_process(fd, (uid_t) 0,(gid_t) 0, &found_pid,
 242                                             &found_uid, &found_gid))) {
 243         crm_crit("Rejecting Corosync CMAP provider because process %lld "
 244                  "is running as uid %lld gid %lld, not root",
 245                  (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
 246                  (long long) found_uid, (long long) found_gid);
 247         cmap_finalize(local_handle);
 248         return FALSE;
 249     } else if (rv < 0) {
 250         crm_crit("Could not authenticate Corosync CMAP provider: %s "
 251                  CRM_XS " rc=%d", strerror(-rv), -rv);
 252         cmap_finalize(local_handle);
 253         return FALSE;
 254     }
 255 
 256     stack = get_cluster_type();
 257     if (stack != pcmk_cluster_corosync) {
 258         crm_crit("Expected corosync stack but detected %s " CRM_XS " stack=%d",
 259                  name_for_cluster_type(stack), stack);
 260         return FALSE;
 261     }
 262 
 263     crm_info("Reading configuration for %s stack",
 264              name_for_cluster_type(stack));
 265     pcmk__set_env_option("cluster_type", "corosync");
 266     pcmk__set_env_option("quorum_type", "corosync");
 267 
 268     // If debug logging is not configured, check whether corosync has it
 269     if (pcmk__env_option("debug") == NULL) {
 270         char *debug_enabled = NULL;
 271 
 272         get_config_opt(config, local_handle, "logging.debug", &debug_enabled, "off");
 273 
 274         if (crm_is_true(debug_enabled)) {
 275             pcmk__set_env_option("debug", "1");
 276             if (get_crm_log_level() < LOG_DEBUG) {
 277                 set_crm_log_level(LOG_DEBUG);
 278             }
 279 
 280         } else {
 281             pcmk__set_env_option("debug", "0");
 282         }
 283 
 284         free(debug_enabled);
 285     }
 286 
 287     if(local_handle){
 288         gid_t gid = 0;
 289         if (pcmk_daemon_user(NULL, &gid) < 0) {
 290             crm_warn("Could not authorize group with Corosync " CRM_XS
 291                      " No group found for user %s", CRM_DAEMON_USER);
 292 
 293         } else {
 294             char key[PATH_MAX];
 295             snprintf(key, PATH_MAX, "uidgid.gid.%u", gid);
 296             rc = cmap_set_uint8(local_handle, key, 1);
 297             if (rc != CS_OK) {
 298                 crm_warn("Could not authorize group with Corosync: %s " CRM_XS
 299                          " group=%u rc=%d", ais_error2text(rc), gid, rc);
 300             }
 301         }
 302     }
 303     cmap_finalize(local_handle);
 304 
 305     return TRUE;
 306 }

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