root/daemons/controld/controld_control.c

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

DEFINITIONS

This source file includes following definitions.
  1. do_ha_control
  2. do_shutdown
  3. do_shutdown_req
  4. crmd_fast_exit
  5. crmd_exit
  6. do_exit
  7. sigpipe_ignore
  8. do_startup
  9. accept_controller_client
  10. dispatch_controller_ipc
  11. ipc_client_disconnected
  12. ipc_connection_destroyed
  13. do_stop
  14. do_started
  15. do_recover
  16. crmd_metadata
  17. config_query_callback
  18. controld_trigger_config_as
  19. crm_read_options
  20. do_read_config
  21. crm_shutdown

   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 <sys/param.h>
  13 #include <sys/types.h>
  14 #include <sys/stat.h>
  15 
  16 #include <crm/crm.h>
  17 #include <crm/msg_xml.h>
  18 #include <crm/pengine/rules.h>
  19 #include <crm/cluster/internal.h>
  20 #include <crm/cluster/election_internal.h>
  21 #include <crm/common/ipc_internal.h>
  22 
  23 #include <pacemaker-controld.h>
  24 
  25 static qb_ipcs_service_t *ipcs = NULL;
  26 
  27 static crm_trigger_t *config_read_trigger = NULL;
  28 
  29 #if SUPPORT_COROSYNC
  30 extern gboolean crm_connect_corosync(crm_cluster_t * cluster);
  31 #endif
  32 
  33 void crm_shutdown(int nsig);
  34 static gboolean crm_read_options(gpointer user_data);
  35 
  36 /*       A_HA_CONNECT   */
  37 void
  38 do_ha_control(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
  39               enum crmd_fsa_cause cause,
  40               enum crmd_fsa_state cur_state,
  41               enum crmd_fsa_input current_input, fsa_data_t * msg_data)
  42 {
  43     gboolean registered = FALSE;
  44     static crm_cluster_t *cluster = NULL;
  45 
  46     if (cluster == NULL) {
  47         cluster = pcmk_cluster_new();
  48     }
  49 
  50     if (action & A_HA_DISCONNECT) {
  51         crm_cluster_disconnect(cluster);
  52         crm_info("Disconnected from the cluster");
  53 
  54         controld_set_fsa_input_flags(R_HA_DISCONNECTED);
  55     }
  56 
  57     if (action & A_HA_CONNECT) {
  58         crm_set_status_callback(&peer_update_callback);
  59         crm_set_autoreap(FALSE);
  60 
  61 #if SUPPORT_COROSYNC
  62         if (is_corosync_cluster()) {
  63             registered = crm_connect_corosync(cluster);
  64         }
  65 #endif // SUPPORT_COROSYNC
  66 
  67         if (registered) {
  68             controld_election_init(cluster->uname);
  69             controld_globals.our_nodename = cluster->uname;
  70             controld_globals.our_uuid = cluster->uuid;
  71             if(cluster->uuid == NULL) {
  72                 crm_err("Could not obtain local uuid");
  73                 registered = FALSE;
  74             }
  75         }
  76 
  77         if (!registered) {
  78             controld_set_fsa_input_flags(R_HA_DISCONNECTED);
  79             register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
  80             return;
  81         }
  82 
  83         populate_cib_nodes(node_update_none, __func__);
  84         controld_clear_fsa_input_flags(R_HA_DISCONNECTED);
  85         crm_info("Connected to the cluster");
  86     }
  87 
  88     if (action & ~(A_HA_CONNECT | A_HA_DISCONNECT)) {
  89         crm_err("Unexpected action %s in %s", fsa_action2string(action),
  90                 __func__);
  91     }
  92 }
  93 
  94 /*       A_SHUTDOWN     */
  95 void
  96 do_shutdown(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
  97             enum crmd_fsa_cause cause,
  98             enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
  99 {
 100     /* just in case */
 101     controld_set_fsa_input_flags(R_SHUTDOWN);
 102     controld_disconnect_fencer(FALSE);
 103 }
 104 
 105 /*       A_SHUTDOWN_REQ */
 106 void
 107 do_shutdown_req(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 108                 enum crmd_fsa_cause cause,
 109                 enum crmd_fsa_state cur_state,
 110                 enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 111 {
 112     xmlNode *msg = NULL;
 113 
 114     controld_set_fsa_input_flags(R_SHUTDOWN);
 115     //controld_set_fsa_input_flags(R_STAYDOWN);
 116     crm_info("Sending shutdown request to all peers (DC is %s)",
 117              pcmk__s(controld_globals.dc_name, "not set"));
 118     msg = create_request(CRM_OP_SHUTDOWN_REQ, NULL, NULL, CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL);
 119 
 120     if (send_cluster_message(NULL, crm_msg_crmd, msg, TRUE) == FALSE) {
 121         register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
 122     }
 123     free_xml(msg);
 124 }
 125 
 126 void
 127 crmd_fast_exit(crm_exit_t exit_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 128 {
 129     if (pcmk_is_set(controld_globals.fsa_input_register, R_STAYDOWN)) {
 130         crm_warn("Inhibiting respawn "CRM_XS" remapping exit code %d to %d",
 131                  exit_code, CRM_EX_FATAL);
 132         exit_code = CRM_EX_FATAL;
 133 
 134     } else if ((exit_code == CRM_EX_OK)
 135                && pcmk_is_set(controld_globals.fsa_input_register,
 136                               R_IN_RECOVERY)) {
 137         crm_err("Could not recover from internal error");
 138         exit_code = CRM_EX_ERROR;
 139     }
 140 
 141     if (controld_globals.logger_out != NULL) {
 142         controld_globals.logger_out->finish(controld_globals.logger_out,
 143                                             exit_code, true, NULL);
 144         pcmk__output_free(controld_globals.logger_out);
 145         controld_globals.logger_out = NULL;
 146     }
 147 
 148     crm_exit(exit_code);
 149 }
 150 
 151 crm_exit_t
 152 crmd_exit(crm_exit_t exit_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 153 {
 154     GMainLoop *mloop = controld_globals.mainloop;
 155 
 156     static bool in_progress = FALSE;
 157 
 158     if (in_progress && (exit_code == CRM_EX_OK)) {
 159         crm_debug("Exit is already in progress");
 160         return exit_code;
 161 
 162     } else if(in_progress) {
 163         crm_notice("Error during shutdown process, exiting now with status %d (%s)",
 164                    exit_code, crm_exit_str(exit_code));
 165         crm_write_blackbox(SIGTRAP, NULL);
 166         crmd_fast_exit(exit_code);
 167     }
 168 
 169     in_progress = TRUE;
 170     crm_trace("Preparing to exit with status %d (%s)",
 171               exit_code, crm_exit_str(exit_code));
 172 
 173     /* Suppress secondary errors resulting from us disconnecting everything */
 174     controld_set_fsa_input_flags(R_HA_DISCONNECTED);
 175 
 176 /* Close all IPC servers and clients to ensure any and all shared memory files are cleaned up */
 177 
 178     if(ipcs) {
 179         crm_trace("Closing IPC server");
 180         mainloop_del_ipc_server(ipcs);
 181         ipcs = NULL;
 182     }
 183 
 184     controld_close_attrd_ipc();
 185     controld_shutdown_schedulerd_ipc();
 186     controld_disconnect_fencer(TRUE);
 187 
 188     if ((exit_code == CRM_EX_OK) && (controld_globals.mainloop == NULL)) {
 189         crm_debug("No mainloop detected");
 190         exit_code = CRM_EX_ERROR;
 191     }
 192 
 193     /* On an error, just get out.
 194      *
 195      * Otherwise, make the effort to have mainloop exit gracefully so
 196      * that it (mostly) cleans up after itself and valgrind has less
 197      * to report on - allowing real errors stand out
 198      */
 199     if (exit_code != CRM_EX_OK) {
 200         crm_notice("Forcing immediate exit with status %d (%s)",
 201                    exit_code, crm_exit_str(exit_code));
 202         crm_write_blackbox(SIGTRAP, NULL);
 203         crmd_fast_exit(exit_code);
 204     }
 205 
 206 /* Clean up as much memory as possible for valgrind */
 207 
 208     for (GList *iter = controld_globals.fsa_message_queue; iter != NULL;
 209          iter = iter->next) {
 210         fsa_data_t *fsa_data = (fsa_data_t *) iter->data;
 211 
 212         crm_info("Dropping %s: [ state=%s cause=%s origin=%s ]",
 213                  fsa_input2string(fsa_data->fsa_input),
 214                  fsa_state2string(controld_globals.fsa_state),
 215                  fsa_cause2string(fsa_data->fsa_cause), fsa_data->origin);
 216         delete_fsa_input(fsa_data);
 217     }
 218 
 219     controld_clear_fsa_input_flags(R_MEMBERSHIP);
 220 
 221     g_list_free(controld_globals.fsa_message_queue);
 222     controld_globals.fsa_message_queue = NULL;
 223 
 224     controld_election_fini();
 225 
 226     /* Tear down the CIB manager connection, but don't free it yet -- it could
 227      * be used when we drain the mainloop later.
 228      */
 229 
 230     controld_disconnect_cib_manager();
 231 
 232     verify_stopped(controld_globals.fsa_state, LOG_WARNING);
 233     controld_clear_fsa_input_flags(R_LRM_CONNECTED);
 234     lrm_state_destroy_all();
 235 
 236     mainloop_destroy_trigger(config_read_trigger);
 237     config_read_trigger = NULL;
 238 
 239     controld_destroy_fsa_trigger();
 240     controld_destroy_transition_trigger();
 241 
 242     pcmk__client_cleanup();
 243     crm_peer_destroy();
 244 
 245     controld_free_fsa_timers();
 246     te_cleanup_stonith_history_sync(NULL, TRUE);
 247     controld_free_sched_timer();
 248 
 249     free(controld_globals.our_nodename);
 250     controld_globals.our_nodename = NULL;
 251 
 252     free(controld_globals.our_uuid);
 253     controld_globals.our_uuid = NULL;
 254 
 255     free(controld_globals.dc_name);
 256     controld_globals.dc_name = NULL;
 257 
 258     free(controld_globals.dc_version);
 259     controld_globals.dc_version = NULL;
 260 
 261     free(controld_globals.cluster_name);
 262     controld_globals.cluster_name = NULL;
 263 
 264     free(controld_globals.te_uuid);
 265     controld_globals.te_uuid = NULL;
 266 
 267     free_max_generation();
 268     controld_destroy_cib_replacements_table();
 269     controld_destroy_failed_sync_table();
 270     controld_destroy_outside_events_table();
 271 
 272     mainloop_destroy_signal(SIGPIPE);
 273     mainloop_destroy_signal(SIGUSR1);
 274     mainloop_destroy_signal(SIGTERM);
 275     mainloop_destroy_signal(SIGTRAP);
 276     /* leave SIGCHLD engaged as we might still want to drain some service-actions */
 277 
 278     if (mloop) {
 279         GMainContext *ctx = g_main_loop_get_context(controld_globals.mainloop);
 280 
 281         /* Don't re-enter this block */
 282         controld_globals.mainloop = NULL;
 283 
 284         /* no signals on final draining anymore */
 285         mainloop_destroy_signal(SIGCHLD);
 286 
 287         crm_trace("Draining mainloop %d %d", g_main_loop_is_running(mloop), g_main_context_pending(ctx));
 288 
 289         {
 290             int lpc = 0;
 291 
 292             while((g_main_context_pending(ctx) && lpc < 10)) {
 293                 lpc++;
 294                 crm_trace("Iteration %d", lpc);
 295                 g_main_context_dispatch(ctx);
 296             }
 297         }
 298 
 299         crm_trace("Closing mainloop %d %d", g_main_loop_is_running(mloop), g_main_context_pending(ctx));
 300         g_main_loop_quit(mloop);
 301 
 302         /* Won't do anything yet, since we're inside it now */
 303         g_main_loop_unref(mloop);
 304     } else {
 305         mainloop_destroy_signal(SIGCHLD);
 306     }
 307 
 308     cib_delete(controld_globals.cib_conn);
 309     controld_globals.cib_conn = NULL;
 310 
 311     throttle_fini();
 312 
 313     /* Graceful */
 314     crm_trace("Done preparing for exit with status %d (%s)",
 315               exit_code, crm_exit_str(exit_code));
 316     return exit_code;
 317 }
 318 
 319 /*       A_EXIT_0, A_EXIT_1     */
 320 void
 321 do_exit(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 322         enum crmd_fsa_cause cause,
 323         enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 324 {
 325     crm_exit_t exit_code = CRM_EX_OK;
 326     int log_level = LOG_INFO;
 327     const char *exit_type = "gracefully";
 328 
 329     if (action & A_EXIT_1) {
 330         log_level = LOG_ERR;
 331         exit_type = "forcefully";
 332         exit_code = CRM_EX_ERROR;
 333     }
 334 
 335     verify_stopped(cur_state, LOG_ERR);
 336     do_crm_log(log_level, "Performing %s - %s exiting the controller",
 337                fsa_action2string(action), exit_type);
 338 
 339     crm_info("[%s] stopped (%d)", crm_system_name, exit_code);
 340     crmd_exit(exit_code);
 341 }
 342 
 343 static void sigpipe_ignore(int nsig) { return; }
     /* [previous][next][first][last][top][bottom][index][help] */
 344 
 345 /*       A_STARTUP      */
 346 void
 347 do_startup(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 348            enum crmd_fsa_cause cause,
 349            enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 350 {
 351     crm_debug("Registering Signal Handlers");
 352     mainloop_add_signal(SIGTERM, crm_shutdown);
 353     mainloop_add_signal(SIGPIPE, sigpipe_ignore);
 354 
 355     config_read_trigger = mainloop_add_trigger(G_PRIORITY_HIGH,
 356                                                crm_read_options, NULL);
 357 
 358     controld_init_fsa_trigger();
 359     controld_init_transition_trigger();
 360 
 361     crm_debug("Creating CIB manager and executor objects");
 362     controld_globals.cib_conn = cib_new();
 363 
 364     lrm_state_init_local();
 365     if (controld_init_fsa_timers() == FALSE) {
 366         register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
 367     }
 368 }
 369 
 370 // \return libqb error code (0 on success, -errno on error)
 371 static int32_t
 372 accept_controller_client(qb_ipcs_connection_t *c, uid_t uid, gid_t gid)
     /* [previous][next][first][last][top][bottom][index][help] */
 373 {
 374     crm_trace("Accepting new IPC client connection");
 375     if (pcmk__new_client(c, uid, gid) == NULL) {
 376         return -EIO;
 377     }
 378     return 0;
 379 }
 380 
 381 // \return libqb error code (0 on success, -errno on error)
 382 static int32_t
 383 dispatch_controller_ipc(qb_ipcs_connection_t * c, void *data, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
 384 {
 385     uint32_t id = 0;
 386     uint32_t flags = 0;
 387     pcmk__client_t *client = pcmk__find_client(c);
 388 
 389     xmlNode *msg = pcmk__client_data2xml(client, data, &id, &flags);
 390 
 391     if (msg == NULL) {
 392         pcmk__ipc_send_ack(client, id, flags, "ack", NULL, CRM_EX_PROTOCOL);
 393         return 0;
 394     }
 395     pcmk__ipc_send_ack(client, id, flags, "ack", NULL, CRM_EX_INDETERMINATE);
 396 
 397     CRM_ASSERT(client->user != NULL);
 398     pcmk__update_acl_user(msg, F_CRM_USER, client->user);
 399 
 400     crm_xml_add(msg, F_CRM_SYS_FROM, client->id);
 401     if (controld_authorize_ipc_message(msg, client, NULL)) {
 402         crm_trace("Processing IPC message from client %s",
 403                   pcmk__client_name(client));
 404         route_message(C_IPC_MESSAGE, msg);
 405     }
 406 
 407     controld_trigger_fsa();
 408     free_xml(msg);
 409     return 0;
 410 }
 411 
 412 static int32_t
 413 ipc_client_disconnected(qb_ipcs_connection_t *c)
     /* [previous][next][first][last][top][bottom][index][help] */
 414 {
 415     pcmk__client_t *client = pcmk__find_client(c);
 416 
 417     if (client) {
 418         crm_trace("Disconnecting %sregistered client %s (%p/%p)",
 419                   (client->userdata? "" : "un"), pcmk__client_name(client),
 420                   c, client);
 421         free(client->userdata);
 422         pcmk__free_client(client);
 423         controld_trigger_fsa();
 424     }
 425     return 0;
 426 }
 427 
 428 static void
 429 ipc_connection_destroyed(qb_ipcs_connection_t *c)
     /* [previous][next][first][last][top][bottom][index][help] */
 430 {
 431     crm_trace("Connection %p", c);
 432     ipc_client_disconnected(c);
 433 }
 434 
 435 /*       A_STOP */
 436 void
 437 do_stop(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 438         enum crmd_fsa_cause cause,
 439         enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 440 {
 441     crm_trace("Closing IPC server");
 442     mainloop_del_ipc_server(ipcs); ipcs = NULL;
 443     register_fsa_input(C_FSA_INTERNAL, I_TERMINATE, NULL);
 444 }
 445 
 446 /*       A_STARTED      */
 447 void
 448 do_started(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 449            enum crmd_fsa_cause cause,
 450            enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 451 {
 452     static struct qb_ipcs_service_handlers crmd_callbacks = {
 453         .connection_accept = accept_controller_client,
 454         .connection_created = NULL,
 455         .msg_process = dispatch_controller_ipc,
 456         .connection_closed = ipc_client_disconnected,
 457         .connection_destroyed = ipc_connection_destroyed
 458     };
 459 
 460     if (cur_state != S_STARTING) {
 461         crm_err("Start cancelled... %s", fsa_state2string(cur_state));
 462         return;
 463 
 464     } else if (!pcmk_is_set(controld_globals.fsa_input_register,
 465                             R_MEMBERSHIP)) {
 466         crm_info("Delaying start, no membership data (%.16llx)", R_MEMBERSHIP);
 467 
 468         crmd_fsa_stall(TRUE);
 469         return;
 470 
 471     } else if (!pcmk_is_set(controld_globals.fsa_input_register,
 472                             R_LRM_CONNECTED)) {
 473         crm_info("Delaying start, not connected to executor (%.16llx)", R_LRM_CONNECTED);
 474 
 475         crmd_fsa_stall(TRUE);
 476         return;
 477 
 478     } else if (!pcmk_is_set(controld_globals.fsa_input_register,
 479                             R_CIB_CONNECTED)) {
 480         crm_info("Delaying start, CIB not connected (%.16llx)", R_CIB_CONNECTED);
 481 
 482         crmd_fsa_stall(TRUE);
 483         return;
 484 
 485     } else if (!pcmk_is_set(controld_globals.fsa_input_register,
 486                             R_READ_CONFIG)) {
 487         crm_info("Delaying start, Config not read (%.16llx)", R_READ_CONFIG);
 488 
 489         crmd_fsa_stall(TRUE);
 490         return;
 491 
 492     } else if (!pcmk_is_set(controld_globals.fsa_input_register, R_PEER_DATA)) {
 493 
 494         crm_info("Delaying start, No peer data (%.16llx)", R_PEER_DATA);
 495         crmd_fsa_stall(TRUE);
 496         return;
 497     }
 498 
 499     crm_debug("Init server comms");
 500     ipcs = pcmk__serve_controld_ipc(&crmd_callbacks);
 501     if (ipcs == NULL) {
 502         crm_err("Failed to create IPC server: shutting down and inhibiting respawn");
 503         register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
 504     } else {
 505         crm_notice("Pacemaker controller successfully started and accepting connections");
 506     }
 507     controld_trigger_fencer_connect();
 508 
 509     controld_clear_fsa_input_flags(R_STARTING);
 510     register_fsa_input(msg_data->fsa_cause, I_PENDING, NULL);
 511 }
 512 
 513 /*       A_RECOVER      */
 514 void
 515 do_recover(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 516            enum crmd_fsa_cause cause,
 517            enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 518 {
 519     controld_set_fsa_input_flags(R_IN_RECOVERY);
 520     crm_warn("Fast-tracking shutdown in response to errors");
 521 
 522     register_fsa_input(C_FSA_INTERNAL, I_TERMINATE, NULL);
 523 }
 524 
 525 static pcmk__cluster_option_t controller_options[] = {
 526     /* name, old name, type, allowed values,
 527      * default value, validator,
 528      * short description,
 529      * long description
 530      */
 531     {
 532         "dc-version", NULL, "string", NULL, PCMK__VALUE_NONE, NULL,
 533         N_("Pacemaker version on cluster node elected Designated Controller (DC)"),
 534         N_("Includes a hash which identifies the exact changeset the code was "
 535             "built from. Used for diagnostic purposes.")
 536     },
 537     {
 538         "cluster-infrastructure", NULL, "string", NULL, "corosync", NULL,
 539         N_("The messaging stack on which Pacemaker is currently running"),
 540         N_("Used for informational and diagnostic purposes.")
 541     },
 542     {
 543         "cluster-name", NULL, "string", NULL, NULL, NULL,
 544         N_("An arbitrary name for the cluster"),
 545         N_("This optional value is mostly for users' convenience as desired "
 546             "in administration, but may also be used in Pacemaker "
 547             "configuration rules via the #cluster-name node attribute, and "
 548             "by higher-level tools and resource agents.")
 549     },
 550     {
 551         XML_CONFIG_ATTR_DC_DEADTIME, NULL, "time",
 552         NULL, "20s", pcmk__valid_interval_spec,
 553         N_("How long to wait for a response from other nodes during start-up"),
 554         N_("The optimal value will depend on the speed and load of your network "
 555             "and the type of switches used.")
 556     },
 557     {
 558         XML_CONFIG_ATTR_RECHECK, NULL, "time",
 559         N_("Zero disables polling, while positive values are an interval in seconds"
 560             "(unless other units are specified, for example \"5min\")"),
 561         "15min", pcmk__valid_interval_spec,
 562         N_("Polling interval to recheck cluster state and evaluate rules "
 563             "with date specifications"),
 564         N_("Pacemaker is primarily event-driven, and looks ahead to know when to "
 565             "recheck cluster state for failure timeouts and most time-based "
 566             "rules. However, it will also recheck the cluster after this "
 567             "amount of inactivity, to evaluate rules with date specifications "
 568             "and serve as a fail-safe for certain types of scheduler bugs.")
 569     },
 570     {
 571         "load-threshold", NULL, "percentage", NULL,
 572         "80%", pcmk__valid_percentage,
 573         N_("Maximum amount of system load that should be used by cluster nodes"),
 574         N_("The cluster will slow down its recovery process when the amount of "
 575             "system resources used (currently CPU) approaches this limit"),
 576     },
 577     {
 578         "node-action-limit", NULL, "integer", NULL,
 579         "0", pcmk__valid_number,
 580         N_("Maximum number of jobs that can be scheduled per node "
 581             "(defaults to 2x cores)")
 582     },
 583     { XML_CONFIG_ATTR_FENCE_REACTION, NULL, "string", NULL, "stop", NULL,
 584         N_("How a cluster node should react if notified of its own fencing"),
 585         N_("A cluster node may receive notification of its own fencing if fencing "
 586         "is misconfigured, or if fabric fencing is in use that doesn't cut "
 587         "cluster communication. Allowed values are \"stop\" to attempt to "
 588         "immediately stop Pacemaker and stay stopped, or \"panic\" to attempt "
 589         "to immediately reboot the local node, falling back to stop on failure.")
 590     },
 591     {
 592         XML_CONFIG_ATTR_ELECTION_FAIL, NULL, "time", NULL,
 593         "2min", pcmk__valid_interval_spec,
 594         "*** Advanced Use Only ***",
 595         N_("Declare an election failed if it is not decided within this much "
 596             "time. If you need to adjust this value, it probably indicates "
 597             "the presence of a bug.")
 598     },
 599     {
 600         XML_CONFIG_ATTR_FORCE_QUIT, NULL, "time", NULL,
 601         "20min", pcmk__valid_interval_spec,
 602         "*** Advanced Use Only ***",
 603         N_("Exit immediately if shutdown does not complete within this much "
 604             "time. If you need to adjust this value, it probably indicates "
 605             "the presence of a bug.")
 606     },
 607     {
 608         "join-integration-timeout", "crmd-integration-timeout", "time", NULL,
 609         "3min", pcmk__valid_interval_spec,
 610         "*** Advanced Use Only ***",
 611         N_("If you need to adjust this value, it probably indicates "
 612             "the presence of a bug.")
 613     },
 614     {
 615         "join-finalization-timeout", "crmd-finalization-timeout", "time", NULL,
 616         "30min", pcmk__valid_interval_spec,
 617         "*** Advanced Use Only ***",
 618         N_("If you need to adjust this value, it probably indicates "
 619             "the presence of a bug.")
 620     },
 621     {
 622         "transition-delay", "crmd-transition-delay", "time", NULL,
 623         "0s", pcmk__valid_interval_spec,
 624         N_("*** Advanced Use Only *** Enabling this option will slow down "
 625             "cluster recovery under all conditions"),
 626         N_("Delay cluster recovery for this much time to allow for additional "
 627             "events to occur. Useful if your configuration is sensitive to "
 628             "the order in which ping updates arrive.")
 629     },
 630     {
 631         "stonith-watchdog-timeout", NULL, "time", NULL,
 632         "0", controld_verify_stonith_watchdog_timeout,
 633         N_("How long before nodes can be assumed to be safely down when "
 634            "watchdog-based self-fencing via SBD is in use"),
 635         N_("If this is set to a positive value, lost nodes are assumed to "
 636            "self-fence using watchdog-based SBD within this much time. This "
 637            "does not require a fencing resource to be explicitly configured, "
 638            "though a fence_watchdog resource can be configured, to limit use "
 639            "to specific nodes. If this is set to 0 (the default), the cluster "
 640            "will never assume watchdog-based self-fencing. If this is set to a "
 641            "negative value, the cluster will use twice the local value of the "
 642            "`SBD_WATCHDOG_TIMEOUT` environment variable if that is positive, "
 643            "or otherwise treat this as 0. WARNING: When used, this timeout "
 644            "must be larger than `SBD_WATCHDOG_TIMEOUT` on all nodes that use "
 645            "watchdog-based SBD, and Pacemaker will refuse to start on any of "
 646            "those nodes where this is not true for the local value or SBD is "
 647            "not active. When this is set to a negative value, "
 648            "`SBD_WATCHDOG_TIMEOUT` must be set to the same value on all nodes "
 649            "that use SBD, otherwise data corruption or loss could occur.")
 650     },
 651     {
 652         "stonith-max-attempts", NULL, "integer", NULL,
 653         "10", pcmk__valid_positive_number,
 654         N_("How many times fencing can fail before it will no longer be "
 655             "immediately re-attempted on a target")
 656     },
 657 
 658     // Already documented in libpe_status (other values must be kept identical)
 659     {
 660         "no-quorum-policy", NULL, "select",
 661         "stop, freeze, ignore, demote, suicide", "stop", pcmk__valid_quorum,
 662         N_("What to do when the cluster does not have quorum"), NULL
 663     },
 664     {
 665         XML_CONFIG_ATTR_SHUTDOWN_LOCK, NULL, "boolean", NULL,
 666         "false", pcmk__valid_boolean,
 667         N_("Whether to lock resources to a cleanly shut down node"),
 668         N_("When true, resources active on a node when it is cleanly shut down "
 669             "are kept \"locked\" to that node (not allowed to run elsewhere) "
 670             "until they start again on that node after it rejoins (or for at "
 671             "most shutdown-lock-limit, if set). Stonith resources and "
 672             "Pacemaker Remote connections are never locked. Clone and bundle "
 673             "instances and the promoted role of promotable clones are "
 674             "currently never locked, though support could be added in a future "
 675             "release.")
 676     },
 677     {
 678         XML_CONFIG_ATTR_SHUTDOWN_LOCK_LIMIT, NULL, "time", NULL,
 679         "0", pcmk__valid_interval_spec,
 680         N_("Do not lock resources to a cleanly shut down node longer than "
 681            "this"),
 682         N_("If shutdown-lock is true and this is set to a nonzero time "
 683             "duration, shutdown locks will expire after this much time has "
 684             "passed since the shutdown was initiated, even if the node has not "
 685             "rejoined.")
 686     },
 687 };
 688 
 689 void
 690 crmd_metadata(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 691 {
 692     const char *desc_short = "Pacemaker controller options";
 693     const char *desc_long = "Cluster options used by Pacemaker's controller";
 694 
 695     gchar *s = pcmk__format_option_metadata("pacemaker-controld", desc_short,
 696                                             desc_long, controller_options,
 697                                             PCMK__NELEM(controller_options));
 698     printf("%s", s);
 699     g_free(s);
 700 }
 701 
 702 static void
 703 config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 704 {
 705     const char *value = NULL;
 706     GHashTable *config_hash = NULL;
 707     crm_time_t *now = crm_time_new(NULL);
 708     xmlNode *crmconfig = NULL;
 709     xmlNode *alerts = NULL;
 710 
 711     if (rc != pcmk_ok) {
 712         fsa_data_t *msg_data = NULL;
 713 
 714         crm_err("Local CIB query resulted in an error: %s", pcmk_strerror(rc));
 715         register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
 716 
 717         if (rc == -EACCES || rc == -pcmk_err_schema_validation) {
 718             crm_err("The cluster is mis-configured - shutting down and staying down");
 719             controld_set_fsa_input_flags(R_STAYDOWN);
 720         }
 721         goto bail;
 722     }
 723 
 724     crmconfig = output;
 725     if ((crmconfig) &&
 726         (crm_element_name(crmconfig)) &&
 727         (strcmp(crm_element_name(crmconfig), XML_CIB_TAG_CRMCONFIG) != 0)) {
 728         crmconfig = first_named_child(crmconfig, XML_CIB_TAG_CRMCONFIG);
 729     }
 730     if (!crmconfig) {
 731         fsa_data_t *msg_data = NULL;
 732 
 733         crm_err("Local CIB query for " XML_CIB_TAG_CRMCONFIG " section failed");
 734         register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
 735         goto bail;
 736     }
 737 
 738     crm_debug("Call %d : Parsing CIB options", call_id);
 739     config_hash = pcmk__strkey_table(free, free);
 740     pe_unpack_nvpairs(crmconfig, crmconfig, XML_CIB_TAG_PROPSET, NULL,
 741                       config_hash, CIB_OPTIONS_FIRST, FALSE, now, NULL);
 742 
 743     // Validate all options, and use defaults if not already present in hash
 744     pcmk__validate_cluster_options(config_hash, controller_options,
 745                                    PCMK__NELEM(controller_options));
 746 
 747     value = g_hash_table_lookup(config_hash, "no-quorum-policy");
 748     if (pcmk__str_eq(value, "suicide", pcmk__str_casei) && pcmk__locate_sbd()) {
 749         controld_set_global_flags(controld_no_quorum_suicide);
 750     }
 751 
 752     value = g_hash_table_lookup(config_hash, XML_CONFIG_ATTR_SHUTDOWN_LOCK);
 753     if (crm_is_true(value)) {
 754         controld_set_global_flags(controld_shutdown_lock_enabled);
 755     } else {
 756         controld_clear_global_flags(controld_shutdown_lock_enabled);
 757     }
 758 
 759     value = g_hash_table_lookup(config_hash,
 760                                 XML_CONFIG_ATTR_SHUTDOWN_LOCK_LIMIT);
 761     controld_globals.shutdown_lock_limit = crm_parse_interval_spec(value)
 762                                            / 1000;
 763 
 764     value = g_hash_table_lookup(config_hash, "cluster-name");
 765     pcmk__str_update(&(controld_globals.cluster_name), value);
 766 
 767     // Let subcomponents initialize their own static variables
 768     controld_configure_election(config_hash);
 769     controld_configure_fencing(config_hash);
 770     controld_configure_fsa_timers(config_hash);
 771     controld_configure_throttle(config_hash);
 772 
 773     alerts = first_named_child(output, XML_CIB_TAG_ALERTS);
 774     crmd_unpack_alerts(alerts);
 775 
 776     controld_set_fsa_input_flags(R_READ_CONFIG);
 777     controld_trigger_fsa();
 778 
 779     g_hash_table_destroy(config_hash);
 780   bail:
 781     crm_time_free(now);
 782 }
 783 
 784 /*!
 785  * \internal
 786  * \brief Trigger read and processing of the configuration
 787  *
 788  * \param[in] fn    Calling function name
 789  * \param[in] line  Line number where call occurred
 790  */
 791 void
 792 controld_trigger_config_as(const char *fn, int line)
     /* [previous][next][first][last][top][bottom][index][help] */
 793 {
 794     if (config_read_trigger != NULL) {
 795         crm_trace("%s:%d - Triggered config processing", fn, line);
 796         mainloop_set_trigger(config_read_trigger);
 797     }
 798 }
 799 
 800 gboolean
 801 crm_read_options(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 802 {
 803     cib_t *cib_conn = controld_globals.cib_conn;
 804     int call_id = cib_conn->cmds->query(cib_conn,
 805                                         "//" XML_CIB_TAG_CRMCONFIG
 806                                         " | //" XML_CIB_TAG_ALERTS,
 807                                         NULL, cib_xpath|cib_scope_local);
 808 
 809     fsa_register_cib_callback(call_id, NULL, config_query_callback);
 810     crm_trace("Querying the CIB... call %d", call_id);
 811     return TRUE;
 812 }
 813 
 814 /*       A_READCONFIG   */
 815 void
 816 do_read_config(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 817                enum crmd_fsa_cause cause,
 818                enum crmd_fsa_state cur_state,
 819                enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 820 {
 821     throttle_init();
 822     controld_trigger_config();
 823 }
 824 
 825 void
 826 crm_shutdown(int nsig)
     /* [previous][next][first][last][top][bottom][index][help] */
 827 {
 828     const char *value = NULL;
 829     guint default_period_ms = 0;
 830 
 831     if ((controld_globals.mainloop == NULL)
 832         || !g_main_loop_is_running(controld_globals.mainloop)) {
 833         crmd_exit(CRM_EX_OK);
 834         return;
 835     }
 836 
 837     if (pcmk_is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
 838         crm_err("Escalating shutdown");
 839         register_fsa_input_before(C_SHUTDOWN, I_ERROR, NULL);
 840         return;
 841     }
 842 
 843     controld_set_fsa_input_flags(R_SHUTDOWN);
 844     register_fsa_input(C_SHUTDOWN, I_SHUTDOWN, NULL);
 845 
 846     /* If shutdown timer doesn't have a period set, use the default
 847      *
 848      * @TODO: Evaluate whether this is still necessary. As long as
 849      * config_query_callback() has been run at least once, it doesn't look like
 850      * anything could have changed the timer period since then.
 851      */
 852     value = pcmk__cluster_option(NULL, controller_options,
 853                                  PCMK__NELEM(controller_options),
 854                                  XML_CONFIG_ATTR_FORCE_QUIT);
 855     default_period_ms = crm_parse_interval_spec(value);
 856     controld_shutdown_start_countdown(default_period_ms);
 857 }

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