root/daemons/based/pacemaker-based.c

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

DEFINITIONS

This source file includes following definitions.
  1. cib_enable_writes
  2. setup_stand_alone
  3. based_metadata
  4. build_arg_context
  5. main
  6. cib_cs_dispatch
  7. cib_cs_destroy
  8. cib_peer_update_callback
  9. cib_init
  10. startCib

   1 /*
   2  * Copyright 2004-2024 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 
  12 #include <stdio.h>
  13 #include <stdlib.h>
  14 #include <pwd.h>
  15 #include <grp.h>
  16 #include <bzlib.h>
  17 #include <sys/types.h>
  18 
  19 #include <glib.h>
  20 #include <libxml/tree.h>
  21 
  22 #include <crm/crm.h>
  23 #include <crm/cib/internal.h>
  24 #include <crm/cluster/internal.h>
  25 #include <crm/common/cmdline_internal.h>
  26 #include <crm/common/mainloop.h>
  27 #include <crm/common/output_internal.h>
  28 #include <crm/common/xml.h>
  29 
  30 #include <pacemaker-based.h>
  31 
  32 #define SUMMARY "daemon for managing the configuration of a Pacemaker cluster"
  33 
  34 extern int init_remote_listener(int port, gboolean encrypted);
  35 gboolean cib_shutdown_flag = FALSE;
  36 int cib_status = pcmk_ok;
  37 
  38 pcmk_cluster_t *crm_cluster = NULL;
  39 
  40 GMainLoop *mainloop = NULL;
  41 gchar *cib_root = NULL;
  42 static gboolean preserve_status = FALSE;
  43 
  44 gboolean cib_writes_enabled = TRUE;
  45 gboolean stand_alone = FALSE;
  46 
  47 int remote_fd = 0;
  48 int remote_tls_fd = 0;
  49 
  50 GHashTable *config_hash = NULL;
  51 
  52 static void cib_init(void);
  53 void cib_shutdown(int nsig);
  54 static bool startCib(const char *filename);
  55 extern int write_cib_contents(gpointer p);
  56 
  57 static crm_exit_t exit_code = CRM_EX_OK;
  58 
  59 static void
  60 cib_enable_writes(int nsig)
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62     crm_info("(Re)enabling disk writes");
  63     cib_writes_enabled = TRUE;
  64 }
  65 
  66 /*!
  67  * \internal
  68  * \brief Set up options, users, and groups for stand-alone mode
  69  *
  70  * \param[out] error  GLib error object
  71  *
  72  * \return Standard Pacemaker return code
  73  */
  74 static int
  75 setup_stand_alone(GError **error)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77     int rc = 0;
  78     struct passwd *pwentry = NULL;
  79 
  80     preserve_status = TRUE;
  81     cib_writes_enabled = FALSE;
  82 
  83     errno = 0;
  84     pwentry = getpwnam(CRM_DAEMON_USER);
  85     if (pwentry == NULL) {
  86         exit_code = CRM_EX_FATAL;
  87         if (errno != 0) {
  88             g_set_error(error, PCMK__EXITC_ERROR, exit_code,
  89                         "Error getting password DB entry for %s: %s",
  90                         CRM_DAEMON_USER, strerror(errno));
  91             return errno;
  92         }
  93         g_set_error(error, PCMK__EXITC_ERROR, exit_code,
  94                     "Password DB entry for '%s' not found", CRM_DAEMON_USER);
  95         return ENXIO;
  96     }
  97 
  98     rc = setgid(pwentry->pw_gid);
  99     if (rc < 0) {
 100         exit_code = CRM_EX_FATAL;
 101         g_set_error(error, PCMK__EXITC_ERROR, exit_code,
 102                     "Could not set group to %d: %s",
 103                     pwentry->pw_gid, strerror(errno));
 104         return errno;
 105     }
 106 
 107     rc = initgroups(CRM_DAEMON_USER, pwentry->pw_gid);
 108     if (rc < 0) {
 109         exit_code = CRM_EX_FATAL;
 110         g_set_error(error, PCMK__EXITC_ERROR, exit_code,
 111                     "Could not setup groups for user %d: %s",
 112                     pwentry->pw_uid, strerror(errno));
 113         return errno;
 114     }
 115 
 116     rc = setuid(pwentry->pw_uid);
 117     if (rc < 0) {
 118         exit_code = CRM_EX_FATAL;
 119         g_set_error(error, PCMK__EXITC_ERROR, exit_code,
 120                     "Could not set user to %d: %s",
 121                     pwentry->pw_uid, strerror(errno));
 122         return errno;
 123     }
 124     return pcmk_rc_ok;
 125 }
 126 
 127 /* @COMPAT Deprecated since 2.1.8. Use pcmk_list_cluster_options() or
 128  * crm_attribute --list-options=cluster instead of querying daemon metadata.
 129  *
 130  * NOTE: pcs (as of at least 0.11.8) uses this
 131  */
 132 static int
 133 based_metadata(pcmk__output_t *out)
     /* [previous][next][first][last][top][bottom][index][help] */
 134 {
 135     return pcmk__daemon_metadata(out, PCMK__SERVER_BASED,
 136                                  "Cluster Information Base manager options",
 137                                  "Cluster options used by Pacemaker's Cluster "
 138                                  "Information Base manager",
 139                                  pcmk__opt_based);
 140 }
 141 
 142 static GOptionEntry entries[] = {
 143     { "stand-alone", 's', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &stand_alone,
 144       "(Advanced use only) Run in stand-alone mode", NULL },
 145 
 146     { "disk-writes", 'w', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE,
 147       &cib_writes_enabled,
 148       "(Advanced use only) Enable disk writes (enabled by default unless in "
 149       "stand-alone mode)", NULL },
 150 
 151     { "cib-root", 'r', G_OPTION_FLAG_NONE, G_OPTION_ARG_FILENAME, &cib_root,
 152       "(Advanced use only) Directory where the CIB XML file should be located "
 153       "(default: " CRM_CONFIG_DIR ")", NULL },
 154 
 155     { NULL }
 156 };
 157 
 158 static pcmk__supported_format_t formats[] = {
 159     PCMK__SUPPORTED_FORMAT_NONE,
 160     PCMK__SUPPORTED_FORMAT_TEXT,
 161     PCMK__SUPPORTED_FORMAT_XML,
 162     { NULL, NULL, NULL }
 163 };
 164 
 165 static GOptionContext *
 166 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group)
     /* [previous][next][first][last][top][bottom][index][help] */
 167 {
 168     GOptionContext *context = NULL;
 169 
 170     context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
 171     pcmk__add_main_args(context, entries);
 172     return context;
 173 }
 174 
 175 int
 176 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 177 {
 178     int rc = pcmk_rc_ok;
 179     crm_ipc_t *old_instance = NULL;
 180 
 181     pcmk__output_t *out = NULL;
 182 
 183     GError *error = NULL;
 184 
 185     GOptionGroup *output_group = NULL;
 186     pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
 187     gchar **processed_args = pcmk__cmdline_preproc(argv, "r");
 188     GOptionContext *context = build_arg_context(args, &output_group);
 189 
 190     crm_log_preinit(NULL, argc, argv);
 191 
 192     pcmk__register_formats(output_group, formats);
 193     if (!g_option_context_parse_strv(context, &processed_args, &error)) {
 194         exit_code = CRM_EX_USAGE;
 195         goto done;
 196     }
 197 
 198     rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
 199     if (rc != pcmk_rc_ok) {
 200         exit_code = CRM_EX_ERROR;
 201         g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 202                     "Error creating output format %s: %s",
 203                     args->output_ty, pcmk_rc_str(rc));
 204         goto done;
 205     }
 206 
 207     if (args->version) {
 208         out->version(out, false);
 209         goto done;
 210     }
 211 
 212     mainloop_add_signal(SIGTERM, cib_shutdown);
 213     mainloop_add_signal(SIGPIPE, cib_enable_writes);
 214 
 215     cib_writer = mainloop_add_trigger(G_PRIORITY_LOW, write_cib_contents, NULL);
 216 
 217     if ((g_strv_length(processed_args) >= 2)
 218         && pcmk__str_eq(processed_args[1], "metadata", pcmk__str_none)) {
 219 
 220         rc = based_metadata(out);
 221         if (rc != pcmk_rc_ok) {
 222             exit_code = CRM_EX_FATAL;
 223             g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 224                         "Unable to display metadata: %s", pcmk_rc_str(rc));
 225         }
 226         goto done;
 227     }
 228 
 229     pcmk__cli_init_logging(PCMK__SERVER_BASED, args->verbosity);
 230     crm_log_init(NULL, LOG_INFO, TRUE, FALSE, argc, argv, FALSE);
 231     crm_notice("Starting Pacemaker CIB manager");
 232 
 233     old_instance = crm_ipc_new(PCMK__SERVER_BASED_RO, 0);
 234     if (old_instance == NULL) {
 235         /* crm_ipc_new() will have already logged an error message with
 236          * crm_err()
 237          */
 238         exit_code = CRM_EX_FATAL;
 239         goto done;
 240     }
 241 
 242     if (pcmk__connect_generic_ipc(old_instance) == pcmk_rc_ok) {
 243         /* IPC end-point already up */
 244         crm_ipc_close(old_instance);
 245         crm_ipc_destroy(old_instance);
 246         crm_crit("Aborting start-up because another CIB manager instance is "
 247                  "already active");
 248         goto done;
 249     } else {
 250         /* not up or not authentic, we'll proceed either way */
 251         crm_ipc_destroy(old_instance);
 252         old_instance = NULL;
 253     }
 254 
 255     if (stand_alone) {
 256         rc = setup_stand_alone(&error);
 257         if (rc != pcmk_rc_ok) {
 258             goto done;
 259         }
 260     }
 261 
 262     if (cib_root == NULL) {
 263         cib_root = g_strdup(CRM_CONFIG_DIR);
 264     } else {
 265         crm_notice("Using custom config location: %s", cib_root);
 266     }
 267 
 268     if (!pcmk__daemon_can_write(cib_root, NULL)) {
 269         exit_code = CRM_EX_FATAL;
 270         crm_err("Terminating due to bad permissions on %s", cib_root);
 271         g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
 272                     "Bad permissions on %s (see logs for details)", cib_root);
 273         goto done;
 274     }
 275 
 276     pcmk__cluster_init_node_caches();
 277 
 278     // Read initial CIB, connect to cluster, and start IPC servers
 279     cib_init();
 280 
 281     // Run the main loop
 282     mainloop = g_main_loop_new(NULL, FALSE);
 283     crm_notice("Pacemaker CIB manager successfully started and accepting connections");
 284     g_main_loop_run(mainloop);
 285 
 286     /* If main loop returned, clean up and exit. We disconnect in case
 287      * terminate_cib() was called with fast=-1.
 288      */
 289     pcmk_cluster_disconnect(crm_cluster);
 290     pcmk__stop_based_ipc(ipcs_ro, ipcs_rw, ipcs_shm);
 291 
 292 done:
 293     g_strfreev(processed_args);
 294     pcmk__free_arg_context(context);
 295 
 296     pcmk__cluster_destroy_node_caches();
 297 
 298     if (config_hash != NULL) {
 299         g_hash_table_destroy(config_hash);
 300     }
 301     pcmk__client_cleanup();
 302     pcmk_cluster_free(crm_cluster);
 303     g_free(cib_root);
 304 
 305     pcmk__output_and_clear_error(&error, out);
 306 
 307     if (out != NULL) {
 308         out->finish(out, exit_code, true, NULL);
 309         pcmk__output_free(out);
 310     }
 311     pcmk__unregister_formats();
 312     crm_exit(exit_code);
 313 }
 314 
 315 #if SUPPORT_COROSYNC
 316 static void
 317 cib_cs_dispatch(cpg_handle_t handle,
     /* [previous][next][first][last][top][bottom][index][help] */
 318                  const struct cpg_name *groupName,
 319                  uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
 320 {
 321     xmlNode *xml = NULL;
 322     const char *from = NULL;
 323     char *data = pcmk__cpg_message_data(handle, nodeid, pid, msg, &from);
 324 
 325     if(data == NULL) {
 326         return;
 327     }
 328 
 329     xml = pcmk__xml_parse(data);
 330     if (xml == NULL) {
 331         crm_err("Invalid XML: '%.120s'", data);
 332         free(data);
 333         return;
 334     }
 335     crm_xml_add(xml, PCMK__XA_SRC, from);
 336     cib_peer_callback(xml, NULL);
 337 
 338     pcmk__xml_free(xml);
 339     free(data);
 340 }
 341 
 342 static void
 343 cib_cs_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 344 {
 345     if (cib_shutdown_flag) {
 346         crm_info("Corosync disconnection complete");
 347     } else {
 348         crm_crit("Lost connection to cluster layer, shutting down");
 349         terminate_cib(__func__, CRM_EX_DISCONNECT);
 350     }
 351 }
 352 #endif
 353 
 354 static void
 355 cib_peer_update_callback(enum pcmk__node_update type,
     /* [previous][next][first][last][top][bottom][index][help] */
 356                          pcmk__node_status_t *node, const void *data)
 357 {
 358     switch (type) {
 359         case pcmk__node_update_name:
 360         case pcmk__node_update_state:
 361             if (cib_shutdown_flag && (pcmk__cluster_num_active_nodes() < 2)
 362                 && (pcmk__ipc_client_count() == 0)) {
 363 
 364                 crm_info("No more peers");
 365                 terminate_cib(__func__, -1);
 366             }
 367             break;
 368 
 369         default:
 370             break;
 371     }
 372 }
 373 
 374 static void
 375 cib_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 376 {
 377     crm_cluster = pcmk_cluster_new();
 378 
 379 #if SUPPORT_COROSYNC
 380     if (pcmk_get_cluster_layer() == pcmk_cluster_layer_corosync) {
 381         pcmk_cluster_set_destroy_fn(crm_cluster, cib_cs_destroy);
 382         pcmk_cpg_set_deliver_fn(crm_cluster, cib_cs_dispatch);
 383         pcmk_cpg_set_confchg_fn(crm_cluster, pcmk__cpg_confchg_cb);
 384     }
 385 #endif // SUPPORT_COROSYNC
 386 
 387     config_hash = pcmk__strkey_table(free, free);
 388 
 389     if (startCib("cib.xml") == FALSE) {
 390         crm_crit("Cannot start CIB... terminating");
 391         crm_exit(CRM_EX_NOINPUT);
 392     }
 393 
 394     if (!stand_alone) {
 395         pcmk__cluster_set_status_callback(&cib_peer_update_callback);
 396 
 397         if (pcmk_cluster_connect(crm_cluster) != pcmk_rc_ok) {
 398             crm_crit("Cannot sign in to the cluster... terminating");
 399             crm_exit(CRM_EX_FATAL);
 400         }
 401     }
 402 
 403     pcmk__serve_based_ipc(&ipcs_ro, &ipcs_rw, &ipcs_shm, &ipc_ro_callbacks,
 404                           &ipc_rw_callbacks);
 405 
 406     if (stand_alone) {
 407         based_is_primary = true;
 408     }
 409 }
 410 
 411 static bool
 412 startCib(const char *filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 413 {
 414     gboolean active = FALSE;
 415     xmlNode *cib = readCibXmlFile(cib_root, filename, !preserve_status);
 416 
 417     if (activateCibXml(cib, TRUE, "start") == 0) {
 418         int port = 0;
 419 
 420         active = TRUE;
 421 
 422         cib_read_config(config_hash, cib);
 423 
 424         pcmk__scan_port(crm_element_value(cib, PCMK_XA_REMOTE_TLS_PORT), &port);
 425         if (port >= 0) {
 426             remote_tls_fd = init_remote_listener(port, TRUE);
 427         }
 428 
 429         pcmk__scan_port(crm_element_value(cib, PCMK_XA_REMOTE_CLEAR_PORT),
 430                         &port);
 431         if (port >= 0) {
 432             remote_fd = init_remote_listener(port, FALSE);
 433         }
 434     }
 435     return active;
 436 }

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