root/daemons/controld/controld_election.c

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

DEFINITIONS

This source file includes following definitions.
  1. election_win_cb
  2. controld_election_init
  3. controld_configure_election
  4. controld_remove_voter
  5. controld_stop_current_election_timeout
  6. do_election_vote
  7. do_election_check
  8. do_election_count_vote
  9. feature_update_callback
  10. do_dc_takeover
  11. do_dc_release

   1 /*
   2  * Copyright 2004-2024 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <sys/time.h>
  13 #include <sys/resource.h>
  14 
  15 #include <crm/common/xml.h>
  16 #include <crm/cluster/internal.h>
  17 #include <crm/cluster/election_internal.h>
  18 #include <crm/crm.h>
  19 
  20 #include <pacemaker-controld.h>
  21 
  22 static void
  23 election_win_cb(pcmk_cluster_t *cluster)
     /* [previous][next][first][last][top][bottom][index][help] */
  24 {
  25     register_fsa_input(C_FSA_INTERNAL, I_ELECTION_DC, NULL);
  26 }
  27 
  28 void
  29 controld_election_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  30 {
  31     election_init(controld_globals.cluster, election_win_cb);
  32 }
  33 
  34 /*!
  35  * \internal
  36  * \brief Configure election options based on the CIB
  37  *
  38  * \param[in,out] options  Name/value pairs for configured options
  39  */
  40 void
  41 controld_configure_election(GHashTable *options)
     /* [previous][next][first][last][top][bottom][index][help] */
  42 {
  43     const char *value = g_hash_table_lookup(options, PCMK_OPT_ELECTION_TIMEOUT);
  44     guint interval_ms = 0U;
  45 
  46     pcmk_parse_interval_spec(value, &interval_ms);
  47     election_timeout_set_period(controld_globals.cluster, interval_ms);
  48 }
  49 
  50 void
  51 controld_remove_voter(const char *uname)
     /* [previous][next][first][last][top][bottom][index][help] */
  52 {
  53     election_remove(controld_globals.cluster, uname);
  54 
  55     if (pcmk__str_eq(uname, controld_globals.dc_name, pcmk__str_casei)) {
  56         /* Clear any election dampening in effect. Otherwise, if the lost DC had
  57          * just won, an immediate new election could fizzle out with no new DC.
  58          */
  59         election_clear_dampening(controld_globals.cluster);
  60     }
  61 }
  62 
  63 void
  64 controld_stop_current_election_timeout(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  65 {
  66     election_timeout_stop(controld_globals.cluster);
  67 }
  68 
  69 /*      A_ELECTION_VOTE */
  70 void
  71 do_election_vote(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
  72                  enum crmd_fsa_cause cause,
  73                  enum crmd_fsa_state cur_state,
  74                  enum crmd_fsa_input current_input, fsa_data_t * msg_data)
  75 {
  76     gboolean not_voting = FALSE;
  77 
  78     /* don't vote if we're in one of these states or wanting to shut down */
  79     switch (cur_state) {
  80         case S_STARTING:
  81         case S_RECOVERY:
  82         case S_STOPPING:
  83         case S_TERMINATE:
  84             crm_warn("Not voting in election, we're in state %s", fsa_state2string(cur_state));
  85             not_voting = TRUE;
  86             break;
  87         case S_ELECTION:
  88         case S_INTEGRATION:
  89         case S_RELEASE_DC:
  90             break;
  91         default:
  92             crm_err("Broken? Voting in state %s", fsa_state2string(cur_state));
  93             break;
  94     }
  95 
  96     if (not_voting == FALSE) {
  97         if (pcmk_is_set(controld_globals.fsa_input_register, R_STARTING)) {
  98             not_voting = TRUE;
  99         }
 100     }
 101 
 102     if (not_voting) {
 103         if (AM_I_DC) {
 104             register_fsa_input(C_FSA_INTERNAL, I_RELEASE_DC, NULL);
 105 
 106         } else {
 107             register_fsa_input(C_FSA_INTERNAL, I_PENDING, NULL);
 108         }
 109         return;
 110     }
 111 
 112     election_vote(controld_globals.cluster);
 113     return;
 114 }
 115 
 116 void
 117 do_election_check(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 118                   enum crmd_fsa_cause cause,
 119                   enum crmd_fsa_state cur_state,
 120                   enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 121 {
 122     if (controld_globals.fsa_state == S_ELECTION) {
 123         election_check(controld_globals.cluster);
 124     } else {
 125         crm_debug("Ignoring election check because we are not in an election");
 126     }
 127 }
 128 
 129 /*      A_ELECTION_COUNT        */
 130 void
 131 do_election_count_vote(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 132                        enum crmd_fsa_cause cause,
 133                        enum crmd_fsa_state cur_state,
 134                        enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 135 {
 136     enum election_result rc = 0;
 137     ha_msg_input_t *vote = fsa_typed_data(fsa_dt_ha_msg);
 138 
 139     if (pcmk__peer_cache == NULL) {
 140         if (!pcmk_is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
 141             crm_err("Internal error, no peer cache");
 142         }
 143         return;
 144     }
 145 
 146     rc = election_count_vote(controld_globals.cluster, vote->msg,
 147                              (cur_state != S_STARTING));
 148     switch(rc) {
 149         case election_start:
 150             election_reset(controld_globals.cluster);
 151             register_fsa_input(C_FSA_INTERNAL, I_ELECTION, NULL);
 152             break;
 153 
 154         case election_lost:
 155             update_dc(NULL);
 156 
 157             if (pcmk_is_set(controld_globals.fsa_input_register, R_THE_DC)) {
 158                 cib_t *cib_conn = controld_globals.cib_conn;
 159 
 160                 register_fsa_input(C_FSA_INTERNAL, I_RELEASE_DC, NULL);
 161                 cib_conn->cmds->set_secondary(cib_conn, cib_none);
 162 
 163             } else if (cur_state != S_STARTING) {
 164                 register_fsa_input(C_FSA_INTERNAL, I_PENDING, NULL);
 165             }
 166             break;
 167 
 168         default:
 169             crm_trace("Election message resulted in state %d", rc);
 170     }
 171 }
 172 
 173 static void
 174 feature_update_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 175 {
 176     if (rc != pcmk_ok) {
 177         fsa_data_t *msg_data = NULL;
 178 
 179         crm_notice("Feature update failed: %s " QB_XS " rc=%d",
 180                    pcmk_strerror(rc), rc);
 181         register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
 182     }
 183 }
 184 
 185 /*!
 186  * \internal
 187  * \brief Update a node attribute in the CIB during a DC takeover
 188  *
 189  * \param[in] name   Name of attribute to update
 190  * \param[in] value  New attribute value
 191  */
 192 #define dc_takeover_update_attr(name, value) do {                           \
 193        cib__update_node_attr(controld_globals.logger_out,                   \
 194                              controld_globals.cib_conn, cib_none,           \
 195                              PCMK_XE_CRM_CONFIG, NULL, NULL, NULL, NULL,    \
 196                              name, value, NULL, NULL);                      \
 197     } while (0)
 198 
 199 /*       A_DC_TAKEOVER  */
 200 void
 201 do_dc_takeover(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 202                enum crmd_fsa_cause cause,
 203                enum crmd_fsa_state cur_state,
 204                enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 205 {
 206     xmlNode *cib = NULL;
 207     const enum pcmk_cluster_layer cluster_layer = pcmk_get_cluster_layer();
 208     const char *cluster_layer_s = pcmk_cluster_layer_text(cluster_layer);
 209     pid_t watchdog = pcmk__locate_sbd();
 210 
 211     crm_info("Taking over DC status for this partition");
 212     controld_set_fsa_input_flags(R_THE_DC);
 213     execute_stonith_cleanup();
 214 
 215     election_reset(controld_globals.cluster);
 216     controld_set_fsa_input_flags(R_JOIN_OK|R_INVOKE_PE);
 217 
 218     controld_globals.cib_conn->cmds->set_primary(controld_globals.cib_conn,
 219                                                  cib_none);
 220 
 221     cib = pcmk__xe_create(NULL, PCMK_XE_CIB);
 222     crm_xml_add(cib, PCMK_XA_CRM_FEATURE_SET, CRM_FEATURE_SET);
 223     controld_update_cib(PCMK_XE_CIB, cib, cib_none, feature_update_callback);
 224 
 225     dc_takeover_update_attr(PCMK_OPT_HAVE_WATCHDOG, pcmk__btoa(watchdog));
 226     dc_takeover_update_attr(PCMK_OPT_DC_VERSION,
 227                             PACEMAKER_VERSION "-" BUILD_VERSION);
 228     dc_takeover_update_attr(PCMK_OPT_CLUSTER_INFRASTRUCTURE, cluster_layer_s);
 229 
 230 #if SUPPORT_COROSYNC
 231     if ((controld_globals.cluster_name == NULL)
 232         && (pcmk_get_cluster_layer() == pcmk_cluster_layer_corosync)) {
 233 
 234         char *cluster_name = pcmk__corosync_cluster_name();
 235 
 236         if (cluster_name != NULL) {
 237             dc_takeover_update_attr(PCMK_OPT_CLUSTER_NAME, cluster_name);
 238         }
 239         free(cluster_name);
 240     }
 241 #endif
 242 
 243     controld_trigger_config();
 244     pcmk__xml_free(cib);
 245 }
 246 
 247 /*       A_DC_RELEASE   */
 248 void
 249 do_dc_release(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 250               enum crmd_fsa_cause cause,
 251               enum crmd_fsa_state cur_state,
 252               enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 253 {
 254     if (action & A_DC_RELEASE) {
 255         crm_debug("Releasing the role of DC");
 256         controld_clear_fsa_input_flags(R_THE_DC);
 257         controld_expect_sched_reply(NULL);
 258 
 259     } else if (action & A_DC_RELEASED) {
 260         crm_info("DC role released");
 261         if (pcmk_is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
 262             xmlNode *update = NULL;
 263             pcmk__node_status_t *node = controld_get_local_node_status();
 264 
 265             pcmk__update_peer_expected(__func__, node, CRMD_JOINSTATE_DOWN);
 266             update = create_node_state_update(node, node_update_expected, NULL,
 267                                               __func__);
 268             /* Don't need a based response because controld will stop. */
 269             fsa_cib_anon_update_discard_reply(PCMK_XE_STATUS, update);
 270             pcmk__xml_free(update);
 271         }
 272         register_fsa_input(C_FSA_INTERNAL, I_RELEASE_SUCCESS, NULL);
 273 
 274     } else {
 275         crm_err("Unknown DC action %s", fsa_action2string(action));
 276     }
 277 
 278     crm_trace("Am I still the DC? %s", pcmk__btoa(AM_I_DC));
 279 }

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