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. build_arg_context
  4. main
  5. cib_cs_dispatch
  6. cib_cs_destroy
  7. cib_peer_update_callback
  8. cib_init
  9. startCib

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

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