diff --git a/daemons/controld/controld_election.c b/daemons/controld/controld_election.c index a13cdbdac1..2ec5882486 100644 --- a/daemons/controld/controld_election.c +++ b/daemons/controld/controld_election.c @@ -1,280 +1,279 @@ /* * Copyright 2004-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include #include #include static void election_win_cb(pcmk_cluster_t *cluster) { register_fsa_input(C_FSA_INTERNAL, I_ELECTION_DC, NULL); } void controld_election_init(void) { election_init(controld_globals.cluster, election_win_cb); } /*! * \internal * \brief Configure election options based on the CIB * * \param[in,out] options Name/value pairs for configured options */ void controld_configure_election(GHashTable *options) { const char *value = g_hash_table_lookup(options, PCMK_OPT_ELECTION_TIMEOUT); guint interval_ms = 0U; pcmk_parse_interval_spec(value, &interval_ms); election_timeout_set_period(controld_globals.cluster, interval_ms); } void controld_remove_voter(const char *uname) { election_remove(controld_globals.cluster, uname); if (pcmk__str_eq(uname, controld_globals.dc_name, pcmk__str_casei)) { /* Clear any election dampening in effect. Otherwise, if the lost DC had * just won, an immediate new election could fizzle out with no new DC. */ election_clear_dampening(controld_globals.cluster); } } void controld_stop_current_election_timeout(void) { election_timeout_stop(controld_globals.cluster); } /* A_ELECTION_VOTE */ void do_election_vote(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data) { gboolean not_voting = FALSE; /* don't vote if we're in one of these states or wanting to shut down */ switch (cur_state) { case S_STARTING: case S_RECOVERY: case S_STOPPING: case S_TERMINATE: crm_warn("Not voting in election, we're in state %s", fsa_state2string(cur_state)); not_voting = TRUE; break; case S_ELECTION: case S_INTEGRATION: case S_RELEASE_DC: break; default: crm_err("Broken? Voting in state %s", fsa_state2string(cur_state)); break; } if (not_voting == FALSE) { if (pcmk__is_set(controld_globals.fsa_input_register, R_STARTING)) { not_voting = TRUE; } } if (not_voting) { if (AM_I_DC) { register_fsa_input(C_FSA_INTERNAL, I_RELEASE_DC, NULL); } else { register_fsa_input(C_FSA_INTERNAL, I_PENDING, NULL); } return; } election_vote(controld_globals.cluster); return; } void do_election_check(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data) { if (controld_globals.fsa_state == S_ELECTION) { election_check(controld_globals.cluster); } else { crm_debug("Ignoring election check because we are not in an election"); } } /* A_ELECTION_COUNT */ void do_election_count_vote(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data) { enum election_result rc = 0; ha_msg_input_t *vote = fsa_typed_data(fsa_dt_ha_msg); if (pcmk__peer_cache == NULL) { if (!pcmk__is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) { crm_err("Internal error, no peer cache"); } return; } rc = election_count_vote(controld_globals.cluster, vote->msg, (cur_state != S_STARTING)); switch(rc) { case election_start: election_reset(controld_globals.cluster); register_fsa_input(C_FSA_INTERNAL, I_ELECTION, NULL); break; case election_lost: update_dc(NULL); if (pcmk__is_set(controld_globals.fsa_input_register, R_THE_DC)) { cib_t *cib_conn = controld_globals.cib_conn; register_fsa_input(C_FSA_INTERNAL, I_RELEASE_DC, NULL); cib_conn->cmds->set_secondary(cib_conn, cib_none); } else if (cur_state != S_STARTING) { register_fsa_input(C_FSA_INTERNAL, I_PENDING, NULL); } break; default: crm_trace("Election message resulted in state %d", rc); } } static void feature_update_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data) { if (rc != pcmk_ok) { fsa_data_t *msg_data = NULL; crm_notice("Feature update failed: %s " QB_XS " rc=%d", pcmk_strerror(rc), rc); register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL); } } /*! * \internal * \brief Update a node attribute in the CIB during a DC takeover * * \param[in] name Name of attribute to update * \param[in] value New attribute value */ #define dc_takeover_update_attr(name, value) do { \ cib__update_node_attr(controld_globals.logger_out, \ controld_globals.cib_conn, cib_none, \ PCMK_XE_CRM_CONFIG, NULL, NULL, NULL, NULL, \ name, value, NULL, NULL); \ } while (0) /* A_DC_TAKEOVER */ void do_dc_takeover(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data) { xmlNode *cib = NULL; const enum pcmk_cluster_layer cluster_layer = pcmk_get_cluster_layer(); const char *cluster_layer_s = pcmk_cluster_layer_text(cluster_layer); pid_t watchdog = pcmk__locate_sbd(); crm_info("Taking over DC status for this partition"); controld_set_fsa_input_flags(R_THE_DC); controld_execute_fencing_cleanup(); election_reset(controld_globals.cluster); - controld_set_fsa_input_flags(R_JOIN_OK|R_INVOKE_PE); controld_globals.cib_conn->cmds->set_primary(controld_globals.cib_conn, cib_none); cib = pcmk__xe_create(NULL, PCMK_XE_CIB); pcmk__xe_set(cib, PCMK_XA_CRM_FEATURE_SET, CRM_FEATURE_SET); controld_update_cib(PCMK_XE_CIB, cib, cib_none, feature_update_callback); dc_takeover_update_attr(PCMK_OPT_HAVE_WATCHDOG, pcmk__btoa(watchdog)); dc_takeover_update_attr(PCMK_OPT_DC_VERSION, PACEMAKER_VERSION "-" BUILD_VERSION); dc_takeover_update_attr(PCMK_OPT_CLUSTER_INFRASTRUCTURE, cluster_layer_s); #if SUPPORT_COROSYNC if ((controld_globals.cluster_name == NULL) && (pcmk_get_cluster_layer() == pcmk_cluster_layer_corosync)) { char *cluster_name = pcmk__corosync_cluster_name(); if (cluster_name != NULL) { dc_takeover_update_attr(PCMK_OPT_CLUSTER_NAME, cluster_name); } free(cluster_name); } #endif controld_trigger_config(); pcmk__xml_free(cib); } /* A_DC_RELEASE */ void do_dc_release(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data) { if (action & A_DC_RELEASE) { crm_debug("Releasing the role of DC"); controld_clear_fsa_input_flags(R_THE_DC); controld_expect_sched_reply(NULL); } else if (action & A_DC_RELEASED) { crm_info("DC role released"); if (pcmk__is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) { xmlNode *update = NULL; pcmk__node_status_t *node = controld_get_local_node_status(); pcmk__update_peer_expected(__func__, node, CRMD_JOINSTATE_DOWN); update = create_node_state_update(node, controld_node_update_expected, NULL, __func__); /* Don't need a based response because controld will stop. */ fsa_cib_anon_update_discard_reply(PCMK_XE_STATUS, update); pcmk__xml_free(update); } register_fsa_input(C_FSA_INTERNAL, I_RELEASE_SUCCESS, NULL); } else { crm_err("Unknown DC action %s", fsa_action2string(action)); } crm_trace("Am I still the DC? %s", pcmk__btoa(AM_I_DC)); } diff --git a/daemons/controld/controld_fsa.h b/daemons/controld/controld_fsa.h index c60a05fff7..2fbddde38b 100644 --- a/daemons/controld/controld_fsa.h +++ b/daemons/controld/controld_fsa.h @@ -1,733 +1,694 @@ /* * Copyright 2004-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #ifndef CRMD_FSA__H # define CRMD_FSA__H # include // UINT64_C, PRIx64 # include # include # include # include # include # include # include /*! States the controller can be in */ enum crmd_fsa_state { S_IDLE = 0, /* Nothing happening */ S_ELECTION, /* Take part in the election algorithm as * described below */ S_INTEGRATION, /* integrate that status of new nodes (which is * all of them if we have just been elected DC) * to form a complete and up-to-date picture of * the CIB */ S_FINALIZE_JOIN, /* integrate that status of new nodes (which is * all of them if we have just been elected DC) * to form a complete and up-to-date picture of * the CIB */ S_NOT_DC, /* we are in non-DC mode */ S_POLICY_ENGINE, /* Determine next stable state of the cluster */ S_RECOVERY, /* Something bad happened, check everything is ok * before continuing and attempt to recover if * required */ S_RELEASE_DC, /* we were the DC, but now we arent anymore, * possibly by our own request, and we should * release all unnecessary sub-systems, finish * any pending actions, do general cleanup and * unset anything that makes us think we are * special :) */ S_STARTING, /* we are just starting out */ S_PENDING, /* we are not a full/active member yet */ S_STOPPING, /* We are in the final stages of shutting down */ S_TERMINATE, /* We are going to shutdown, this is the equiv of * "Sending TERM signal to all processes" in Linux * and in worst case scenarios could be considered * self-fencing */ S_TRANSITION_ENGINE, /* Attempt to make the calculated next stable * state of the cluster a reality */ S_HALT, /* Freeze - don't do anything * Something bad happened that needs the admin to fix * Wait for I_ELECTION */ /* ----------- Last input found in table is above ---------- */ S_ILLEGAL /* This is an illegal FSA state */ /* (must be last) */ }; # define MAXSTATE S_ILLEGAL /* Once we start and do some basic sanity checks, we go into the S_NOT_DC state and await instructions from the DC or input from the cluster layer which indicates the election algorithm needs to run. If the election algorithm is triggered, we enter the S_ELECTION state from where we can either go back to the S_NOT_DC state or progress to the S_INTEGRATION state (or S_RELEASE_DC if we used to be the DC but aren't anymore). See the libcrmcluster API documentation for more information about the election algorithm. Once the election is complete, if we are the DC, we enter the S_INTEGRATION state which is a DC-in-waiting style state. We are the DC, but we shouldn't do anything yet because we may not have an up-to-date picture of the cluster. There may of course be times when this fails, so we should go back to the S_RECOVERY stage and check everything is ok. We may also end up here if a new node came online, since each node is authoritative about itself, and we would want to incorporate its information into the CIB. Once we have the latest CIB, we then enter the S_POLICY_ENGINE state where invoke the scheduler. It is possible that between invoking the scheduler and receiving an answer, that we receive more input. In this case, we would discard the orginal result and invoke it again. Once we are satisfied with the output from the scheduler, we enter S_TRANSITION_ENGINE and feed the scheduler's output to the Transition Engine who attempts to make the scheduler's calculation a reality. If the transition completes successfully, we enter S_IDLE, otherwise we go back to S_POLICY_ENGINE with the current unstable state and try again. Of course, we may be asked to shutdown at any time, however we must progress to S_NOT_DC before doing so. Once we have handed over DC duties to another node, we can then shut down like everyone else, that is, by asking the DC for permission and waiting for it to take all our resources away. The case where we are the DC and the only node in the cluster is a special case and handled as an escalation which takes us to S_SHUTDOWN. Similarly, if any other point in the shutdown fails or stalls, this is escalated and we end up in S_TERMINATE. At any point, the controller can relay messages for its subsystems, but outbound messages (from subsystems) should probably be blocked until S_INTEGRATION (for the DC) or the join protocol has completed (for non-DC controllers). */ /*====================================== * * Inputs/Events/Stimuli to be given to the finite state machine * * Some of these a true events, and others are synthesised based on * the "register" (see below) and the contents or source of messages. * * The machine keeps processing until receiving I_NULL * *======================================*/ enum crmd_fsa_input { I_NULL, /* Nothing happened */ I_CIB_UPDATE, /* An update to the CIB occurred */ I_DC_TIMEOUT, /* We have lost communication with the DC */ I_ELECTION, /* Someone started an election */ I_PE_CALC, /* The scheduler needs to be invoked */ I_RELEASE_DC, /* The election completed and we were not * elected, but we were the DC beforehand */ I_ELECTION_DC, /* The election completed and we were (re-)elected * DC */ I_ERROR, /* Something bad happened (more serious than * I_FAIL) and may not have been due to the action * being performed. For example, we may have lost * our connection to the CIB. */ I_FAIL, /* The action failed to complete successfully */ I_INTEGRATED, I_FINALIZED, I_NODE_JOIN, /* A node has entered the cluster */ I_NOT_DC, /* We are not and were not the DC before or after * the current operation or state */ I_RECOVERED, /* The recovery process completed successfully */ I_RELEASE_FAIL, /* We could not give up DC status for some reason */ I_RELEASE_SUCCESS, /* We are no longer the DC */ I_RESTART, /* The current set of actions needs to be * restarted */ I_TE_SUCCESS, /* Some non-resource, non-cluster-layer action * is required of us, e.g. ping */ I_ROUTER, /* Do our job as router and forward this to the * right place */ I_SHUTDOWN, /* We are asking to shutdown */ I_STOP, /* We have been told to shutdown */ I_TERMINATE, /* Actually exit */ I_STARTUP, I_PE_SUCCESS, /* The action completed successfully */ I_JOIN_OFFER, /* The DC is offering membership */ I_JOIN_REQUEST, /* The client is requesting membership */ I_JOIN_RESULT, /* If not the DC: The result of a join request * Else: A client is responding with its local state info */ I_WAIT_FOR_EVENT, /* we may be waiting for an async task to "happen" * and until it does, we can't do anything else */ I_DC_HEARTBEAT, /* The DC is telling us that it is alive and well */ I_PENDING, I_HALT, /* ------------ Last input found in table is above ----------- */ I_ILLEGAL /* This is an illegal value for an FSA input */ /* (must be last) */ }; # define MAXINPUT I_ILLEGAL # define I_MESSAGE I_ROUTER /*====================================== * * actions * * Some of the actions below will always occur together for now, but this may * not always be the case, so they are split up so that they can easily be * called independently in the future, if necessary. * * For example, separating A_LRM_CONNECT from A_STARTUP might be useful * if we ever try to recover from a faulty or disconnected executor. * *======================================*/ /* Don't do anything */ #define A_NOTHING (UINT64_C(0)) /* -- Startup actions -- */ /* Hook to perform any actions (other than connecting to other daemons) that * might be needed as part of the startup. */ #define A_STARTUP (UINT64_C(1) << 0) /* Hook to perform any actions that might be needed as part after startup is * successful. */ #define A_STARTED (UINT64_C(1) << 1) /* Connect to cluster layer */ #define A_HA_CONNECT (UINT64_C(1) << 2) #define A_HA_DISCONNECT (UINT64_C(1) << 3) #define A_INTEGRATE_TIMER_START (UINT64_C(1) << 4) #define A_INTEGRATE_TIMER_STOP (UINT64_C(1) << 5) #define A_FINALIZE_TIMER_START (UINT64_C(1) << 6) #define A_FINALIZE_TIMER_STOP (UINT64_C(1) << 7) /* -- Election actions -- */ #define A_DC_TIMER_START (UINT64_C(1) << 8) #define A_DC_TIMER_STOP (UINT64_C(1) << 9) #define A_ELECTION_COUNT (UINT64_C(1) << 10) #define A_ELECTION_VOTE (UINT64_C(1) << 11) #define A_ELECTION_START (UINT64_C(1) << 12) /* -- Message processing -- */ -/* Process the queue of requests */ -#define A_MSG_PROCESS (UINT64_C(1) << 13) - /* Send the message to the correct recipient */ #define A_MSG_ROUTE (UINT64_C(1) << 14) /* Send a welcome message to new node(s) */ #define A_DC_JOIN_OFFER_ONE (UINT64_C(1) << 15) /* -- Server Join protocol actions -- */ /* Send a welcome message to all nodes */ #define A_DC_JOIN_OFFER_ALL (UINT64_C(1) << 16) /* Process the remote node's ack of our join message */ #define A_DC_JOIN_PROCESS_REQ (UINT64_C(1) << 17) /* Send out the results of the Join phase */ #define A_DC_JOIN_FINALIZE (UINT64_C(1) << 18) /* Send out the results of the Join phase */ #define A_DC_JOIN_PROCESS_ACK (UINT64_C(1) << 19) /* -- Client Join protocol actions -- */ #define A_CL_JOIN_QUERY (UINT64_C(1) << 20) #define A_CL_JOIN_ANNOUNCE (UINT64_C(1) << 21) /* Request membership to the DC list */ #define A_CL_JOIN_REQUEST (UINT64_C(1) << 22) /* Did the DC accept or reject the request */ #define A_CL_JOIN_RESULT (UINT64_C(1) << 23) /* -- Recovery, DC start/stop -- */ /* Something bad happened, try to recover */ #define A_RECOVER (UINT64_C(1) << 24) /* Hook to perform any actions (apart from starting, the TE, scheduler, and * gathering the latest CIB) that might be necessary before giving up the * responsibilities of being the DC. */ #define A_DC_RELEASE (UINT64_C(1) << 25) #define A_DC_RELEASED (UINT64_C(1) << 26) /* Hook to perform any actions (apart from starting, the TE, scheduler, and * gathering the latest CIB) that might be necessary before taking over the * responsibilities of being the DC. */ #define A_DC_TAKEOVER (UINT64_C(1) << 27) /* -- Shutdown actions -- */ #define A_SHUTDOWN (UINT64_C(1) << 28) #define A_STOP (UINT64_C(1) << 29) #define A_EXIT_0 (UINT64_C(1) << 30) #define A_EXIT_1 (UINT64_C(1) << 31) #define A_SHUTDOWN_REQ (UINT64_C(1) << 32) #define A_ELECTION_CHECK (UINT64_C(1) << 33) #define A_DC_JOIN_FINAL (UINT64_C(1) << 34) /* -- CIB actions -- */ #define A_CIB_START (UINT64_C(1) << 41) #define A_CIB_STOP (UINT64_C(1) << 42) /* -- Transition Engine actions -- */ /* Attempt to reach the newly calculated cluster state. This is only called * once per transition (except if it is asked to stop the transition or start * a new one). Once given a cluster state to reach, the TE will determine * tasks that can be performed in parallel, execute them, wait for replies and * then determine the next set until the new state is reached or no further * tasks can be taken. */ #define A_TE_INVOKE (UINT64_C(1) << 44) #define A_TE_START (UINT64_C(1) << 45) #define A_TE_STOP (UINT64_C(1) << 46) #define A_TE_CANCEL (UINT64_C(1) << 47) #define A_TE_HALT (UINT64_C(1) << 48) /* -- Scheduler actions -- */ /* Calculate the next state for the cluster. This is only invoked once per * needed calculation. */ #define A_PE_INVOKE (UINT64_C(1) << 49) #define A_PE_START (UINT64_C(1) << 50) #define A_PE_STOP (UINT64_C(1) << 51) /* -- Misc actions -- */ -/* Add a system generate "block" so that resources arent moved to or are - * activly moved away from the affected node. This way we can return quickly - * even if busy with other things. - */ -#define A_NODE_BLOCK (UINT64_C(1) << 52) - -/* Update our information in the local CIB */ -#define A_UPDATE_NODESTATUS (UINT64_C(1) << 53) #define A_READCONFIG (UINT64_C(1) << 55) /* -- LRM Actions -- */ /* Connect to the local executor */ #define A_LRM_CONNECT (UINT64_C(1) << 56) /* Disconnect from the local executor */ #define A_LRM_DISCONNECT (UINT64_C(1) << 57) #define A_LRM_INVOKE (UINT64_C(1) << 58) /* -- Logging actions -- */ #define A_LOG (UINT64_C(1) << 60) #define A_ERROR (UINT64_C(1) << 61) #define A_WARN (UINT64_C(1) << 62) #define O_EXIT (A_SHUTDOWN|A_STOP|A_LRM_DISCONNECT|A_HA_DISCONNECT|A_EXIT_0|A_CIB_STOP) #define O_RELEASE (A_DC_TIMER_STOP|A_DC_RELEASE|A_PE_STOP|A_TE_STOP|A_DC_RELEASED) #define O_PE_RESTART (A_PE_START|A_PE_STOP) #define O_TE_RESTART (A_TE_START|A_TE_STOP) #define O_CIB_RESTART (A_CIB_START|A_CIB_STOP) #define O_LRM_RECONNECT (A_LRM_CONNECT|A_LRM_DISCONNECT) #define O_DC_TIMER_RESTART (A_DC_TIMER_STOP|A_DC_TIMER_START) /*====================================== * * "register" contents * * Things we may want to remember regardless of which state we are in. * * These also count as inputs for synthesizing I_* * *======================================*/ // Are we the DC? #define R_THE_DC (UINT64_C(1) << 0) // Are we starting up? #define R_STARTING (UINT64_C(1) << 1) // Are we trying to shut down? #define R_SHUTDOWN (UINT64_C(1) << 2) // Should we restart? #define R_STAYDOWN (UINT64_C(1) << 3) -// Have we completed the join process? -#define R_JOIN_OK (UINT64_C(1) << 4) - // Has the configuration been read? #define R_READ_CONFIG (UINT64_C(1) << 6) -// Should the scheduler be invoked? -#define R_INVOKE_PE (UINT64_C(1) << 7) - // Is the CIB connected? #define R_CIB_CONNECTED (UINT64_C(1) << 8) // Is the scheduler connected? #define R_PE_CONNECTED (UINT64_C(1) << 9) // Is the Transition Engine connected? #define R_TE_CONNECTED (UINT64_C(1) << 10) // Is the executor connected? #define R_LRM_CONNECTED (UINT64_C(1) << 11) -// Is the CIB required? -#define R_CIB_REQUIRED (UINT64_C(1) << 12) - // Is the scheduler required? #define R_PE_REQUIRED (UINT64_C(1) << 13) -// Is the Transition Engine required? -#define R_TE_REQUIRED (UINT64_C(1) << 14) - // Is the fencer daemon required? #define R_ST_REQUIRED (UINT64_C(1) << 15) -// Have we calculated the CIB? -#define R_CIB_DONE (UINT64_C(1) << 16) - // Do we have an up-to-date CIB? #define R_HAVE_CIB (UINT64_C(1) << 17) // Have we received cluster layer data yet? #define R_MEMBERSHIP (UINT64_C(1) << 20) // Ever received membership-layer data #define R_PEER_DATA (UINT64_C(1) << 21) // Did we sign out of our own accord? #define R_HA_DISCONNECTED (UINT64_C(1) << 22) -// Are there requests waiting for processing? -#define R_REQ_PEND (UINT64_C(1) << 24) - -// Are we awaiting reply from scheduler? -#define R_PE_PEND (UINT64_C(1) << 25) - -// Has the TE been invoked and we're awaiting completion? -#define R_TE_PEND (UINT64_C(1) << 26) - -// Do we have clients waiting on a response? If so perhaps we -// shouldn't stop yet. -#define R_RESP_PEND (UINT64_C(1) << 27) - /* Have we sent a stop action to all resources in preparation for * shutting down? */ #define R_SENT_RSC_STOP (UINT64_C(1) << 29) // Are we in recovery mode? #define R_IN_RECOVERY (UINT64_C(1) << 31) #define CRM_DIRECT_NACK_RC (99) // Deprecated (see PCMK_EXEC_INVALID) enum crmd_fsa_cause { C_UNKNOWN = 0, C_STARTUP, C_IPC_MESSAGE, C_HA_MESSAGE, C_CRMD_STATUS_CALLBACK, C_LRM_OP_CALLBACK, C_TIMER_POPPED, C_SHUTDOWN, C_FSA_INTERNAL, }; enum fsa_data_type { fsa_dt_none, fsa_dt_ha_msg, fsa_dt_xml, fsa_dt_lrm, }; typedef struct fsa_data_s fsa_data_t; struct fsa_data_s { int id; enum crmd_fsa_input fsa_input; enum crmd_fsa_cause fsa_cause; uint64_t actions; const char *origin; void *data; enum fsa_data_type data_type; }; #define controld_set_fsa_input_flags(flags_to_set) do { \ controld_globals.fsa_input_register \ = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE, \ "FSA input", "controller", \ controld_globals.fsa_input_register, \ (flags_to_set), #flags_to_set); \ } while (0) #define controld_clear_fsa_input_flags(flags_to_clear) do { \ controld_globals.fsa_input_register \ = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, \ "FSA input", "controller", \ controld_globals.fsa_input_register, \ (flags_to_clear), \ #flags_to_clear); \ } while (0) #define controld_set_fsa_action_flags(flags_to_set) do { \ controld_globals.fsa_actions \ = pcmk__set_flags_as(__func__, __LINE__, LOG_DEBUG, \ "FSA action", "controller", \ controld_globals.fsa_actions, \ (flags_to_set), #flags_to_set); \ } while (0) #define controld_clear_fsa_action_flags(flags_to_clear) do { \ controld_globals.fsa_actions \ = pcmk__clear_flags_as(__func__, __LINE__, LOG_DEBUG, \ "FSA action", "controller", \ controld_globals.fsa_actions, \ (flags_to_clear), #flags_to_clear); \ } while (0) // This should be moved elsewhere xmlNode *controld_query_executor_state(void); const char *fsa_input2string(enum crmd_fsa_input input); const char *fsa_state2string(enum crmd_fsa_state state); const char *fsa_cause2string(enum crmd_fsa_cause cause); const char *fsa_action2string(long long action); enum crmd_fsa_state s_crmd_fsa(enum crmd_fsa_cause cause); enum crmd_fsa_state controld_fsa_get_next_state(enum crmd_fsa_input input); uint64_t controld_fsa_get_action(enum crmd_fsa_input input); void controld_init_fsa_trigger(void); void controld_destroy_fsa_trigger(void); void free_max_generation(void); #define AM_I_DC pcmk__is_set(controld_globals.fsa_input_register, R_THE_DC) #define controld_trigger_fsa() controld_trigger_fsa_as(__func__, __LINE__) void controld_trigger_fsa_as(const char *fn, int line); /* A_READCONFIG */ void do_read_config(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data); /* A_PE_INVOKE */ void do_pe_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data); /* A_LOG */ void do_log(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_STARTUP */ void do_startup(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_CIB_START, STOP, RESTART */ void do_cib_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_HA_CONNECT */ void do_ha_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_LRM_CONNECT */ void do_lrm_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_PE_START, STOP, RESTART */ void do_pe_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_TE_START, STOP, RESTART */ void do_te_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_STARTED */ void do_started(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_MSG_ROUTE */ void do_msg_route(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_RECOVER */ void do_recover(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_ELECTION_VOTE */ void do_election_vote(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_ELECTION_COUNT */ void do_election_count_vote(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_ELECTION_CHECK */ void do_election_check(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_DC_TIMER_STOP */ void do_timer_control(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_DC_TAKEOVER */ void do_dc_takeover(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_DC_RELEASE */ void do_dc_release(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_DC_JOIN_OFFER_ALL */ void do_dc_join_offer_all(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_DC_JOIN_OFFER_ONE */ void do_dc_join_offer_one(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_DC_JOIN_ACK */ void do_dc_join_ack(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_DC_JOIN_REQ */ void do_dc_join_filter_offer(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_DC_JOIN_FINALIZE */ void do_dc_join_finalize(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_CL_JOIN_QUERY */ /* is there a DC out there? */ void do_cl_join_query(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data); /* A_CL_JOIN_ANNOUNCE */ void do_cl_join_announce(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data); /* A_CL_JOIN_REQUEST */ void do_cl_join_offer_respond(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data); /* A_CL_JOIN_RESULT */ void do_cl_join_finalize_respond(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data); /* A_LRM_INVOKE */ void do_lrm_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_TE_INVOKE, A_TE_CANCEL */ void do_te_invoke(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_SHUTDOWN_REQ */ void do_shutdown_req(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_SHUTDOWN */ void do_shutdown(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_STOP */ void do_stop(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_EXIT_0, A_EXIT_1 */ void do_exit(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input cur_input, fsa_data_t *msg_data); /* A_DC_JOIN_FINAL */ void do_dc_join_final(long long action, enum crmd_fsa_cause cause, enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t *msg_data); #endif diff --git a/daemons/controld/controld_utils.c b/daemons/controld/controld_utils.c index c99630c0b4..6979b9fc2d 100644 --- a/daemons/controld/controld_utils.c +++ b/daemons/controld/controld_utils.c @@ -1,856 +1,811 @@ /* * Copyright 2004-2025 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. */ #include #include #include // uint64_t #include // PRIx64 #include #include #include #include /*! * \internal * \brief Check whether a given name is for the local node * * \param[in] name Name to check * * \return true if \p name is the name of the local node, otherwise false */ bool controld_is_local_node(const char *name) { CRM_CHECK(controld_globals.cluster != NULL, return false); return pcmk__str_eq(name, controld_globals.cluster->priv->node_name, pcmk__str_casei); } /*! * \internal * \brief Get node status object for local node * * \return Node status object for local node */ pcmk__node_status_t * controld_get_local_node_status(void) { CRM_CHECK(controld_globals.cluster != NULL, return NULL); return pcmk__get_node(controld_globals.cluster->priv->node_id, controld_globals.cluster->priv->node_name, NULL, pcmk__node_search_cluster_member); } const char * fsa_input2string(enum crmd_fsa_input input) { const char *inputAsText = NULL; switch (input) { case I_NULL: inputAsText = "I_NULL"; break; case I_CIB_UPDATE: inputAsText = "I_CIB_UPDATE"; break; case I_DC_TIMEOUT: inputAsText = "I_DC_TIMEOUT"; break; case I_ELECTION: inputAsText = "I_ELECTION"; break; case I_PE_CALC: inputAsText = "I_PE_CALC"; break; case I_RELEASE_DC: inputAsText = "I_RELEASE_DC"; break; case I_ELECTION_DC: inputAsText = "I_ELECTION_DC"; break; case I_ERROR: inputAsText = "I_ERROR"; break; case I_FAIL: inputAsText = "I_FAIL"; break; case I_INTEGRATED: inputAsText = "I_INTEGRATED"; break; case I_FINALIZED: inputAsText = "I_FINALIZED"; break; case I_NODE_JOIN: inputAsText = "I_NODE_JOIN"; break; case I_JOIN_OFFER: inputAsText = "I_JOIN_OFFER"; break; case I_JOIN_REQUEST: inputAsText = "I_JOIN_REQUEST"; break; case I_JOIN_RESULT: inputAsText = "I_JOIN_RESULT"; break; case I_NOT_DC: inputAsText = "I_NOT_DC"; break; case I_RECOVERED: inputAsText = "I_RECOVERED"; break; case I_RELEASE_FAIL: inputAsText = "I_RELEASE_FAIL"; break; case I_RELEASE_SUCCESS: inputAsText = "I_RELEASE_SUCCESS"; break; case I_RESTART: inputAsText = "I_RESTART"; break; case I_PE_SUCCESS: inputAsText = "I_PE_SUCCESS"; break; case I_ROUTER: inputAsText = "I_ROUTER"; break; case I_SHUTDOWN: inputAsText = "I_SHUTDOWN"; break; case I_STARTUP: inputAsText = "I_STARTUP"; break; case I_TE_SUCCESS: inputAsText = "I_TE_SUCCESS"; break; case I_STOP: inputAsText = "I_STOP"; break; case I_DC_HEARTBEAT: inputAsText = "I_DC_HEARTBEAT"; break; case I_WAIT_FOR_EVENT: inputAsText = "I_WAIT_FOR_EVENT"; break; case I_PENDING: inputAsText = "I_PENDING"; break; case I_HALT: inputAsText = "I_HALT"; break; case I_TERMINATE: inputAsText = "I_TERMINATE"; break; case I_ILLEGAL: inputAsText = "I_ILLEGAL"; break; } if (inputAsText == NULL) { crm_err("Input %d is unknown", input); inputAsText = ""; } return inputAsText; } const char * fsa_state2string(enum crmd_fsa_state state) { const char *stateAsText = NULL; switch (state) { case S_IDLE: stateAsText = "S_IDLE"; break; case S_ELECTION: stateAsText = "S_ELECTION"; break; case S_INTEGRATION: stateAsText = "S_INTEGRATION"; break; case S_FINALIZE_JOIN: stateAsText = "S_FINALIZE_JOIN"; break; case S_NOT_DC: stateAsText = "S_NOT_DC"; break; case S_POLICY_ENGINE: stateAsText = "S_POLICY_ENGINE"; break; case S_RECOVERY: stateAsText = "S_RECOVERY"; break; case S_RELEASE_DC: stateAsText = "S_RELEASE_DC"; break; case S_PENDING: stateAsText = "S_PENDING"; break; case S_STOPPING: stateAsText = "S_STOPPING"; break; case S_TERMINATE: stateAsText = "S_TERMINATE"; break; case S_TRANSITION_ENGINE: stateAsText = "S_TRANSITION_ENGINE"; break; case S_STARTING: stateAsText = "S_STARTING"; break; case S_HALT: stateAsText = "S_HALT"; break; case S_ILLEGAL: stateAsText = "S_ILLEGAL"; break; } if (stateAsText == NULL) { crm_err("State %d is unknown", state); stateAsText = ""; } return stateAsText; } const char * fsa_cause2string(enum crmd_fsa_cause cause) { const char *causeAsText = NULL; switch (cause) { case C_UNKNOWN: causeAsText = "C_UNKNOWN"; break; case C_STARTUP: causeAsText = "C_STARTUP"; break; case C_IPC_MESSAGE: causeAsText = "C_IPC_MESSAGE"; break; case C_HA_MESSAGE: causeAsText = "C_HA_MESSAGE"; break; case C_TIMER_POPPED: causeAsText = "C_TIMER_POPPED"; break; case C_SHUTDOWN: causeAsText = "C_SHUTDOWN"; break; case C_LRM_OP_CALLBACK: causeAsText = "C_LRM_OP_CALLBACK"; break; case C_CRMD_STATUS_CALLBACK: causeAsText = "C_CRMD_STATUS_CALLBACK"; break; case C_FSA_INTERNAL: causeAsText = "C_FSA_INTERNAL"; break; } if (causeAsText == NULL) { crm_err("Cause %d is unknown", cause); causeAsText = ""; } return causeAsText; } const char * fsa_action2string(long long action) { const char *actionAsText = NULL; switch (action) { case A_NOTHING: actionAsText = "A_NOTHING"; break; case A_ELECTION_START: actionAsText = "A_ELECTION_START"; break; case A_DC_JOIN_FINAL: actionAsText = "A_DC_JOIN_FINAL"; break; case A_READCONFIG: actionAsText = "A_READCONFIG"; break; case O_RELEASE: actionAsText = "O_RELEASE"; break; case A_STARTUP: actionAsText = "A_STARTUP"; break; case A_STARTED: actionAsText = "A_STARTED"; break; case A_HA_CONNECT: actionAsText = "A_HA_CONNECT"; break; case A_HA_DISCONNECT: actionAsText = "A_HA_DISCONNECT"; break; case A_LRM_CONNECT: actionAsText = "A_LRM_CONNECT"; break; case A_LRM_INVOKE: actionAsText = "A_LRM_INVOKE"; break; case A_LRM_DISCONNECT: actionAsText = "A_LRM_DISCONNECT"; break; case O_LRM_RECONNECT: actionAsText = "O_LRM_RECONNECT"; break; case A_CL_JOIN_QUERY: actionAsText = "A_CL_JOIN_QUERY"; break; case A_DC_TIMER_STOP: actionAsText = "A_DC_TIMER_STOP"; break; case A_DC_TIMER_START: actionAsText = "A_DC_TIMER_START"; break; case A_INTEGRATE_TIMER_START: actionAsText = "A_INTEGRATE_TIMER_START"; break; case A_INTEGRATE_TIMER_STOP: actionAsText = "A_INTEGRATE_TIMER_STOP"; break; case A_FINALIZE_TIMER_START: actionAsText = "A_FINALIZE_TIMER_START"; break; case A_FINALIZE_TIMER_STOP: actionAsText = "A_FINALIZE_TIMER_STOP"; break; case A_ELECTION_COUNT: actionAsText = "A_ELECTION_COUNT"; break; case A_ELECTION_VOTE: actionAsText = "A_ELECTION_VOTE"; break; case A_ELECTION_CHECK: actionAsText = "A_ELECTION_CHECK"; break; case A_CL_JOIN_ANNOUNCE: actionAsText = "A_CL_JOIN_ANNOUNCE"; break; case A_CL_JOIN_REQUEST: actionAsText = "A_CL_JOIN_REQUEST"; break; case A_CL_JOIN_RESULT: actionAsText = "A_CL_JOIN_RESULT"; break; case A_DC_JOIN_OFFER_ALL: actionAsText = "A_DC_JOIN_OFFER_ALL"; break; case A_DC_JOIN_OFFER_ONE: actionAsText = "A_DC_JOIN_OFFER_ONE"; break; case A_DC_JOIN_PROCESS_REQ: actionAsText = "A_DC_JOIN_PROCESS_REQ"; break; case A_DC_JOIN_PROCESS_ACK: actionAsText = "A_DC_JOIN_PROCESS_ACK"; break; case A_DC_JOIN_FINALIZE: actionAsText = "A_DC_JOIN_FINALIZE"; break; - case A_MSG_PROCESS: - actionAsText = "A_MSG_PROCESS"; - break; case A_MSG_ROUTE: actionAsText = "A_MSG_ROUTE"; break; case A_RECOVER: actionAsText = "A_RECOVER"; break; case A_DC_RELEASE: actionAsText = "A_DC_RELEASE"; break; case A_DC_RELEASED: actionAsText = "A_DC_RELEASED"; break; case A_DC_TAKEOVER: actionAsText = "A_DC_TAKEOVER"; break; case A_SHUTDOWN: actionAsText = "A_SHUTDOWN"; break; case A_SHUTDOWN_REQ: actionAsText = "A_SHUTDOWN_REQ"; break; case A_STOP: actionAsText = "A_STOP "; break; case A_EXIT_0: actionAsText = "A_EXIT_0"; break; case A_EXIT_1: actionAsText = "A_EXIT_1"; break; case O_CIB_RESTART: actionAsText = "O_CIB_RESTART"; break; case A_CIB_START: actionAsText = "A_CIB_START"; break; case A_CIB_STOP: actionAsText = "A_CIB_STOP"; break; case A_TE_INVOKE: actionAsText = "A_TE_INVOKE"; break; case O_TE_RESTART: actionAsText = "O_TE_RESTART"; break; case A_TE_START: actionAsText = "A_TE_START"; break; case A_TE_STOP: actionAsText = "A_TE_STOP"; break; case A_TE_HALT: actionAsText = "A_TE_HALT"; break; case A_TE_CANCEL: actionAsText = "A_TE_CANCEL"; break; case A_PE_INVOKE: actionAsText = "A_PE_INVOKE"; break; case O_PE_RESTART: actionAsText = "O_PE_RESTART"; break; case A_PE_START: actionAsText = "A_PE_START"; break; case A_PE_STOP: actionAsText = "A_PE_STOP"; break; - case A_NODE_BLOCK: - actionAsText = "A_NODE_BLOCK"; - break; - case A_UPDATE_NODESTATUS: - actionAsText = "A_UPDATE_NODESTATUS"; - break; case A_LOG: actionAsText = "A_LOG "; break; case A_ERROR: actionAsText = "A_ERROR "; break; case A_WARN: actionAsText = "A_WARN "; break; /* Composite actions */ case A_DC_TIMER_START | A_CL_JOIN_QUERY: actionAsText = "A_DC_TIMER_START|A_CL_JOIN_QUERY"; break; } if (actionAsText == NULL) { crm_err("Action %.16llx is unknown", action); actionAsText = ""; } return actionAsText; } void fsa_dump_inputs(int log_level, const char *text, long long input_register) { if (input_register == A_NOTHING) { return; } if (text == NULL) { text = "Input register contents:"; } if (pcmk__is_set(input_register, R_THE_DC)) { crm_trace("%s %.16" PRIx64 " (R_THE_DC)", text, R_THE_DC); } if (pcmk__is_set(input_register, R_STARTING)) { crm_trace("%s %.16" PRIx64 " (R_STARTING)", text, R_STARTING); } if (pcmk__is_set(input_register, R_SHUTDOWN)) { crm_trace("%s %.16" PRIx64 " (R_SHUTDOWN)", text, R_SHUTDOWN); } if (pcmk__is_set(input_register, R_STAYDOWN)) { crm_trace("%s %.16" PRIx64 " (R_STAYDOWN)", text, R_STAYDOWN); } - if (pcmk__is_set(input_register, R_JOIN_OK)) { - crm_trace("%s %.16" PRIx64 " (R_JOIN_OK)", text, R_JOIN_OK); - } if (pcmk__is_set(input_register, R_READ_CONFIG)) { crm_trace("%s %.16" PRIx64 " (R_READ_CONFIG)", text, R_READ_CONFIG); } - if (pcmk__is_set(input_register, R_INVOKE_PE)) { - crm_trace("%s %.16" PRIx64 " (R_INVOKE_PE)", text, R_INVOKE_PE); - } if (pcmk__is_set(input_register, R_CIB_CONNECTED)) { crm_trace("%s %.16" PRIx64 " (R_CIB_CONNECTED)", text, R_CIB_CONNECTED); } if (pcmk__is_set(input_register, R_PE_CONNECTED)) { crm_trace("%s %.16" PRIx64 " (R_PE_CONNECTED)", text, R_PE_CONNECTED); } if (pcmk__is_set(input_register, R_TE_CONNECTED)) { crm_trace("%s %.16" PRIx64 " (R_TE_CONNECTED)", text, R_TE_CONNECTED); } if (pcmk__is_set(input_register, R_LRM_CONNECTED)) { crm_trace("%s %.16" PRIx64 " (R_LRM_CONNECTED)", text, R_LRM_CONNECTED); } - if (pcmk__is_set(input_register, R_CIB_REQUIRED)) { - crm_trace("%s %.16" PRIx64 " (R_CIB_REQUIRED)", text, R_CIB_REQUIRED); - } if (pcmk__is_set(input_register, R_PE_REQUIRED)) { crm_trace("%s %.16" PRIx64 " (R_PE_REQUIRED)", text, R_PE_REQUIRED); } - if (pcmk__is_set(input_register, R_TE_REQUIRED)) { - crm_trace("%s %.16" PRIx64 " (R_TE_REQUIRED)", text, R_TE_REQUIRED); - } - if (pcmk__is_set(input_register, R_REQ_PEND)) { - crm_trace("%s %.16" PRIx64 " (R_REQ_PEND)", text, R_REQ_PEND); - } - if (pcmk__is_set(input_register, R_PE_PEND)) { - crm_trace("%s %.16" PRIx64 " (R_PE_PEND)", text, R_PE_PEND); - } - if (pcmk__is_set(input_register, R_TE_PEND)) { - crm_trace("%s %.16" PRIx64 " (R_TE_PEND)", text, R_TE_PEND); - } - if (pcmk__is_set(input_register, R_RESP_PEND)) { - crm_trace("%s %.16" PRIx64 " (R_RESP_PEND)", text, R_RESP_PEND); - } - if (pcmk__is_set(input_register, R_CIB_DONE)) { - crm_trace("%s %.16" PRIx64 " (R_CIB_DONE)", text, R_CIB_DONE); - } if (pcmk__is_set(input_register, R_HAVE_CIB)) { crm_trace("%s %.16" PRIx64 " (R_HAVE_CIB)", text, R_HAVE_CIB); } if (pcmk__is_set(input_register, R_MEMBERSHIP)) { crm_trace("%s %.16" PRIx64 " (R_MEMBERSHIP)", text, R_MEMBERSHIP); } if (pcmk__is_set(input_register, R_PEER_DATA)) { crm_trace("%s %.16" PRIx64 " (R_PEER_DATA)", text, R_PEER_DATA); } if (pcmk__is_set(input_register, R_IN_RECOVERY)) { crm_trace("%s %.16" PRIx64 " (R_IN_RECOVERY)", text, R_IN_RECOVERY); } } void fsa_dump_actions(uint64_t action, const char *text) { if (pcmk__is_set(action, A_READCONFIG)) { crm_trace("Action %.16" PRIx64 " (A_READCONFIG) %s", A_READCONFIG, text); } if (pcmk__is_set(action, A_STARTUP)) { crm_trace("Action %.16" PRIx64 " (A_STARTUP) %s", A_STARTUP, text); } if (pcmk__is_set(action, A_STARTED)) { crm_trace("Action %.16" PRIx64 " (A_STARTED) %s", A_STARTED, text); } if (pcmk__is_set(action, A_HA_CONNECT)) { crm_trace("Action %.16" PRIx64 " (A_CONNECT) %s", A_HA_CONNECT, text); } if (pcmk__is_set(action, A_HA_DISCONNECT)) { crm_trace("Action %.16" PRIx64 " (A_DISCONNECT) %s", A_HA_DISCONNECT, text); } if (pcmk__is_set(action, A_LRM_CONNECT)) { crm_trace("Action %.16" PRIx64 " (A_LRM_CONNECT) %s", A_LRM_CONNECT, text); } if (pcmk__is_set(action, A_LRM_INVOKE)) { crm_trace("Action %.16" PRIx64 " (A_LRM_INVOKE) %s", A_LRM_INVOKE, text); } if (pcmk__is_set(action, A_LRM_DISCONNECT)) { crm_trace("Action %.16" PRIx64 " (A_LRM_DISCONNECT) %s", A_LRM_DISCONNECT, text); } if (pcmk__is_set(action, A_DC_TIMER_STOP)) { crm_trace("Action %.16" PRIx64 " (A_DC_TIMER_STOP) %s", A_DC_TIMER_STOP, text); } if (pcmk__is_set(action, A_DC_TIMER_START)) { crm_trace("Action %.16" PRIx64 " (A_DC_TIMER_START) %s", A_DC_TIMER_START, text); } if (pcmk__is_set(action, A_INTEGRATE_TIMER_START)) { crm_trace("Action %.16" PRIx64 " (A_INTEGRATE_TIMER_START) %s", A_INTEGRATE_TIMER_START, text); } if (pcmk__is_set(action, A_INTEGRATE_TIMER_STOP)) { crm_trace("Action %.16" PRIx64 " (A_INTEGRATE_TIMER_STOP) %s", A_INTEGRATE_TIMER_STOP, text); } if (pcmk__is_set(action, A_FINALIZE_TIMER_START)) { crm_trace("Action %.16" PRIx64 " (A_FINALIZE_TIMER_START) %s", A_FINALIZE_TIMER_START, text); } if (pcmk__is_set(action, A_FINALIZE_TIMER_STOP)) { crm_trace("Action %.16" PRIx64 " (A_FINALIZE_TIMER_STOP) %s", A_FINALIZE_TIMER_STOP, text); } if (pcmk__is_set(action, A_ELECTION_COUNT)) { crm_trace("Action %.16" PRIx64 " (A_ELECTION_COUNT) %s", A_ELECTION_COUNT, text); } if (pcmk__is_set(action, A_ELECTION_VOTE)) { crm_trace("Action %.16" PRIx64 " (A_ELECTION_VOTE) %s", A_ELECTION_VOTE, text); } if (pcmk__is_set(action, A_ELECTION_CHECK)) { crm_trace("Action %.16" PRIx64 " (A_ELECTION_CHECK) %s", A_ELECTION_CHECK, text); } if (pcmk__is_set(action, A_CL_JOIN_ANNOUNCE)) { crm_trace("Action %.16" PRIx64 " (A_CL_JOIN_ANNOUNCE) %s", A_CL_JOIN_ANNOUNCE, text); } if (pcmk__is_set(action, A_CL_JOIN_REQUEST)) { crm_trace("Action %.16" PRIx64 " (A_CL_JOIN_REQUEST) %s", A_CL_JOIN_REQUEST, text); } if (pcmk__is_set(action, A_CL_JOIN_RESULT)) { crm_trace("Action %.16" PRIx64 " (A_CL_JOIN_RESULT) %s", A_CL_JOIN_RESULT, text); } if (pcmk__is_set(action, A_DC_JOIN_OFFER_ALL)) { crm_trace("Action %.16" PRIx64 " (A_DC_JOIN_OFFER_ALL) %s", A_DC_JOIN_OFFER_ALL, text); } if (pcmk__is_set(action, A_DC_JOIN_OFFER_ONE)) { crm_trace("Action %.16" PRIx64 " (A_DC_JOIN_OFFER_ONE) %s", A_DC_JOIN_OFFER_ONE, text); } if (pcmk__is_set(action, A_DC_JOIN_PROCESS_REQ)) { crm_trace("Action %.16" PRIx64 " (A_DC_JOIN_PROCESS_REQ) %s", A_DC_JOIN_PROCESS_REQ, text); } if (pcmk__is_set(action, A_DC_JOIN_PROCESS_ACK)) { crm_trace("Action %.16" PRIx64 " (A_DC_JOIN_PROCESS_ACK) %s", A_DC_JOIN_PROCESS_ACK, text); } if (pcmk__is_set(action, A_DC_JOIN_FINALIZE)) { crm_trace("Action %.16" PRIx64 " (A_DC_JOIN_FINALIZE) %s", A_DC_JOIN_FINALIZE, text); } - if (pcmk__is_set(action, A_MSG_PROCESS)) { - crm_trace("Action %.16" PRIx64 " (A_MSG_PROCESS) %s", A_MSG_PROCESS, text); - } if (pcmk__is_set(action, A_MSG_ROUTE)) { crm_trace("Action %.16" PRIx64 " (A_MSG_ROUTE) %s", A_MSG_ROUTE, text); } if (pcmk__is_set(action, A_RECOVER)) { crm_trace("Action %.16" PRIx64 " (A_RECOVER) %s", A_RECOVER, text); } if (pcmk__is_set(action, A_DC_RELEASE)) { crm_trace("Action %.16" PRIx64 " (A_DC_RELEASE) %s", A_DC_RELEASE, text); } if (pcmk__is_set(action, A_DC_RELEASED)) { crm_trace("Action %.16" PRIx64 " (A_DC_RELEASED) %s", A_DC_RELEASED, text); } if (pcmk__is_set(action, A_DC_TAKEOVER)) { crm_trace("Action %.16" PRIx64 " (A_DC_TAKEOVER) %s", A_DC_TAKEOVER, text); } if (pcmk__is_set(action, A_SHUTDOWN)) { crm_trace("Action %.16" PRIx64 " (A_SHUTDOWN) %s", A_SHUTDOWN, text); } if (pcmk__is_set(action, A_SHUTDOWN_REQ)) { crm_trace("Action %.16" PRIx64 " (A_SHUTDOWN_REQ) %s", A_SHUTDOWN_REQ, text); } if (pcmk__is_set(action, A_STOP)) { crm_trace("Action %.16" PRIx64 " (A_STOP ) %s", A_STOP, text); } if (pcmk__is_set(action, A_EXIT_0)) { crm_trace("Action %.16" PRIx64 " (A_EXIT_0) %s", A_EXIT_0, text); } if (pcmk__is_set(action, A_EXIT_1)) { crm_trace("Action %.16" PRIx64 " (A_EXIT_1) %s", A_EXIT_1, text); } if (pcmk__is_set(action, A_CIB_START)) { crm_trace("Action %.16" PRIx64 " (A_CIB_START) %s", A_CIB_START, text); } if (pcmk__is_set(action, A_CIB_STOP)) { crm_trace("Action %.16" PRIx64 " (A_CIB_STOP) %s", A_CIB_STOP, text); } if (pcmk__is_set(action, A_TE_INVOKE)) { crm_trace("Action %.16" PRIx64 " (A_TE_INVOKE) %s", A_TE_INVOKE, text); } if (pcmk__is_set(action, A_TE_START)) { crm_trace("Action %.16" PRIx64 " (A_TE_START) %s", A_TE_START, text); } if (pcmk__is_set(action, A_TE_STOP)) { crm_trace("Action %.16" PRIx64 " (A_TE_STOP) %s", A_TE_STOP, text); } if (pcmk__is_set(action, A_TE_CANCEL)) { crm_trace("Action %.16" PRIx64 " (A_TE_CANCEL) %s", A_TE_CANCEL, text); } if (pcmk__is_set(action, A_PE_INVOKE)) { crm_trace("Action %.16" PRIx64 " (A_PE_INVOKE) %s", A_PE_INVOKE, text); } if (pcmk__is_set(action, A_PE_START)) { crm_trace("Action %.16" PRIx64 " (A_PE_START) %s", A_PE_START, text); } if (pcmk__is_set(action, A_PE_STOP)) { crm_trace("Action %.16" PRIx64 " (A_PE_STOP) %s", A_PE_STOP, text); } - if (pcmk__is_set(action, A_NODE_BLOCK)) { - crm_trace("Action %.16" PRIx64 " (A_NODE_BLOCK) %s", A_NODE_BLOCK, text); - } - if (pcmk__is_set(action, A_UPDATE_NODESTATUS)) { - crm_trace("Action %.16" PRIx64 " (A_UPDATE_NODESTATUS) %s", A_UPDATE_NODESTATUS, text); - } if (pcmk__is_set(action, A_LOG)) { crm_trace("Action %.16" PRIx64 " (A_LOG ) %s", A_LOG, text); } if (pcmk__is_set(action, A_ERROR)) { crm_trace("Action %.16" PRIx64 " (A_ERROR ) %s", A_ERROR, text); } if (pcmk__is_set(action, A_WARN)) { crm_trace("Action %.16" PRIx64 " (A_WARN ) %s", A_WARN, text); } } gboolean update_dc(xmlNode * msg) { char *last_dc = controld_globals.dc_name; const char *dc_version = NULL; const char *welcome_from = NULL; if (msg != NULL) { gboolean invalid = FALSE; dc_version = pcmk__xe_get(msg, PCMK_XA_VERSION); welcome_from = pcmk__xe_get(msg, PCMK__XA_SRC); CRM_CHECK(dc_version != NULL, return FALSE); CRM_CHECK(welcome_from != NULL, return FALSE); if (AM_I_DC && !controld_is_local_node(welcome_from)) { invalid = TRUE; } else if ((controld_globals.dc_name != NULL) && !pcmk__str_eq(welcome_from, controld_globals.dc_name, pcmk__str_casei)) { invalid = TRUE; } if (invalid) { if (AM_I_DC) { crm_err("Not updating DC to %s (%s): we are also a DC", welcome_from, dc_version); } else { crm_warn("New DC %s is not %s", welcome_from, controld_globals.dc_name); } controld_set_fsa_action_flags(A_CL_JOIN_QUERY | A_DC_TIMER_START); controld_trigger_fsa(); return FALSE; } } controld_globals.dc_name = NULL; // freed as last_dc pcmk__str_update(&(controld_globals.dc_name), welcome_from); pcmk__str_update(&(controld_globals.dc_version), dc_version); if (pcmk__str_eq(controld_globals.dc_name, last_dc, pcmk__str_casei)) { /* do nothing */ } else if (controld_globals.dc_name != NULL) { pcmk__node_status_t *dc_node = pcmk__get_node(0, controld_globals.dc_name, NULL, pcmk__node_search_cluster_member); crm_info("Set DC to %s (%s)", controld_globals.dc_name, pcmk__s(controld_globals.dc_version, "unknown version")); pcmk__update_peer_expected(__func__, dc_node, CRMD_JOINSTATE_MEMBER); } else if (last_dc != NULL) { crm_info("Unset DC (was %s)", last_dc); } free(last_dc); return TRUE; } void crmd_peer_down(pcmk__node_status_t *peer, bool full) { if(full && peer->state == NULL) { pcmk__update_peer_state(__func__, peer, PCMK__VALUE_LOST, 0); crm_update_peer_proc(__func__, peer, crm_proc_none, NULL); } crm_update_peer_join(__func__, peer, controld_join_none); pcmk__update_peer_expected(__func__, peer, CRMD_JOINSTATE_DOWN); } /*! * \internal * \brief Check feature set compatibility of DC and joining node * * Return true if a joining node's CRM feature set is compatible with the * current DC's. The feature sets are compatible if they have the same major * version number, and the DC's minor version number is the same or older than * the joining node's. The minor-minor version is intended solely to allow * resource agents to detect feature support, and so is ignored. * * \param[in] dc_version DC's feature set * \param[in] join_version Joining node's version */ bool feature_set_compatible(const char *dc_version, const char *join_version) { char *dc_minor = NULL; char *join_minor = NULL; long dc_v = 0; long join_v = 0; // Get DC's major version errno = 0; dc_v = strtol(dc_version, &dc_minor, 10); if (errno) { return FALSE; } // Get joining node's major version errno = 0; join_v = strtol(join_version, &join_minor, 10); if (errno) { return FALSE; } // Major version component must be identical if (dc_v != join_v) { return FALSE; } // Get DC's minor version if (*dc_minor == '.') { ++dc_minor; } errno = 0; dc_v = strtol(dc_minor, NULL, 10); if (errno) { return FALSE; } // Get joining node's minor version if (*join_minor == '.') { ++join_minor; } errno = 0; join_v = strtol(join_minor, NULL, 10); if (errno) { return FALSE; } // DC's minor version must be the same or older return dc_v <= join_v; } const char * get_node_id(xmlNode *lrm_rsc_op) { xmlNode *node = lrm_rsc_op; while ((node != NULL) && !pcmk__xe_is(node, PCMK__XE_NODE_STATE)) { node = node->parent; } CRM_CHECK(node != NULL, return NULL); return pcmk__xe_id(node); }