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. config_query_callback
  17. controld_trigger_config_as
  18. crm_read_options
  19. do_read_config
  20. crm_shutdown

   1 /*
   2  * Copyright 2004-2025 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/common/xml.h>
  18 #include <crm/cluster/internal.h>
  19 #include <crm/cluster/election_internal.h>
  20 #include <crm/common/ipc_internal.h>
  21 
  22 #include <pacemaker-controld.h>
  23 
  24 static qb_ipcs_service_t *ipcs = NULL;
  25 
  26 static crm_trigger_t *config_read_trigger = NULL;
  27 
  28 #if SUPPORT_COROSYNC
  29 extern gboolean crm_connect_corosync(pcmk_cluster_t *cluster);
  30 #endif
  31 
  32 static void crm_shutdown(int nsig);
  33 static gboolean crm_read_options(gpointer user_data);
  34 
  35 /*       A_HA_CONNECT   */
  36 void
  37 do_ha_control(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
  38               enum crmd_fsa_cause cause,
  39               enum crmd_fsa_state cur_state,
  40               enum crmd_fsa_input current_input, fsa_data_t * msg_data)
  41 {
  42     gboolean registered = FALSE;
  43 
  44     if (controld_globals.cluster == NULL) {
  45         controld_globals.cluster = pcmk_cluster_new();
  46     }
  47 
  48     if (action & A_HA_DISCONNECT) {
  49         pcmk_cluster_disconnect(controld_globals.cluster);
  50         crm_info("Disconnected from the cluster");
  51 
  52         controld_set_fsa_input_flags(R_HA_DISCONNECTED);
  53     }
  54 
  55     if (action & A_HA_CONNECT) {
  56         pcmk__cluster_set_status_callback(&peer_update_callback);
  57         pcmk__cluster_set_autoreap(false);
  58 
  59 #if SUPPORT_COROSYNC
  60         if (pcmk_get_cluster_layer() == pcmk_cluster_layer_corosync) {
  61             registered = crm_connect_corosync(controld_globals.cluster);
  62         }
  63 #endif // SUPPORT_COROSYNC
  64 
  65         if (registered) {
  66             pcmk__node_status_t *node = controld_get_local_node_status();
  67 
  68             controld_election_init();
  69 
  70             free(controld_globals.our_uuid);
  71             controld_globals.our_uuid =
  72                 pcmk__str_copy(pcmk__cluster_get_xml_id(node));
  73 
  74             if (controld_globals.our_uuid == NULL) {
  75                 crm_err("Could not obtain local uuid");
  76                 registered = FALSE;
  77             }
  78         }
  79 
  80         if (!registered) {
  81             controld_set_fsa_input_flags(R_HA_DISCONNECTED);
  82             register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
  83             return;
  84         }
  85 
  86         populate_cib_nodes(controld_node_update_none, __func__);
  87         controld_clear_fsa_input_flags(R_HA_DISCONNECTED);
  88         crm_info("Connected to the cluster");
  89     }
  90 
  91     if (action & ~(A_HA_CONNECT | A_HA_DISCONNECT)) {
  92         crm_err("Unexpected action %s in %s", fsa_action2string(action),
  93                 __func__);
  94     }
  95 }
  96 
  97 /*       A_SHUTDOWN     */
  98 void
  99 do_shutdown(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 100             enum crmd_fsa_cause cause,
 101             enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 102 {
 103     /* just in case */
 104     controld_set_fsa_input_flags(R_SHUTDOWN);
 105     controld_disconnect_fencer(FALSE);
 106 }
 107 
 108 /*       A_SHUTDOWN_REQ */
 109 void
 110 do_shutdown_req(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 111                 enum crmd_fsa_cause cause,
 112                 enum crmd_fsa_state cur_state,
 113                 enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 114 {
 115     xmlNode *msg = NULL;
 116 
 117     controld_set_fsa_input_flags(R_SHUTDOWN);
 118     //controld_set_fsa_input_flags(R_STAYDOWN);
 119     crm_info("Sending shutdown request to all peers (DC is %s)",
 120              pcmk__s(controld_globals.dc_name, "not set"));
 121     msg = pcmk__new_request(pcmk_ipc_controld, CRM_SYSTEM_CRMD, NULL,
 122                             CRM_SYSTEM_CRMD, CRM_OP_SHUTDOWN_REQ, NULL);
 123 
 124     if (!pcmk__cluster_send_message(NULL, pcmk_ipc_controld, msg)) {
 125         register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
 126     }
 127     pcmk__xml_free(msg);
 128 }
 129 
 130 void
 131 crmd_fast_exit(crm_exit_t exit_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 132 {
 133     if (pcmk_is_set(controld_globals.fsa_input_register, R_STAYDOWN)) {
 134         crm_warn("Inhibiting respawn " QB_XS " remapping exit code %d to %d",
 135                  exit_code, CRM_EX_FATAL);
 136         exit_code = CRM_EX_FATAL;
 137 
 138     } else if ((exit_code == CRM_EX_OK)
 139                && pcmk_is_set(controld_globals.fsa_input_register,
 140                               R_IN_RECOVERY)) {
 141         crm_err("Could not recover from internal error");
 142         exit_code = CRM_EX_ERROR;
 143     }
 144 
 145     if (controld_globals.logger_out != NULL) {
 146         controld_globals.logger_out->finish(controld_globals.logger_out,
 147                                             exit_code, true, NULL);
 148         pcmk__output_free(controld_globals.logger_out);
 149         controld_globals.logger_out = NULL;
 150     }
 151 
 152     crm_exit(exit_code);
 153 }
 154 
 155 crm_exit_t
 156 crmd_exit(crm_exit_t exit_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 157 {
 158     GMainLoop *mloop = controld_globals.mainloop;
 159 
 160     static bool in_progress = FALSE;
 161 
 162     if (in_progress && (exit_code == CRM_EX_OK)) {
 163         crm_debug("Exit is already in progress");
 164         return exit_code;
 165 
 166     } else if(in_progress) {
 167         crm_notice("Error during shutdown process, exiting now with status %d (%s)",
 168                    exit_code, crm_exit_str(exit_code));
 169         crm_write_blackbox(SIGTRAP, NULL);
 170         crmd_fast_exit(exit_code);
 171     }
 172 
 173     in_progress = TRUE;
 174     crm_trace("Preparing to exit with status %d (%s)",
 175               exit_code, crm_exit_str(exit_code));
 176 
 177     /* Suppress secondary errors resulting from us disconnecting everything */
 178     controld_set_fsa_input_flags(R_HA_DISCONNECTED);
 179 
 180 /* Close all IPC servers and clients to ensure any and all shared memory files are cleaned up */
 181 
 182     if(ipcs) {
 183         crm_trace("Closing IPC server");
 184         mainloop_del_ipc_server(ipcs);
 185         ipcs = NULL;
 186     }
 187 
 188     controld_close_attrd_ipc();
 189     controld_shutdown_schedulerd_ipc();
 190     controld_disconnect_fencer(TRUE);
 191 
 192     if ((exit_code == CRM_EX_OK) && (controld_globals.mainloop == NULL)) {
 193         crm_debug("No mainloop detected");
 194         exit_code = CRM_EX_ERROR;
 195     }
 196 
 197     /* On an error, just get out.
 198      *
 199      * Otherwise, make the effort to have mainloop exit gracefully so
 200      * that it (mostly) cleans up after itself and valgrind has less
 201      * to report on - allowing real errors stand out
 202      */
 203     if (exit_code != CRM_EX_OK) {
 204         crm_notice("Forcing immediate exit with status %d (%s)",
 205                    exit_code, crm_exit_str(exit_code));
 206         crm_write_blackbox(SIGTRAP, NULL);
 207         crmd_fast_exit(exit_code);
 208     }
 209 
 210 /* Clean up as much memory as possible for valgrind */
 211 
 212     for (GList *iter = controld_globals.fsa_message_queue; iter != NULL;
 213          iter = iter->next) {
 214         fsa_data_t *fsa_data = (fsa_data_t *) iter->data;
 215 
 216         crm_info("Dropping %s: [ state=%s cause=%s origin=%s ]",
 217                  fsa_input2string(fsa_data->fsa_input),
 218                  fsa_state2string(controld_globals.fsa_state),
 219                  fsa_cause2string(fsa_data->fsa_cause), fsa_data->origin);
 220         delete_fsa_input(fsa_data);
 221     }
 222 
 223     controld_clear_fsa_input_flags(R_MEMBERSHIP);
 224 
 225     g_list_free(controld_globals.fsa_message_queue);
 226     controld_globals.fsa_message_queue = NULL;
 227 
 228     controld_free_node_pending_timers();
 229     election_reset(controld_globals.cluster); // Stop any election timer
 230 
 231     /* Tear down the CIB manager connection, but don't free it yet -- it could
 232      * be used when we drain the mainloop later.
 233      */
 234 
 235     controld_disconnect_cib_manager();
 236 
 237     verify_stopped(controld_globals.fsa_state, LOG_WARNING);
 238     controld_clear_fsa_input_flags(R_LRM_CONNECTED);
 239     lrm_state_destroy_all();
 240 
 241     mainloop_destroy_trigger(config_read_trigger);
 242     config_read_trigger = NULL;
 243 
 244     controld_destroy_fsa_trigger();
 245     controld_destroy_transition_trigger();
 246 
 247     pcmk__client_cleanup();
 248     pcmk__cluster_destroy_node_caches();
 249 
 250     controld_free_fsa_timers();
 251     te_cleanup_stonith_history_sync(NULL, TRUE);
 252     controld_free_sched_timer();
 253 
 254     free(controld_globals.our_uuid);
 255     controld_globals.our_uuid = NULL;
 256 
 257     free(controld_globals.dc_name);
 258     controld_globals.dc_name = NULL;
 259 
 260     free(controld_globals.dc_version);
 261     controld_globals.dc_version = NULL;
 262 
 263     free(controld_globals.cluster_name);
 264     controld_globals.cluster_name = NULL;
 265 
 266     free(controld_globals.te_uuid);
 267     controld_globals.te_uuid = NULL;
 268 
 269     free_max_generation();
 270     controld_destroy_failed_sync_table();
 271     controld_destroy_outside_events_table();
 272 
 273     mainloop_destroy_signal(SIGPIPE);
 274     mainloop_destroy_signal(SIGUSR1);
 275     mainloop_destroy_signal(SIGTERM);
 276     mainloop_destroy_signal(SIGTRAP);
 277     /* leave SIGCHLD engaged as we might still want to drain some service-actions */
 278 
 279     if (mloop) {
 280         GMainContext *ctx = g_main_loop_get_context(controld_globals.mainloop);
 281 
 282         /* Don't re-enter this block */
 283         controld_globals.mainloop = NULL;
 284 
 285         /* no signals on final draining anymore */
 286         mainloop_destroy_signal(SIGCHLD);
 287 
 288         crm_trace("Draining mainloop %d %d", g_main_loop_is_running(mloop), g_main_context_pending(ctx));
 289 
 290         {
 291             int lpc = 0;
 292 
 293             while((g_main_context_pending(ctx) && lpc < 10)) {
 294                 lpc++;
 295                 crm_trace("Iteration %d", lpc);
 296                 g_main_context_dispatch(ctx);
 297             }
 298         }
 299 
 300         crm_trace("Closing mainloop %d %d", g_main_loop_is_running(mloop), g_main_context_pending(ctx));
 301         g_main_loop_quit(mloop);
 302 
 303         /* Won't do anything yet, since we're inside it now */
 304         g_main_loop_unref(mloop);
 305     } else {
 306         mainloop_destroy_signal(SIGCHLD);
 307     }
 308 
 309     cib_delete(controld_globals.cib_conn);
 310     controld_globals.cib_conn = NULL;
 311 
 312     throttle_fini();
 313 
 314     pcmk_cluster_free(controld_globals.cluster);
 315     controld_globals.cluster = NULL;
 316 
 317     /* Graceful */
 318     crm_trace("Done preparing for exit with status %d (%s)",
 319               exit_code, crm_exit_str(exit_code));
 320     return exit_code;
 321 }
 322 
 323 /*       A_EXIT_0, A_EXIT_1     */
 324 void
 325 do_exit(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 326         enum crmd_fsa_cause cause,
 327         enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 328 {
 329     crm_exit_t exit_code = CRM_EX_OK;
 330 
 331     if (pcmk_is_set(action, A_EXIT_1)) {
 332         exit_code = CRM_EX_ERROR;
 333         crm_err("Exiting now due to errors");
 334     }
 335     verify_stopped(cur_state, LOG_ERR);
 336     crmd_exit(exit_code);
 337 }
 338 
 339 static void sigpipe_ignore(int nsig) { return; }
     /* [previous][next][first][last][top][bottom][index][help] */
 340 
 341 /*       A_STARTUP      */
 342 void
 343 do_startup(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 344            enum crmd_fsa_cause cause,
 345            enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 346 {
 347     crm_debug("Registering Signal Handlers");
 348     mainloop_add_signal(SIGTERM, crm_shutdown);
 349     mainloop_add_signal(SIGPIPE, sigpipe_ignore);
 350 
 351     config_read_trigger = mainloop_add_trigger(G_PRIORITY_HIGH,
 352                                                crm_read_options, NULL);
 353 
 354     controld_init_fsa_trigger();
 355     controld_init_transition_trigger();
 356 
 357     crm_debug("Creating CIB manager and executor objects");
 358     controld_globals.cib_conn = cib_new();
 359 
 360     lrm_state_init_local();
 361     if (controld_init_fsa_timers() == FALSE) {
 362         register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
 363     }
 364 }
 365 
 366 // \return libqb error code (0 on success, -errno on error)
 367 static int32_t
 368 accept_controller_client(qb_ipcs_connection_t *c, uid_t uid, gid_t gid)
     /* [previous][next][first][last][top][bottom][index][help] */
 369 {
 370     crm_trace("Accepting new IPC client connection");
 371     if (pcmk__new_client(c, uid, gid) == NULL) {
 372         return -ENOMEM;
 373     }
 374     return 0;
 375 }
 376 
 377 // \return libqb error code (0 on success, -errno on error)
 378 static int32_t
 379 dispatch_controller_ipc(qb_ipcs_connection_t * c, void *data, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
 380 {
 381     int rc = pcmk_rc_ok;
 382     uint32_t id = 0;
 383     uint32_t flags = 0;
 384     pcmk__client_t *client = pcmk__find_client(c);
 385     xmlNode *msg = NULL;
 386 
 387     rc = pcmk__ipc_msg_append(&client->buffer, data);
 388 
 389     if (rc == pcmk_rc_ipc_more) {
 390         /* We haven't read the complete message yet, so just return. */
 391         return 0;
 392 
 393     } else if (rc == pcmk_rc_ok) {
 394         /* We've read the complete message and there's already a header on
 395          * the front.  Pass it off for processing.
 396          */
 397         msg = pcmk__client_data2xml(client, &id, &flags);
 398         g_byte_array_free(client->buffer, TRUE);
 399         client->buffer = NULL;
 400 
 401     } else {
 402         /* Some sort of error occurred reassembling the message.  All we can
 403          * do is clean up, log an error and return.
 404          */
 405         crm_err("Error when reading IPC message: %s", pcmk_rc_str(rc));
 406 
 407         if (client->buffer != NULL) {
 408             g_byte_array_free(client->buffer, TRUE);
 409             client->buffer = NULL;
 410         }
 411 
 412         return 0;
 413     }
 414 
 415     if (msg == NULL) {
 416         pcmk__ipc_send_ack(client, id, flags, PCMK__XE_ACK, NULL,
 417                            CRM_EX_PROTOCOL);
 418         return 0;
 419     }
 420     pcmk__ipc_send_ack(client, id, flags, PCMK__XE_ACK, NULL,
 421                        CRM_EX_INDETERMINATE);
 422 
 423     pcmk__assert(client->user != NULL);
 424     pcmk__update_acl_user(msg, PCMK__XA_CRM_USER, client->user);
 425 
 426     crm_xml_add(msg, PCMK__XA_CRM_SYS_FROM, client->id);
 427     if (controld_authorize_ipc_message(msg, client, NULL)) {
 428         crm_trace("Processing IPC message from client %s",
 429                   pcmk__client_name(client));
 430         route_message(C_IPC_MESSAGE, msg);
 431     }
 432 
 433     controld_trigger_fsa();
 434     pcmk__xml_free(msg);
 435     return 0;
 436 }
 437 
 438 static int32_t
 439 ipc_client_disconnected(qb_ipcs_connection_t *c)
     /* [previous][next][first][last][top][bottom][index][help] */
 440 {
 441     pcmk__client_t *client = pcmk__find_client(c);
 442 
 443     if (client) {
 444         crm_trace("Disconnecting %sregistered client %s (%p/%p)",
 445                   (client->userdata? "" : "un"), pcmk__client_name(client),
 446                   c, client);
 447         free(client->userdata);
 448         pcmk__free_client(client);
 449         controld_trigger_fsa();
 450     }
 451     return 0;
 452 }
 453 
 454 static void
 455 ipc_connection_destroyed(qb_ipcs_connection_t *c)
     /* [previous][next][first][last][top][bottom][index][help] */
 456 {
 457     crm_trace("Connection %p", c);
 458     ipc_client_disconnected(c);
 459 }
 460 
 461 /*       A_STOP */
 462 void
 463 do_stop(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 464         enum crmd_fsa_cause cause,
 465         enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 466 {
 467     crm_trace("Closing IPC server");
 468     mainloop_del_ipc_server(ipcs); ipcs = NULL;
 469     register_fsa_input(C_FSA_INTERNAL, I_TERMINATE, NULL);
 470 }
 471 
 472 /*       A_STARTED      */
 473 void
 474 do_started(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 475            enum crmd_fsa_cause cause,
 476            enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 477 {
 478     static struct qb_ipcs_service_handlers crmd_callbacks = {
 479         .connection_accept = accept_controller_client,
 480         .connection_created = NULL,
 481         .msg_process = dispatch_controller_ipc,
 482         .connection_closed = ipc_client_disconnected,
 483         .connection_destroyed = ipc_connection_destroyed
 484     };
 485 
 486     if (cur_state != S_STARTING) {
 487         crm_err("Start cancelled... %s", fsa_state2string(cur_state));
 488         return;
 489 
 490     } else if (!pcmk_is_set(controld_globals.fsa_input_register,
 491                             R_MEMBERSHIP)) {
 492         crm_info("Delaying start, no membership data (%.16llx)", R_MEMBERSHIP);
 493 
 494         crmd_fsa_stall(TRUE);
 495         return;
 496 
 497     } else if (!pcmk_is_set(controld_globals.fsa_input_register,
 498                             R_LRM_CONNECTED)) {
 499         crm_info("Delaying start, not connected to executor (%.16llx)", R_LRM_CONNECTED);
 500 
 501         crmd_fsa_stall(TRUE);
 502         return;
 503 
 504     } else if (!pcmk_is_set(controld_globals.fsa_input_register,
 505                             R_CIB_CONNECTED)) {
 506         crm_info("Delaying start, CIB not connected (%.16llx)", R_CIB_CONNECTED);
 507 
 508         crmd_fsa_stall(TRUE);
 509         return;
 510 
 511     } else if (!pcmk_is_set(controld_globals.fsa_input_register,
 512                             R_READ_CONFIG)) {
 513         crm_info("Delaying start, Config not read (%.16llx)", R_READ_CONFIG);
 514 
 515         crmd_fsa_stall(TRUE);
 516         return;
 517 
 518     } else if (!pcmk_is_set(controld_globals.fsa_input_register, R_PEER_DATA)) {
 519 
 520         crm_info("Delaying start, No peer data (%.16llx)", R_PEER_DATA);
 521         crmd_fsa_stall(TRUE);
 522         return;
 523     }
 524 
 525     crm_debug("Init server comms");
 526     ipcs = pcmk__serve_controld_ipc(&crmd_callbacks);
 527     if (ipcs == NULL) {
 528         crm_err("Failed to create IPC server: shutting down and inhibiting respawn");
 529         register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
 530     } else {
 531         crm_notice("Pacemaker controller successfully started and accepting connections");
 532     }
 533     controld_set_fsa_input_flags(R_ST_REQUIRED);
 534     controld_timer_fencer_connect(GINT_TO_POINTER(TRUE));
 535 
 536     controld_clear_fsa_input_flags(R_STARTING);
 537     register_fsa_input(msg_data->fsa_cause, I_PENDING, NULL);
 538 }
 539 
 540 /*       A_RECOVER      */
 541 void
 542 do_recover(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 543            enum crmd_fsa_cause cause,
 544            enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 545 {
 546     controld_set_fsa_input_flags(R_IN_RECOVERY);
 547     crm_warn("Fast-tracking shutdown in response to errors");
 548 
 549     register_fsa_input(C_FSA_INTERNAL, I_TERMINATE, NULL);
 550 }
 551 
 552 static void
 553 config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 554 {
 555     const char *value = NULL;
 556     GHashTable *config_hash = NULL;
 557     crm_time_t *now = crm_time_new(NULL);
 558     xmlNode *crmconfig = NULL;
 559     xmlNode *alerts = NULL;
 560     pcmk_rule_input_t rule_input = {
 561         .now = now,
 562     };
 563 
 564     if (rc != pcmk_ok) {
 565         fsa_data_t *msg_data = NULL;
 566 
 567         crm_err("Local CIB query resulted in an error: %s", pcmk_strerror(rc));
 568         register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
 569 
 570         if (rc == -EACCES || rc == -pcmk_err_schema_validation) {
 571             crm_err("The cluster is mis-configured - shutting down and staying down");
 572             controld_set_fsa_input_flags(R_STAYDOWN);
 573         }
 574         goto bail;
 575     }
 576 
 577     crmconfig = output;
 578     if ((crmconfig != NULL) && !pcmk__xe_is(crmconfig, PCMK_XE_CRM_CONFIG)) {
 579         crmconfig = pcmk__xe_first_child(crmconfig, PCMK_XE_CRM_CONFIG, NULL,
 580                                          NULL);
 581     }
 582     if (!crmconfig) {
 583         fsa_data_t *msg_data = NULL;
 584 
 585         crm_err("Local CIB query for " PCMK_XE_CRM_CONFIG " section failed");
 586         register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
 587         goto bail;
 588     }
 589 
 590     crm_debug("Call %d : Parsing CIB options", call_id);
 591     config_hash = pcmk__strkey_table(free, free);
 592     pcmk_unpack_nvpair_blocks(crmconfig, PCMK_XE_CLUSTER_PROPERTY_SET,
 593                               PCMK_VALUE_CIB_BOOTSTRAP_OPTIONS, &rule_input,
 594                               config_hash, NULL);
 595 
 596     // Validate all options, and use defaults if not already present in hash
 597     pcmk__validate_cluster_options(config_hash);
 598 
 599     /* Validate the watchdog timeout in the context of the local node
 600      * environment. If invalid, the controller will exit with a fatal error.
 601      *
 602      * We do this via a wrapper in the controller, so that we call
 603      * pcmk__valid_stonith_watchdog_timeout() only if watchdog fencing is
 604      * enabled for the local node. Otherwise, we may exit unnecessarily.
 605      *
 606      * A validator function in libcrmcommon can't act as such a wrapper, because
 607      * it doesn't have a stonith API connection or the local node name.
 608      */
 609     value = g_hash_table_lookup(config_hash, PCMK_OPT_STONITH_WATCHDOG_TIMEOUT);
 610     controld_verify_stonith_watchdog_timeout(value);
 611 
 612     value = g_hash_table_lookup(config_hash, PCMK_OPT_NO_QUORUM_POLICY);
 613     if (pcmk__strcase_any_of(value, PCMK_VALUE_FENCE, PCMK_VALUE_FENCE_LEGACY,
 614                              NULL)
 615         && (pcmk__locate_sbd() != 0)) {
 616         controld_set_global_flags(controld_no_quorum_panic);
 617     }
 618 
 619     value = g_hash_table_lookup(config_hash, PCMK_OPT_SHUTDOWN_LOCK);
 620     if (crm_is_true(value)) {
 621         controld_set_global_flags(controld_shutdown_lock_enabled);
 622     } else {
 623         controld_clear_global_flags(controld_shutdown_lock_enabled);
 624     }
 625 
 626     value = g_hash_table_lookup(config_hash, PCMK_OPT_SHUTDOWN_LOCK_LIMIT);
 627     pcmk_parse_interval_spec(value, &controld_globals.shutdown_lock_limit);
 628     controld_globals.shutdown_lock_limit /= 1000;
 629 
 630     value = g_hash_table_lookup(config_hash, PCMK_OPT_NODE_PENDING_TIMEOUT);
 631     pcmk_parse_interval_spec(value, &controld_globals.node_pending_timeout);
 632     controld_globals.node_pending_timeout /= 1000;
 633 
 634     value = g_hash_table_lookup(config_hash, PCMK_OPT_CLUSTER_NAME);
 635     pcmk__str_update(&(controld_globals.cluster_name), value);
 636 
 637     // Let subcomponents initialize their own static variables
 638     controld_configure_election(config_hash);
 639     controld_configure_fencing(config_hash);
 640     controld_configure_fsa_timers(config_hash);
 641     controld_configure_throttle(config_hash);
 642 
 643     alerts = pcmk__xe_first_child(output, PCMK_XE_ALERTS, NULL, NULL);
 644     crmd_unpack_alerts(alerts);
 645 
 646     controld_set_fsa_input_flags(R_READ_CONFIG);
 647     controld_trigger_fsa();
 648 
 649     g_hash_table_destroy(config_hash);
 650   bail:
 651     crm_time_free(now);
 652 }
 653 
 654 /*!
 655  * \internal
 656  * \brief Trigger read and processing of the configuration
 657  *
 658  * \param[in] fn    Calling function name
 659  * \param[in] line  Line number where call occurred
 660  */
 661 void
 662 controld_trigger_config_as(const char *fn, int line)
     /* [previous][next][first][last][top][bottom][index][help] */
 663 {
 664     if (config_read_trigger != NULL) {
 665         crm_trace("%s:%d - Triggered config processing", fn, line);
 666         mainloop_set_trigger(config_read_trigger);
 667     }
 668 }
 669 
 670 gboolean
 671 crm_read_options(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 672 {
 673     cib_t *cib_conn = controld_globals.cib_conn;
 674     int call_id = cib_conn->cmds->query(cib_conn,
 675                                         "//" PCMK_XE_CRM_CONFIG
 676                                         " | //" PCMK_XE_ALERTS,
 677                                         NULL, cib_xpath);
 678 
 679     fsa_register_cib_callback(call_id, NULL, config_query_callback);
 680     crm_trace("Querying the CIB... call %d", call_id);
 681     return TRUE;
 682 }
 683 
 684 /*       A_READCONFIG   */
 685 void
 686 do_read_config(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 687                enum crmd_fsa_cause cause,
 688                enum crmd_fsa_state cur_state,
 689                enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 690 {
 691     throttle_init();
 692     controld_trigger_config();
 693 }
 694 
 695 static void
 696 crm_shutdown(int nsig)
     /* [previous][next][first][last][top][bottom][index][help] */
 697 {
 698     const char *value = NULL;
 699     guint default_period_ms = 0;
 700 
 701     if ((controld_globals.mainloop == NULL)
 702         || !g_main_loop_is_running(controld_globals.mainloop)) {
 703         crmd_exit(CRM_EX_OK);
 704         return;
 705     }
 706 
 707     if (pcmk_is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
 708         crm_err("Escalating shutdown");
 709         register_fsa_input_before(C_SHUTDOWN, I_ERROR, NULL);
 710         return;
 711     }
 712 
 713     controld_set_fsa_input_flags(R_SHUTDOWN);
 714     register_fsa_input(C_SHUTDOWN, I_SHUTDOWN, NULL);
 715 
 716     /* If shutdown timer doesn't have a period set, use the default
 717      *
 718      * @TODO: Evaluate whether this is still necessary. As long as
 719      * config_query_callback() has been run at least once, it doesn't look like
 720      * anything could have changed the timer period since then.
 721      */
 722     value = pcmk__cluster_option(NULL, PCMK_OPT_SHUTDOWN_ESCALATION);
 723     pcmk_parse_interval_spec(value, &default_period_ms);
 724     controld_shutdown_start_countdown(default_period_ms);
 725 }

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