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

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