1 /*
2 * Copyright 2004-2026 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 <inttypes.h> // PRIx64
13 #include <sys/param.h>
14 #include <stdio.h>
15 #include <stdint.h> // uint8_t, uint64_t
16 #include <string.h>
17 #include <time.h>
18
19 #include <crm/crm.h>
20 #include <crm/lrmd.h>
21 #include <crm/cib.h>
22 #include <crm/common/xml.h>
23 #include <crm/cluster/election_internal.h>
24 #include <crm/cluster.h>
25
26 #include <pacemaker-controld.h>
27
28 //! Triggers an FSA invocation
29 static crm_trigger_t *fsa_trigger = NULL;
30
31 static void do_state_transition(enum crmd_fsa_state cur_state,
32 enum crmd_fsa_state next_state,
33 fsa_data_t *msg_data);
34
35 void s_crmd_fsa_actions(fsa_data_t * fsa_data);
36
37 static void
38 do_fsa_action(fsa_data_t * fsa_data, long long an_action,
39 void (*function) (long long action,
40 enum crmd_fsa_cause cause,
41 enum crmd_fsa_state cur_state,
42 enum crmd_fsa_input cur_input, fsa_data_t * msg_data))
43 {
44 controld_clear_fsa_action_flags(an_action);
45 function(an_action, fsa_data->fsa_cause, controld_globals.fsa_state,
46 fsa_data->fsa_input, fsa_data);
47 }
48
49 static const uint64_t startup_actions =
50 A_STARTUP | A_CIB_START | A_LRM_CONNECT | A_HA_CONNECT | A_READCONFIG |
51 A_STARTED | A_CL_JOIN_QUERY;
52
53 // A_LOG, A_WARN, A_ERROR
54 static void
55 do_log(long long action, enum crmd_fsa_cause cause,
56 enum crmd_fsa_state cur_state,
57 enum crmd_fsa_input current_input, fsa_data_t *msg_data)
58 {
59 uint8_t log_type = LOG_TRACE;
60
61 pcmk__assert(msg_data != NULL);
62
63 // @TODO Should the order of precedence be reversed?
64 if (pcmk__is_set(action, A_LOG)) {
65 log_type = LOG_INFO;
66 } else if (pcmk__is_set(action, A_WARN)) {
67 log_type = LOG_WARNING;
68 } else if (pcmk__is_set(action, A_ERROR)) {
69 log_type = LOG_ERR;
70 }
71
72 do_crm_log(log_type, "Input %s received in state %s from %s",
73 fsa_input2string(msg_data->fsa_input),
74 fsa_state2string(cur_state), msg_data->origin);
75
76 if (msg_data->data != NULL) {
77 pcmk__log_xml_debug(msg_data->data->msg, __func__);
78 }
79 }
80
81 /*!
82 * \internal
83 * \brief Initialize the FSA trigger
84 */
85 void
86 controld_init_fsa_trigger(void)
87 {
88 fsa_trigger = mainloop_add_trigger(G_PRIORITY_HIGH, crm_fsa_trigger, NULL);
89 }
90
91 /*!
92 * \internal
93 * \brief Destroy the FSA trigger
94 */
95 void
96 controld_destroy_fsa_trigger(void)
97 {
98 // This basically will not work, since mainloop has a reference to it
|
CID (unavailable; MK=3880079d3ed1a02ccbd3cca0687b0df9) (#1 of 1): Inconsistent C union access (INCONSISTENT_UNION_ACCESS): |
|
(1) Event assign_union_field: |
The union field "in" of "_pp" is written. |
|
(2) Event inconsistent_union_field_access: |
In "_pp.out", the union field used: "out" is inconsistent with the field most recently stored: "in". |
99 g_clear_pointer(&fsa_trigger, mainloop_destroy_trigger);
100 }
101
102 /*!
103 * \internal
104 * \brief Trigger an FSA invocation
105 *
106 * \param[in] fn Calling function name
107 * \param[in] line Line number where call occurred
108 */
109 void
110 controld_trigger_fsa_as(const char *fn, int line)
111 {
112 if (fsa_trigger != NULL) {
113 pcmk__trace("%s:%d - Triggered FSA invocation", fn, line);
114 mainloop_set_trigger(fsa_trigger);
115 }
116 }
117
118 static void
119 log_fsa_input(fsa_data_t *stored_msg)
120 {
121 pcmk__assert(stored_msg != NULL);
122 pcmk__trace("Processing queued input %llu", stored_msg->id);
123
124 if (stored_msg->data == NULL) {
125 pcmk__trace("FSA processing input from %s", stored_msg->origin);
126
127 } else {
128 pcmk__trace("FSA processing XML message from %s", stored_msg->origin);
129 pcmk__log_xml_trace(stored_msg->data->xml, "FSA message data");
130 }
131 }
132
133 static void
134 log_fsa_data(gpointer data, gpointer user_data)
135 {
136 fsa_data_t *fsa_data = data;
137 unsigned int *offset = user_data;
138
139 pcmk__trace("queue[%u.%llu]: input %s submitted by %s (%p) (cause=%s)",
140 (*offset)++, fsa_data->id,
141 fsa_input2string(fsa_data->fsa_input), fsa_data->origin,
142 fsa_data->data, fsa_cause2string(fsa_data->fsa_cause));
143 }
144
145 enum crmd_fsa_state
146 s_crmd_fsa(enum crmd_fsa_cause cause)
147 {
148 controld_globals_t *globals = &controld_globals;
149 fsa_data_t *fsa_data = NULL;
150 uint64_t register_copy = controld_globals.fsa_input_register;
151 uint64_t new_actions = A_NOTHING;
152 enum crmd_fsa_state last_state;
153
154 pcmk__trace("FSA invoked with Cause: %s\tState: %s",
155 fsa_cause2string(cause),
156 fsa_state2string(globals->fsa_state));
157
158 fsa_dump_actions(controld_globals.fsa_actions, "Initial");
159
160 controld_clear_global_flags(controld_fsa_is_stalled);
161 if ((controld_fsa_message_queue_length() == 0)
162 && (controld_globals.fsa_actions != A_NOTHING)) {
163
164 /* Fake the first message so that we can enter the loop.
165 *
166 * There are already actions to perform. Everything in the loop is a
167 * no-op for this fake message, except the following:
168 * * controld_clear_fsa_action_flags(startup_actions)
169 * * s_crmd_fsa_actions(fsa_data)
170 *
171 * We would still need this fake message even if we changed the loop
172 * condition. s_crmd_fsa_actions() needs an fsa_data_t object so that we
173 * can process the already-pending actions. So a larger refactor would
174 * be required in order to get rid of this.
175 *
176 * We can't call controld_fsa_append() because it currently won't add a
177 * message with I_NULL and A_NOTHING (like this one).
178 */
179 fsa_data = pcmk__assert_alloc(1, sizeof(fsa_data_t));
180 fsa_data->fsa_input = I_NULL;
181 fsa_data->fsa_cause = C_FSA_INTERNAL;
182 fsa_data->origin = __func__;
183
184 if (controld_globals.fsa_message_queue == NULL) {
185 controld_globals.fsa_message_queue = g_queue_new();
186 }
187 g_queue_push_tail(controld_globals.fsa_message_queue, fsa_data);
188 }
189
190 while ((controld_fsa_message_queue_length() > 0)
191 && !pcmk__is_set(controld_globals.flags, controld_fsa_is_stalled)) {
192
193 pcmk__trace("Checking messages (%u remaining)",
194 controld_fsa_message_queue_length());
195
196 fsa_data =
197 (fsa_data_t *) g_queue_pop_head(controld_globals.fsa_message_queue);
198
199 if (fsa_data == NULL) {
200 continue;
201 }
202
203 log_fsa_input(fsa_data);
204
205 /* add any actions back to the queue */
206 controld_set_fsa_action_flags(fsa_data->actions);
207 fsa_dump_actions(fsa_data->actions, "Restored actions");
208
209 /* get the next batch of actions */
210 new_actions = controld_fsa_get_action(fsa_data->fsa_input);
211 controld_set_fsa_action_flags(new_actions);
212 fsa_dump_actions(new_actions, "New actions");
213
214 if (fsa_data->fsa_input != I_NULL && fsa_data->fsa_input != I_ROUTER) {
215 pcmk__debug("Processing %s: [ state=%s cause=%s origin=%s ]",
216 fsa_input2string(fsa_data->fsa_input),
217 fsa_state2string(globals->fsa_state),
218 fsa_cause2string(fsa_data->fsa_cause),
219 fsa_data->origin);
220 }
221
222 /* logging : *before* the state is changed */
223 if (pcmk__is_set(controld_globals.fsa_actions, A_ERROR)) {
224 do_fsa_action(fsa_data, A_ERROR, do_log);
225 }
226 if (pcmk__is_set(controld_globals.fsa_actions, A_WARN)) {
227 do_fsa_action(fsa_data, A_WARN, do_log);
228 }
229 if (pcmk__is_set(controld_globals.fsa_actions, A_LOG)) {
230 do_fsa_action(fsa_data, A_LOG, do_log);
231 }
232
233 /* update state variables */
234 last_state = globals->fsa_state;
235 globals->fsa_state = controld_fsa_get_next_state(fsa_data->fsa_input);
236
237 /*
238 * Remove certain actions during shutdown
239 */
240 if ((globals->fsa_state == S_STOPPING)
241 || pcmk__is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
242 controld_clear_fsa_action_flags(startup_actions);
243 }
244
245 /*
246 * Hook for change of state.
247 * Allows actions to be added or removed when entering a state
248 */
249 if (last_state != globals->fsa_state) {
250 do_state_transition(last_state, globals->fsa_state, fsa_data);
251 }
252
253 /* start doing things... */
254 s_crmd_fsa_actions(fsa_data);
255 delete_fsa_input(fsa_data);
256 }
257
258 if ((controld_fsa_message_queue_length() > 0)
259 || (controld_globals.fsa_actions != A_NOTHING)
260 || pcmk__is_set(controld_globals.flags, controld_fsa_is_stalled)) {
261
262 pcmk__debug("Exiting the FSA: queue=%u, fsa_actions=%" PRIx64
263 ", stalled=%s",
264 controld_fsa_message_queue_length(),
265 controld_globals.fsa_actions,
266 pcmk__flag_text(controld_globals.flags,
267 controld_fsa_is_stalled));
268 } else {
269 pcmk__trace("Exiting the FSA");
270 }
271
272 /* cleanup inputs? */
273 if (register_copy != controld_globals.fsa_input_register) {
274 uint64_t same = register_copy & controld_globals.fsa_input_register;
275
276 fsa_dump_inputs(LOG_DEBUG, "Added",
277 controld_globals.fsa_input_register ^ same);
278 fsa_dump_inputs(LOG_DEBUG, "Removed", register_copy ^ same);
279 }
280
281 fsa_dump_actions(controld_globals.fsa_actions, "Remaining");
282 pcmk__if_tracing(
283 {
284 unsigned int offset = 0;
285
286 g_queue_foreach(controld_globals.fsa_message_queue, log_fsa_data,
287 &offset);
288 },
289 {}
290 );
291
292 return globals->fsa_state;
293 }
294
295 void
296 s_crmd_fsa_actions(fsa_data_t * fsa_data)
297 {
298 /*
299 * Process actions in order of priority but do only one
300 * action at a time to avoid complicating the ordering.
301 */
302 CRM_CHECK(fsa_data != NULL, return);
303 while ((controld_globals.fsa_actions != A_NOTHING)
304 && !pcmk__is_set(controld_globals.flags, controld_fsa_is_stalled)) {
305
306 /* regular action processing in order of action priority
307 *
308 * Make sure all actions that connect to required systems
309 * are performed first
310 */
311 if (pcmk__is_set(controld_globals.fsa_actions, A_ERROR)) {
312 do_fsa_action(fsa_data, A_ERROR, do_log);
313 } else if (pcmk__is_set(controld_globals.fsa_actions, A_WARN)) {
314 do_fsa_action(fsa_data, A_WARN, do_log);
315 } else if (pcmk__is_set(controld_globals.fsa_actions, A_LOG)) {
316 do_fsa_action(fsa_data, A_LOG, do_log);
317
318 /* get out of here NOW! before anything worse happens */
319 } else if (pcmk__is_set(controld_globals.fsa_actions, A_EXIT_1)) {
320 do_fsa_action(fsa_data, A_EXIT_1, do_exit);
321
322 /* sub-system restart */
323 } else if (pcmk__all_flags_set(controld_globals.fsa_actions,
324 O_LRM_RECONNECT)) {
325 do_fsa_action(fsa_data, O_LRM_RECONNECT, do_lrm_control);
326
327 } else if (pcmk__all_flags_set(controld_globals.fsa_actions,
328 O_CIB_RESTART)) {
329 do_fsa_action(fsa_data, O_CIB_RESTART, do_cib_control);
330
331 } else if (pcmk__all_flags_set(controld_globals.fsa_actions,
332 O_PE_RESTART)) {
333 do_fsa_action(fsa_data, O_PE_RESTART, do_pe_control);
334
335 } else if (pcmk__all_flags_set(controld_globals.fsa_actions,
336 O_TE_RESTART)) {
337 do_fsa_action(fsa_data, O_TE_RESTART, do_te_control);
338
339 /* essential start tasks */
340 } else if (pcmk__is_set(controld_globals.fsa_actions, A_STARTUP)) {
341 do_fsa_action(fsa_data, A_STARTUP, do_startup);
342 } else if (pcmk__is_set(controld_globals.fsa_actions, A_CIB_START)) {
343 do_fsa_action(fsa_data, A_CIB_START, do_cib_control);
344 } else if (pcmk__is_set(controld_globals.fsa_actions, A_HA_CONNECT)) {
345 do_fsa_action(fsa_data, A_HA_CONNECT, do_ha_control);
346 } else if (pcmk__is_set(controld_globals.fsa_actions, A_READCONFIG)) {
347 do_fsa_action(fsa_data, A_READCONFIG, do_read_config);
348
349 /* sub-system start/connect */
350 } else if (pcmk__is_set(controld_globals.fsa_actions, A_LRM_CONNECT)) {
351 do_fsa_action(fsa_data, A_LRM_CONNECT, do_lrm_control);
352 } else if (pcmk__is_set(controld_globals.fsa_actions, A_TE_START)) {
353 do_fsa_action(fsa_data, A_TE_START, do_te_control);
354 } else if (pcmk__is_set(controld_globals.fsa_actions, A_PE_START)) {
355 do_fsa_action(fsa_data, A_PE_START, do_pe_control);
356
357 /* Timers */
358 } else if (pcmk__is_set(controld_globals.fsa_actions,
359 A_DC_TIMER_STOP)) {
360 do_fsa_action(fsa_data, A_DC_TIMER_STOP, do_timer_control);
361 } else if (pcmk__is_set(controld_globals.fsa_actions,
362 A_INTEGRATE_TIMER_STOP)) {
363 do_fsa_action(fsa_data, A_INTEGRATE_TIMER_STOP, do_timer_control);
364 } else if (pcmk__is_set(controld_globals.fsa_actions,
365 A_INTEGRATE_TIMER_START)) {
366 do_fsa_action(fsa_data, A_INTEGRATE_TIMER_START, do_timer_control);
367 } else if (pcmk__is_set(controld_globals.fsa_actions,
368 A_FINALIZE_TIMER_STOP)) {
369 do_fsa_action(fsa_data, A_FINALIZE_TIMER_STOP, do_timer_control);
370 } else if (pcmk__is_set(controld_globals.fsa_actions,
371 A_FINALIZE_TIMER_START)) {
372 do_fsa_action(fsa_data, A_FINALIZE_TIMER_START, do_timer_control);
373
374 /*
375 * Highest priority actions
376 */
377 } else if (pcmk__is_set(controld_globals.fsa_actions, A_MSG_ROUTE)) {
378 do_fsa_action(fsa_data, A_MSG_ROUTE, do_msg_route);
379 } else if (pcmk__is_set(controld_globals.fsa_actions, A_RECOVER)) {
380 do_fsa_action(fsa_data, A_RECOVER, do_recover);
381 } else if (pcmk__is_set(controld_globals.fsa_actions,
382 A_CL_JOIN_RESULT)) {
383 do_fsa_action(fsa_data, A_CL_JOIN_RESULT,
384 do_cl_join_finalize_respond);
385
386 } else if (pcmk__is_set(controld_globals.fsa_actions,
387 A_CL_JOIN_REQUEST)) {
388 do_fsa_action(fsa_data, A_CL_JOIN_REQUEST,
389 do_cl_join_offer_respond);
390
391 } else if (pcmk__is_set(controld_globals.fsa_actions, A_SHUTDOWN_REQ)) {
392 do_fsa_action(fsa_data, A_SHUTDOWN_REQ, do_shutdown_req);
393 } else if (pcmk__is_set(controld_globals.fsa_actions,
394 A_ELECTION_VOTE)) {
395 do_fsa_action(fsa_data, A_ELECTION_VOTE, do_election_vote);
396 } else if (pcmk__is_set(controld_globals.fsa_actions,
397 A_ELECTION_COUNT)) {
398 do_fsa_action(fsa_data, A_ELECTION_COUNT, do_election_count_vote);
399
400 /*
401 * High priority actions
402 */
403 } else if (pcmk__is_set(controld_globals.fsa_actions, A_STARTED)) {
404 do_fsa_action(fsa_data, A_STARTED, do_started);
405 } else if (pcmk__is_set(controld_globals.fsa_actions,
406 A_CL_JOIN_QUERY)) {
407 do_fsa_action(fsa_data, A_CL_JOIN_QUERY, do_cl_join_query);
408 } else if (pcmk__is_set(controld_globals.fsa_actions,
409 A_DC_TIMER_START)) {
410 do_fsa_action(fsa_data, A_DC_TIMER_START, do_timer_control);
411
412 /*
413 * Medium priority actions
414 * - Membership
415 */
416 } else if (pcmk__is_set(controld_globals.fsa_actions, A_DC_TAKEOVER)) {
417 do_fsa_action(fsa_data, A_DC_TAKEOVER, do_dc_takeover);
418 } else if (pcmk__is_set(controld_globals.fsa_actions, A_DC_RELEASE)) {
419 do_fsa_action(fsa_data, A_DC_RELEASE, do_dc_release);
420 } else if (pcmk__is_set(controld_globals.fsa_actions,
421 A_DC_JOIN_FINAL)) {
422 do_fsa_action(fsa_data, A_DC_JOIN_FINAL, do_dc_join_final);
423 } else if (pcmk__is_set(controld_globals.fsa_actions,
424 A_ELECTION_CHECK)) {
425 do_fsa_action(fsa_data, A_ELECTION_CHECK, do_election_check);
426
427 } else if (pcmk__is_set(controld_globals.fsa_actions,
428 A_ELECTION_START)) {
429 do_fsa_action(fsa_data, A_ELECTION_START, do_election_vote);
430
431 } else if (pcmk__is_set(controld_globals.fsa_actions,
432 A_DC_JOIN_OFFER_ALL)) {
433 do_fsa_action(fsa_data, A_DC_JOIN_OFFER_ALL, do_dc_join_offer_all);
434
435 } else if (pcmk__is_set(controld_globals.fsa_actions,
436 A_DC_JOIN_OFFER_ONE)) {
437 do_fsa_action(fsa_data, A_DC_JOIN_OFFER_ONE, do_dc_join_offer_one);
438
439 } else if (pcmk__is_set(controld_globals.fsa_actions,
440 A_DC_JOIN_PROCESS_REQ)) {
441 do_fsa_action(fsa_data, A_DC_JOIN_PROCESS_REQ,
442 do_dc_join_filter_offer);
443
444 } else if (pcmk__is_set(controld_globals.fsa_actions,
445 A_DC_JOIN_PROCESS_ACK)) {
446 do_fsa_action(fsa_data, A_DC_JOIN_PROCESS_ACK, do_dc_join_ack);
447
448 } else if (pcmk__is_set(controld_globals.fsa_actions,
449 A_DC_JOIN_FINALIZE)) {
450 do_fsa_action(fsa_data, A_DC_JOIN_FINALIZE, do_dc_join_finalize);
451
452 } else if (pcmk__is_set(controld_globals.fsa_actions,
453 A_CL_JOIN_ANNOUNCE)) {
454 do_fsa_action(fsa_data, A_CL_JOIN_ANNOUNCE, do_cl_join_announce);
455
456 /*
457 * Low(er) priority actions
458 * Make sure the CIB is always updated before invoking the
459 * scheduler, and the scheduler before the transition engine.
460 */
461 } else if (pcmk__is_set(controld_globals.fsa_actions, A_TE_HALT)) {
462 do_fsa_action(fsa_data, A_TE_HALT, do_te_invoke);
463 } else if (pcmk__is_set(controld_globals.fsa_actions, A_TE_CANCEL)) {
464 do_fsa_action(fsa_data, A_TE_CANCEL, do_te_invoke);
465 } else if (pcmk__is_set(controld_globals.fsa_actions, A_PE_INVOKE)) {
466 do_fsa_action(fsa_data, A_PE_INVOKE, do_pe_invoke);
467 } else if (pcmk__is_set(controld_globals.fsa_actions, A_TE_INVOKE)) {
468 do_fsa_action(fsa_data, A_TE_INVOKE, do_te_invoke);
469
470 /* Shutdown actions */
471 } else if (pcmk__is_set(controld_globals.fsa_actions, A_DC_RELEASED)) {
472 do_fsa_action(fsa_data, A_DC_RELEASED, do_dc_release);
473 } else if (pcmk__is_set(controld_globals.fsa_actions, A_PE_STOP)) {
474 do_fsa_action(fsa_data, A_PE_STOP, do_pe_control);
475 } else if (pcmk__is_set(controld_globals.fsa_actions, A_TE_STOP)) {
476 do_fsa_action(fsa_data, A_TE_STOP, do_te_control);
477 } else if (pcmk__is_set(controld_globals.fsa_actions, A_SHUTDOWN)) {
478 do_fsa_action(fsa_data, A_SHUTDOWN, do_shutdown);
479 } else if (pcmk__is_set(controld_globals.fsa_actions,
480 A_LRM_DISCONNECT)) {
481 do_fsa_action(fsa_data, A_LRM_DISCONNECT, do_lrm_control);
482
483 } else if (pcmk__is_set(controld_globals.fsa_actions,
484 A_HA_DISCONNECT)) {
485 do_fsa_action(fsa_data, A_HA_DISCONNECT, do_ha_control);
486 } else if (pcmk__is_set(controld_globals.fsa_actions, A_CIB_STOP)) {
487 do_fsa_action(fsa_data, A_CIB_STOP, do_cib_control);
488 } else if (pcmk__is_set(controld_globals.fsa_actions, A_STOP)) {
489 do_fsa_action(fsa_data, A_STOP, do_stop);
490
491 /* exit gracefully */
492 } else if (pcmk__is_set(controld_globals.fsa_actions, A_EXIT_0)) {
493 do_fsa_action(fsa_data, A_EXIT_0, do_exit);
494
495 /* Error checking and reporting */
496 } else {
497 pcmk__err("Action %s not supported " QB_XS " %" PRIx64,
498 fsa_action2string(controld_globals.fsa_actions),
499 controld_globals.fsa_actions);
500 register_fsa_error(I_ERROR, fsa_data);
501 }
502 }
503 }
504
505 static void
506 check_join_counts(fsa_data_t *msg_data)
507 {
508 int count;
509 guint npeers;
510
511 count = crmd_join_phase_count(controld_join_finalized);
512 if (count > 0) {
513 pcmk__err("%d cluster node%s failed to confirm join", count,
514 pcmk__plural_s(count));
515 crmd_join_phase_log(LOG_NOTICE);
516 return;
517 }
518
519 npeers = pcmk__cluster_num_active_nodes();
520 count = crmd_join_phase_count(controld_join_confirmed);
521 if (count == npeers) {
522 if (npeers == 1) {
523 pcmk__debug("Sole active cluster node is fully joined");
524 } else {
525 pcmk__debug("All %d active cluster nodes are fully joined", count);
526 }
527
528 } else if (count > npeers) {
529 pcmk__err("New election needed because more nodes confirmed join "
530 "than are in membership (%d > %u)", count, npeers);
531 controld_fsa_append(C_FSA_INTERNAL, I_ELECTION, NULL);
532
533 } else if (controld_globals.membership_id != controld_globals.peer_seq) {
534 pcmk__info("New join needed because membership changed (%llu -> %llu)",
535 controld_globals.membership_id, controld_globals.peer_seq);
536 controld_fsa_prepend(C_FSA_INTERNAL, I_NODE_JOIN, NULL);
537
538 } else {
539 pcmk__warn("Only %d of %u active cluster nodes fully joined (%d did "
540 "not respond to offer)",
541 count, npeers,
542 crmd_join_phase_count(controld_join_welcomed));
543 }
544 }
545
546 static void
547 do_state_transition(enum crmd_fsa_state cur_state,
548 enum crmd_fsa_state next_state, fsa_data_t *msg_data)
549 {
550 int level = LOG_INFO;
551 int count = 0;
552 gboolean clear_recovery_bit = TRUE;
553 #if 0
554 uint64_t original_fsa_actions = controld_globals.fsa_actions;
555 #endif
556
557 enum crmd_fsa_cause cause = msg_data->fsa_cause;
558 enum crmd_fsa_input current_input = msg_data->fsa_input;
559
560 const char *state_from = fsa_state2string(cur_state);
561 const char *state_to = fsa_state2string(next_state);
562 const char *input = fsa_input2string(current_input);
563
564 CRM_LOG_ASSERT(cur_state != next_state);
565
566 if (cur_state == S_IDLE || next_state == S_IDLE) {
567 level = LOG_NOTICE;
568 } else if (cur_state == S_NOT_DC || next_state == S_NOT_DC) {
569 level = LOG_NOTICE;
570 } else if (cur_state == S_ELECTION) {
571 level = LOG_NOTICE;
572 } else if (cur_state == S_STARTING) {
573 level = LOG_NOTICE;
574 } else if (next_state == S_RECOVERY) {
575 level = LOG_WARNING;
576 }
577
578 do_crm_log(level, "State transition %s -> %s "
579 QB_XS " input=%s cause=%s origin=%s",
580 state_from, state_to, input, fsa_cause2string(cause),
581 msg_data->origin);
582
583 if (next_state != S_ELECTION && cur_state != S_RELEASE_DC) {
584 controld_stop_current_election_timeout();
585 }
586 if (next_state == S_INTEGRATION) {
587 controld_set_fsa_action_flags(A_INTEGRATE_TIMER_START);
588 } else {
589 controld_set_fsa_action_flags(A_INTEGRATE_TIMER_STOP);
590 }
591
592 if (next_state == S_FINALIZE_JOIN) {
593 controld_set_fsa_action_flags(A_FINALIZE_TIMER_START);
594 } else {
595 controld_set_fsa_action_flags(A_FINALIZE_TIMER_STOP);
596 }
597
598 if (next_state != S_PENDING) {
599 controld_set_fsa_action_flags(A_DC_TIMER_STOP);
600 }
601 if (next_state != S_IDLE) {
602 controld_stop_recheck_timer();
603 }
604
605 if (cur_state == S_FINALIZE_JOIN && next_state == S_POLICY_ENGINE) {
606 populate_cib_nodes(controld_node_update_quick|controld_node_update_all,
607 __func__);
608 }
609
610 switch (next_state) {
611 case S_PENDING:
612 {
613 cib_t *cib_conn = controld_globals.cib_conn;
614 cib_conn->cmds->set_secondary(cib_conn, cib_none);
615 }
616 update_dc(NULL);
617 break;
618
619 case S_ELECTION:
620 update_dc(NULL);
621 break;
622
623 case S_NOT_DC:
624 controld_reset_counter_election_timer();
625 controld_purge_fencing_cleanup();
626
627 if (pcmk__is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
628 pcmk__info("(Re)Issuing shutdown request now that we have a "
629 "new DC");
630 controld_set_fsa_action_flags(A_SHUTDOWN_REQ);
631 }
632 CRM_LOG_ASSERT(controld_globals.dc_name != NULL);
633 if (controld_globals.dc_name == NULL) {
634 pcmk__err("Reached S_NOT_DC without a DC being recorded");
635 }
636 break;
637
638 case S_RECOVERY:
639 clear_recovery_bit = FALSE;
640 break;
641
642 case S_FINALIZE_JOIN:
643 CRM_LOG_ASSERT(AM_I_DC);
644 if (cause == C_TIMER_POPPED) {
645 pcmk__warn("Progressed to state %s after %s",
646 fsa_state2string(next_state),
647 fsa_cause2string(cause));
648 }
649 count = crmd_join_phase_count(controld_join_welcomed);
650 if (count > 0) {
651 pcmk__warn("%d cluster node%s failed to respond to join offer",
652 count, pcmk__plural_s(count));
653 crmd_join_phase_log(LOG_NOTICE);
654
655 } else {
656 pcmk__debug("All cluster nodes (%d) responded to join offer",
657 crmd_join_phase_count(controld_join_integrated));
658 }
659 break;
660
661 case S_POLICY_ENGINE:
662 controld_reset_counter_election_timer();
663 CRM_LOG_ASSERT(AM_I_DC);
664 if (cause == C_TIMER_POPPED) {
665 pcmk__info("Progressed to state %s after %s",
666 fsa_state2string(next_state),
667 fsa_cause2string(cause));
668 }
669 check_join_counts(msg_data);
670 break;
671
672 case S_STOPPING:
673 case S_TERMINATE:
674 /* possibly redundant */
675 controld_set_fsa_input_flags(R_SHUTDOWN);
676 break;
677
678 case S_IDLE:
679 CRM_LOG_ASSERT(AM_I_DC);
680 if (pcmk__is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
681 pcmk__info("(Re)Issuing shutdown request now that we are the "
682 "DC");
683 controld_set_fsa_action_flags(A_SHUTDOWN_REQ);
684 }
685 controld_start_recheck_timer();
686 break;
687
688 default:
689 break;
690 }
691
692 if (clear_recovery_bit && next_state != S_PENDING) {
693 controld_clear_fsa_action_flags(A_RECOVER);
694 } else if (clear_recovery_bit == FALSE) {
695 controld_set_fsa_action_flags(A_RECOVER);
696 }
697
698 #if 0
699 if (original_fsa_actions != controld_globals.fsa_actions) {
700 fsa_dump_actions(original_fsa_actions ^ controld_globals.fsa_actions,
701 "New actions");
702 }
703 #endif
704 }
705