1 /*
2  * Copyright 2004-2021 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 <stdlib.h>
13 #include <stdint.h>                 // uint64_t
14 
15 #include <crm/crm.h>
16 #include <crm/cib.h>
17 #include <crm/msg_xml.h>
18 #include <crm/common/xml.h>
19 
20 #include <pacemaker-controld.h>
21 
22 const char *
fsa_input2string(enum crmd_fsa_input input)23 fsa_input2string(enum crmd_fsa_input input)
24 {
25     const char *inputAsText = NULL;
26 
27     switch (input) {
28         case I_NULL:
29             inputAsText = "I_NULL";
30             break;
31         case I_CIB_OP:
32             inputAsText = "I_CIB_OP (unused)";
33             break;
34         case I_CIB_UPDATE:
35             inputAsText = "I_CIB_UPDATE";
36             break;
37         case I_DC_TIMEOUT:
38             inputAsText = "I_DC_TIMEOUT";
39             break;
40         case I_ELECTION:
41             inputAsText = "I_ELECTION";
42             break;
43         case I_PE_CALC:
44             inputAsText = "I_PE_CALC";
45             break;
46         case I_RELEASE_DC:
47             inputAsText = "I_RELEASE_DC";
48             break;
49         case I_ELECTION_DC:
50             inputAsText = "I_ELECTION_DC";
51             break;
52         case I_ERROR:
53             inputAsText = "I_ERROR";
54             break;
55         case I_FAIL:
56             inputAsText = "I_FAIL";
57             break;
58         case I_INTEGRATED:
59             inputAsText = "I_INTEGRATED";
60             break;
61         case I_FINALIZED:
62             inputAsText = "I_FINALIZED";
63             break;
64         case I_NODE_JOIN:
65             inputAsText = "I_NODE_JOIN";
66             break;
67         case I_JOIN_OFFER:
68             inputAsText = "I_JOIN_OFFER";
69             break;
70         case I_JOIN_REQUEST:
71             inputAsText = "I_JOIN_REQUEST";
72             break;
73         case I_JOIN_RESULT:
74             inputAsText = "I_JOIN_RESULT";
75             break;
76         case I_NOT_DC:
77             inputAsText = "I_NOT_DC";
78             break;
79         case I_RECOVERED:
80             inputAsText = "I_RECOVERED";
81             break;
82         case I_RELEASE_FAIL:
83             inputAsText = "I_RELEASE_FAIL";
84             break;
85         case I_RELEASE_SUCCESS:
86             inputAsText = "I_RELEASE_SUCCESS";
87             break;
88         case I_RESTART:
89             inputAsText = "I_RESTART";
90             break;
91         case I_PE_SUCCESS:
92             inputAsText = "I_PE_SUCCESS";
93             break;
94         case I_ROUTER:
95             inputAsText = "I_ROUTER";
96             break;
97         case I_SHUTDOWN:
98             inputAsText = "I_SHUTDOWN";
99             break;
100         case I_STARTUP:
101             inputAsText = "I_STARTUP";
102             break;
103         case I_TE_SUCCESS:
104             inputAsText = "I_TE_SUCCESS";
105             break;
106         case I_STOP:
107             inputAsText = "I_STOP";
108             break;
109         case I_DC_HEARTBEAT:
110             inputAsText = "I_DC_HEARTBEAT";
111             break;
112         case I_WAIT_FOR_EVENT:
113             inputAsText = "I_WAIT_FOR_EVENT";
114             break;
115         case I_LRM_EVENT:
116             inputAsText = "I_LRM_EVENT";
117             break;
118         case I_PENDING:
119             inputAsText = "I_PENDING";
120             break;
121         case I_HALT:
122             inputAsText = "I_HALT";
123             break;
124         case I_TERMINATE:
125             inputAsText = "I_TERMINATE";
126             break;
127         case I_ILLEGAL:
128             inputAsText = "I_ILLEGAL";
129             break;
130     }
131 
132     if (inputAsText == NULL) {
133         crm_err("Input %d is unknown", input);
134         inputAsText = "<UNKNOWN_INPUT>";
135     }
136 
137     return inputAsText;
138 }
139 
140 const char *
fsa_state2string(enum crmd_fsa_state state)141 fsa_state2string(enum crmd_fsa_state state)
142 {
143     const char *stateAsText = NULL;
144 
145     switch (state) {
146         case S_IDLE:
147             stateAsText = "S_IDLE";
148             break;
149         case S_ELECTION:
150             stateAsText = "S_ELECTION";
151             break;
152         case S_INTEGRATION:
153             stateAsText = "S_INTEGRATION";
154             break;
155         case S_FINALIZE_JOIN:
156             stateAsText = "S_FINALIZE_JOIN";
157             break;
158         case S_NOT_DC:
159             stateAsText = "S_NOT_DC";
160             break;
161         case S_POLICY_ENGINE:
162             stateAsText = "S_POLICY_ENGINE";
163             break;
164         case S_RECOVERY:
165             stateAsText = "S_RECOVERY";
166             break;
167         case S_RELEASE_DC:
168             stateAsText = "S_RELEASE_DC";
169             break;
170         case S_PENDING:
171             stateAsText = "S_PENDING";
172             break;
173         case S_STOPPING:
174             stateAsText = "S_STOPPING";
175             break;
176         case S_TERMINATE:
177             stateAsText = "S_TERMINATE";
178             break;
179         case S_TRANSITION_ENGINE:
180             stateAsText = "S_TRANSITION_ENGINE";
181             break;
182         case S_STARTING:
183             stateAsText = "S_STARTING";
184             break;
185         case S_HALT:
186             stateAsText = "S_HALT";
187             break;
188         case S_ILLEGAL:
189             stateAsText = "S_ILLEGAL";
190             break;
191     }
192 
193     if (stateAsText == NULL) {
194         crm_err("State %d is unknown", state);
195         stateAsText = "<UNKNOWN_STATE>";
196     }
197 
198     return stateAsText;
199 }
200 
201 const char *
fsa_cause2string(enum crmd_fsa_cause cause)202 fsa_cause2string(enum crmd_fsa_cause cause)
203 {
204     const char *causeAsText = NULL;
205 
206     switch (cause) {
207         case C_UNKNOWN:
208             causeAsText = "C_UNKNOWN";
209             break;
210         case C_STARTUP:
211             causeAsText = "C_STARTUP";
212             break;
213         case C_IPC_MESSAGE:
214             causeAsText = "C_IPC_MESSAGE";
215             break;
216         case C_HA_MESSAGE:
217             causeAsText = "C_HA_MESSAGE";
218             break;
219         case C_TIMER_POPPED:
220             causeAsText = "C_TIMER_POPPED";
221             break;
222         case C_SHUTDOWN:
223             causeAsText = "C_SHUTDOWN";
224             break;
225         case C_LRM_OP_CALLBACK:
226             causeAsText = "C_LRM_OP_CALLBACK";
227             break;
228         case C_CRMD_STATUS_CALLBACK:
229             causeAsText = "C_CRMD_STATUS_CALLBACK";
230             break;
231         case C_FSA_INTERNAL:
232             causeAsText = "C_FSA_INTERNAL";
233             break;
234     }
235 
236     if (causeAsText == NULL) {
237         crm_err("Cause %d is unknown", cause);
238         causeAsText = "<UNKNOWN_CAUSE>";
239     }
240 
241     return causeAsText;
242 }
243 
244 const char *
fsa_action2string(long long action)245 fsa_action2string(long long action)
246 {
247     const char *actionAsText = NULL;
248 
249     switch (action) {
250 
251         case A_NOTHING:
252             actionAsText = "A_NOTHING";
253             break;
254         case A_ELECTION_START:
255             actionAsText = "A_ELECTION_START";
256             break;
257         case A_DC_JOIN_FINAL:
258             actionAsText = "A_DC_JOIN_FINAL";
259             break;
260         case A_READCONFIG:
261             actionAsText = "A_READCONFIG";
262             break;
263         case O_RELEASE:
264             actionAsText = "O_RELEASE";
265             break;
266         case A_STARTUP:
267             actionAsText = "A_STARTUP";
268             break;
269         case A_STARTED:
270             actionAsText = "A_STARTED";
271             break;
272         case A_HA_CONNECT:
273             actionAsText = "A_HA_CONNECT";
274             break;
275         case A_HA_DISCONNECT:
276             actionAsText = "A_HA_DISCONNECT";
277             break;
278         case A_LRM_CONNECT:
279             actionAsText = "A_LRM_CONNECT";
280             break;
281         case A_LRM_EVENT:
282             actionAsText = "A_LRM_EVENT";
283             break;
284         case A_LRM_INVOKE:
285             actionAsText = "A_LRM_INVOKE";
286             break;
287         case A_LRM_DISCONNECT:
288             actionAsText = "A_LRM_DISCONNECT";
289             break;
290         case O_LRM_RECONNECT:
291             actionAsText = "O_LRM_RECONNECT";
292             break;
293         case A_CL_JOIN_QUERY:
294             actionAsText = "A_CL_JOIN_QUERY";
295             break;
296         case A_DC_TIMER_STOP:
297             actionAsText = "A_DC_TIMER_STOP";
298             break;
299         case A_DC_TIMER_START:
300             actionAsText = "A_DC_TIMER_START";
301             break;
302         case A_INTEGRATE_TIMER_START:
303             actionAsText = "A_INTEGRATE_TIMER_START";
304             break;
305         case A_INTEGRATE_TIMER_STOP:
306             actionAsText = "A_INTEGRATE_TIMER_STOP";
307             break;
308         case A_FINALIZE_TIMER_START:
309             actionAsText = "A_FINALIZE_TIMER_START";
310             break;
311         case A_FINALIZE_TIMER_STOP:
312             actionAsText = "A_FINALIZE_TIMER_STOP";
313             break;
314         case A_ELECTION_COUNT:
315             actionAsText = "A_ELECTION_COUNT";
316             break;
317         case A_ELECTION_VOTE:
318             actionAsText = "A_ELECTION_VOTE";
319             break;
320         case A_ELECTION_CHECK:
321             actionAsText = "A_ELECTION_CHECK";
322             break;
323         case A_CL_JOIN_ANNOUNCE:
324             actionAsText = "A_CL_JOIN_ANNOUNCE";
325             break;
326         case A_CL_JOIN_REQUEST:
327             actionAsText = "A_CL_JOIN_REQUEST";
328             break;
329         case A_CL_JOIN_RESULT:
330             actionAsText = "A_CL_JOIN_RESULT";
331             break;
332         case A_DC_JOIN_OFFER_ALL:
333             actionAsText = "A_DC_JOIN_OFFER_ALL";
334             break;
335         case A_DC_JOIN_OFFER_ONE:
336             actionAsText = "A_DC_JOIN_OFFER_ONE";
337             break;
338         case A_DC_JOIN_PROCESS_REQ:
339             actionAsText = "A_DC_JOIN_PROCESS_REQ";
340             break;
341         case A_DC_JOIN_PROCESS_ACK:
342             actionAsText = "A_DC_JOIN_PROCESS_ACK";
343             break;
344         case A_DC_JOIN_FINALIZE:
345             actionAsText = "A_DC_JOIN_FINALIZE";
346             break;
347         case A_MSG_PROCESS:
348             actionAsText = "A_MSG_PROCESS";
349             break;
350         case A_MSG_ROUTE:
351             actionAsText = "A_MSG_ROUTE";
352             break;
353         case A_RECOVER:
354             actionAsText = "A_RECOVER";
355             break;
356         case A_DC_RELEASE:
357             actionAsText = "A_DC_RELEASE";
358             break;
359         case A_DC_RELEASED:
360             actionAsText = "A_DC_RELEASED";
361             break;
362         case A_DC_TAKEOVER:
363             actionAsText = "A_DC_TAKEOVER";
364             break;
365         case A_SHUTDOWN:
366             actionAsText = "A_SHUTDOWN";
367             break;
368         case A_SHUTDOWN_REQ:
369             actionAsText = "A_SHUTDOWN_REQ";
370             break;
371         case A_STOP:
372             actionAsText = "A_STOP  ";
373             break;
374         case A_EXIT_0:
375             actionAsText = "A_EXIT_0";
376             break;
377         case A_EXIT_1:
378             actionAsText = "A_EXIT_1";
379             break;
380         case O_CIB_RESTART:
381             actionAsText = "O_CIB_RESTART";
382             break;
383         case A_CIB_START:
384             actionAsText = "A_CIB_START";
385             break;
386         case A_CIB_STOP:
387             actionAsText = "A_CIB_STOP";
388             break;
389         case A_TE_INVOKE:
390             actionAsText = "A_TE_INVOKE";
391             break;
392         case O_TE_RESTART:
393             actionAsText = "O_TE_RESTART";
394             break;
395         case A_TE_START:
396             actionAsText = "A_TE_START";
397             break;
398         case A_TE_STOP:
399             actionAsText = "A_TE_STOP";
400             break;
401         case A_TE_HALT:
402             actionAsText = "A_TE_HALT";
403             break;
404         case A_TE_CANCEL:
405             actionAsText = "A_TE_CANCEL";
406             break;
407         case A_PE_INVOKE:
408             actionAsText = "A_PE_INVOKE";
409             break;
410         case O_PE_RESTART:
411             actionAsText = "O_PE_RESTART";
412             break;
413         case A_PE_START:
414             actionAsText = "A_PE_START";
415             break;
416         case A_PE_STOP:
417             actionAsText = "A_PE_STOP";
418             break;
419         case A_NODE_BLOCK:
420             actionAsText = "A_NODE_BLOCK";
421             break;
422         case A_UPDATE_NODESTATUS:
423             actionAsText = "A_UPDATE_NODESTATUS";
424             break;
425         case A_LOG:
426             actionAsText = "A_LOG   ";
427             break;
428         case A_ERROR:
429             actionAsText = "A_ERROR ";
430             break;
431         case A_WARN:
432             actionAsText = "A_WARN  ";
433             break;
434             /* Composite actions */
435         case A_DC_TIMER_START | A_CL_JOIN_QUERY:
436             actionAsText = "A_DC_TIMER_START|A_CL_JOIN_QUERY";
437             break;
438     }
439 
440     if (actionAsText == NULL) {
441         crm_err("Action %.16llx is unknown", action);
442         actionAsText = "<UNKNOWN_ACTION>";
443     }
444 
445     return actionAsText;
446 }
447 
448 void
fsa_dump_inputs(int log_level,const char * text,long long input_register)449 fsa_dump_inputs(int log_level, const char *text, long long input_register)
450 {
451     if (input_register == A_NOTHING) {
452         return;
453     }
454     if (text == NULL) {
455         text = "Input register contents:";
456     }
457 
458     if (pcmk_is_set(input_register, R_THE_DC)) {
459         crm_trace("%s %.16llx (R_THE_DC)", text, R_THE_DC);
460     }
461     if (pcmk_is_set(input_register, R_STARTING)) {
462         crm_trace("%s %.16llx (R_STARTING)", text, R_STARTING);
463     }
464     if (pcmk_is_set(input_register, R_SHUTDOWN)) {
465         crm_trace("%s %.16llx (R_SHUTDOWN)", text, R_SHUTDOWN);
466     }
467     if (pcmk_is_set(input_register, R_STAYDOWN)) {
468         crm_trace("%s %.16llx (R_STAYDOWN)", text, R_STAYDOWN);
469     }
470     if (pcmk_is_set(input_register, R_JOIN_OK)) {
471         crm_trace("%s %.16llx (R_JOIN_OK)", text, R_JOIN_OK);
472     }
473     if (pcmk_is_set(input_register, R_READ_CONFIG)) {
474         crm_trace("%s %.16llx (R_READ_CONFIG)", text, R_READ_CONFIG);
475     }
476     if (pcmk_is_set(input_register, R_INVOKE_PE)) {
477         crm_trace("%s %.16llx (R_INVOKE_PE)", text, R_INVOKE_PE);
478     }
479     if (pcmk_is_set(input_register, R_CIB_CONNECTED)) {
480         crm_trace("%s %.16llx (R_CIB_CONNECTED)", text, R_CIB_CONNECTED);
481     }
482     if (pcmk_is_set(input_register, R_PE_CONNECTED)) {
483         crm_trace("%s %.16llx (R_PE_CONNECTED)", text, R_PE_CONNECTED);
484     }
485     if (pcmk_is_set(input_register, R_TE_CONNECTED)) {
486         crm_trace("%s %.16llx (R_TE_CONNECTED)", text, R_TE_CONNECTED);
487     }
488     if (pcmk_is_set(input_register, R_LRM_CONNECTED)) {
489         crm_trace("%s %.16llx (R_LRM_CONNECTED)", text, R_LRM_CONNECTED);
490     }
491     if (pcmk_is_set(input_register, R_CIB_REQUIRED)) {
492         crm_trace("%s %.16llx (R_CIB_REQUIRED)", text, R_CIB_REQUIRED);
493     }
494     if (pcmk_is_set(input_register, R_PE_REQUIRED)) {
495         crm_trace("%s %.16llx (R_PE_REQUIRED)", text, R_PE_REQUIRED);
496     }
497     if (pcmk_is_set(input_register, R_TE_REQUIRED)) {
498         crm_trace("%s %.16llx (R_TE_REQUIRED)", text, R_TE_REQUIRED);
499     }
500     if (pcmk_is_set(input_register, R_REQ_PEND)) {
501         crm_trace("%s %.16llx (R_REQ_PEND)", text, R_REQ_PEND);
502     }
503     if (pcmk_is_set(input_register, R_PE_PEND)) {
504         crm_trace("%s %.16llx (R_PE_PEND)", text, R_PE_PEND);
505     }
506     if (pcmk_is_set(input_register, R_TE_PEND)) {
507         crm_trace("%s %.16llx (R_TE_PEND)", text, R_TE_PEND);
508     }
509     if (pcmk_is_set(input_register, R_RESP_PEND)) {
510         crm_trace("%s %.16llx (R_RESP_PEND)", text, R_RESP_PEND);
511     }
512     if (pcmk_is_set(input_register, R_CIB_DONE)) {
513         crm_trace("%s %.16llx (R_CIB_DONE)", text, R_CIB_DONE);
514     }
515     if (pcmk_is_set(input_register, R_HAVE_CIB)) {
516         crm_trace("%s %.16llx (R_HAVE_CIB)", text, R_HAVE_CIB);
517     }
518     if (pcmk_is_set(input_register, R_CIB_ASKED)) {
519         crm_trace("%s %.16llx (R_CIB_ASKED)", text, R_CIB_ASKED);
520     }
521     if (pcmk_is_set(input_register, R_MEMBERSHIP)) {
522         crm_trace("%s %.16llx (R_MEMBERSHIP)", text, R_MEMBERSHIP);
523     }
524     if (pcmk_is_set(input_register, R_PEER_DATA)) {
525         crm_trace("%s %.16llx (R_PEER_DATA)", text, R_PEER_DATA);
526     }
527     if (pcmk_is_set(input_register, R_IN_RECOVERY)) {
528         crm_trace("%s %.16llx (R_IN_RECOVERY)", text, R_IN_RECOVERY);
529     }
530 }
531 
532 void
fsa_dump_actions(uint64_t action,const char * text)533 fsa_dump_actions(uint64_t action, const char *text)
534 {
535     if (pcmk_is_set(action, A_READCONFIG)) {
536         crm_trace("Action %.16llx (A_READCONFIG) %s", A_READCONFIG, text);
537     }
538     if (pcmk_is_set(action, A_STARTUP)) {
539         crm_trace("Action %.16llx (A_STARTUP) %s", A_STARTUP, text);
540     }
541     if (pcmk_is_set(action, A_STARTED)) {
542         crm_trace("Action %.16llx (A_STARTED) %s", A_STARTED, text);
543     }
544     if (pcmk_is_set(action, A_HA_CONNECT)) {
545         crm_trace("Action %.16llx (A_CONNECT) %s", A_HA_CONNECT, text);
546     }
547     if (pcmk_is_set(action, A_HA_DISCONNECT)) {
548         crm_trace("Action %.16llx (A_DISCONNECT) %s", A_HA_DISCONNECT, text);
549     }
550     if (pcmk_is_set(action, A_LRM_CONNECT)) {
551         crm_trace("Action %.16llx (A_LRM_CONNECT) %s", A_LRM_CONNECT, text);
552     }
553     if (pcmk_is_set(action, A_LRM_EVENT)) {
554         crm_trace("Action %.16llx (A_LRM_EVENT) %s", A_LRM_EVENT, text);
555     }
556     if (pcmk_is_set(action, A_LRM_INVOKE)) {
557         crm_trace("Action %.16llx (A_LRM_INVOKE) %s", A_LRM_INVOKE, text);
558     }
559     if (pcmk_is_set(action, A_LRM_DISCONNECT)) {
560         crm_trace("Action %.16llx (A_LRM_DISCONNECT) %s", A_LRM_DISCONNECT, text);
561     }
562     if (pcmk_is_set(action, A_DC_TIMER_STOP)) {
563         crm_trace("Action %.16llx (A_DC_TIMER_STOP) %s", A_DC_TIMER_STOP, text);
564     }
565     if (pcmk_is_set(action, A_DC_TIMER_START)) {
566         crm_trace("Action %.16llx (A_DC_TIMER_START) %s", A_DC_TIMER_START, text);
567     }
568     if (pcmk_is_set(action, A_INTEGRATE_TIMER_START)) {
569         crm_trace("Action %.16llx (A_INTEGRATE_TIMER_START) %s", A_INTEGRATE_TIMER_START, text);
570     }
571     if (pcmk_is_set(action, A_INTEGRATE_TIMER_STOP)) {
572         crm_trace("Action %.16llx (A_INTEGRATE_TIMER_STOP) %s", A_INTEGRATE_TIMER_STOP, text);
573     }
574     if (pcmk_is_set(action, A_FINALIZE_TIMER_START)) {
575         crm_trace("Action %.16llx (A_FINALIZE_TIMER_START) %s", A_FINALIZE_TIMER_START, text);
576     }
577     if (pcmk_is_set(action, A_FINALIZE_TIMER_STOP)) {
578         crm_trace("Action %.16llx (A_FINALIZE_TIMER_STOP) %s", A_FINALIZE_TIMER_STOP, text);
579     }
580     if (pcmk_is_set(action, A_ELECTION_COUNT)) {
581         crm_trace("Action %.16llx (A_ELECTION_COUNT) %s", A_ELECTION_COUNT, text);
582     }
583     if (pcmk_is_set(action, A_ELECTION_VOTE)) {
584         crm_trace("Action %.16llx (A_ELECTION_VOTE) %s", A_ELECTION_VOTE, text);
585     }
586     if (pcmk_is_set(action, A_ELECTION_CHECK)) {
587         crm_trace("Action %.16llx (A_ELECTION_CHECK) %s", A_ELECTION_CHECK, text);
588     }
589     if (pcmk_is_set(action, A_CL_JOIN_ANNOUNCE)) {
590         crm_trace("Action %.16llx (A_CL_JOIN_ANNOUNCE) %s", A_CL_JOIN_ANNOUNCE, text);
591     }
592     if (pcmk_is_set(action, A_CL_JOIN_REQUEST)) {
593         crm_trace("Action %.16llx (A_CL_JOIN_REQUEST) %s", A_CL_JOIN_REQUEST, text);
594     }
595     if (pcmk_is_set(action, A_CL_JOIN_RESULT)) {
596         crm_trace("Action %.16llx (A_CL_JOIN_RESULT) %s", A_CL_JOIN_RESULT, text);
597     }
598     if (pcmk_is_set(action, A_DC_JOIN_OFFER_ALL)) {
599         crm_trace("Action %.16llx (A_DC_JOIN_OFFER_ALL) %s", A_DC_JOIN_OFFER_ALL, text);
600     }
601     if (pcmk_is_set(action, A_DC_JOIN_OFFER_ONE)) {
602         crm_trace("Action %.16llx (A_DC_JOIN_OFFER_ONE) %s", A_DC_JOIN_OFFER_ONE, text);
603     }
604     if (pcmk_is_set(action, A_DC_JOIN_PROCESS_REQ)) {
605         crm_trace("Action %.16llx (A_DC_JOIN_PROCESS_REQ) %s", A_DC_JOIN_PROCESS_REQ, text);
606     }
607     if (pcmk_is_set(action, A_DC_JOIN_PROCESS_ACK)) {
608         crm_trace("Action %.16llx (A_DC_JOIN_PROCESS_ACK) %s", A_DC_JOIN_PROCESS_ACK, text);
609     }
610     if (pcmk_is_set(action, A_DC_JOIN_FINALIZE)) {
611         crm_trace("Action %.16llx (A_DC_JOIN_FINALIZE) %s", A_DC_JOIN_FINALIZE, text);
612     }
613     if (pcmk_is_set(action, A_MSG_PROCESS)) {
614         crm_trace("Action %.16llx (A_MSG_PROCESS) %s", A_MSG_PROCESS, text);
615     }
616     if (pcmk_is_set(action, A_MSG_ROUTE)) {
617         crm_trace("Action %.16llx (A_MSG_ROUTE) %s", A_MSG_ROUTE, text);
618     }
619     if (pcmk_is_set(action, A_RECOVER)) {
620         crm_trace("Action %.16llx (A_RECOVER) %s", A_RECOVER, text);
621     }
622     if (pcmk_is_set(action, A_DC_RELEASE)) {
623         crm_trace("Action %.16llx (A_DC_RELEASE) %s", A_DC_RELEASE, text);
624     }
625     if (pcmk_is_set(action, A_DC_RELEASED)) {
626         crm_trace("Action %.16llx (A_DC_RELEASED) %s", A_DC_RELEASED, text);
627     }
628     if (pcmk_is_set(action, A_DC_TAKEOVER)) {
629         crm_trace("Action %.16llx (A_DC_TAKEOVER) %s", A_DC_TAKEOVER, text);
630     }
631     if (pcmk_is_set(action, A_SHUTDOWN)) {
632         crm_trace("Action %.16llx (A_SHUTDOWN) %s", A_SHUTDOWN, text);
633     }
634     if (pcmk_is_set(action, A_SHUTDOWN_REQ)) {
635         crm_trace("Action %.16llx (A_SHUTDOWN_REQ) %s", A_SHUTDOWN_REQ, text);
636     }
637     if (pcmk_is_set(action, A_STOP)) {
638         crm_trace("Action %.16llx (A_STOP  ) %s", A_STOP, text);
639     }
640     if (pcmk_is_set(action, A_EXIT_0)) {
641         crm_trace("Action %.16llx (A_EXIT_0) %s", A_EXIT_0, text);
642     }
643     if (pcmk_is_set(action, A_EXIT_1)) {
644         crm_trace("Action %.16llx (A_EXIT_1) %s", A_EXIT_1, text);
645     }
646     if (pcmk_is_set(action, A_CIB_START)) {
647         crm_trace("Action %.16llx (A_CIB_START) %s", A_CIB_START, text);
648     }
649     if (pcmk_is_set(action, A_CIB_STOP)) {
650         crm_trace("Action %.16llx (A_CIB_STOP) %s", A_CIB_STOP, text);
651     }
652     if (pcmk_is_set(action, A_TE_INVOKE)) {
653         crm_trace("Action %.16llx (A_TE_INVOKE) %s", A_TE_INVOKE, text);
654     }
655     if (pcmk_is_set(action, A_TE_START)) {
656         crm_trace("Action %.16llx (A_TE_START) %s", A_TE_START, text);
657     }
658     if (pcmk_is_set(action, A_TE_STOP)) {
659         crm_trace("Action %.16llx (A_TE_STOP) %s", A_TE_STOP, text);
660     }
661     if (pcmk_is_set(action, A_TE_CANCEL)) {
662         crm_trace("Action %.16llx (A_TE_CANCEL) %s", A_TE_CANCEL, text);
663     }
664     if (pcmk_is_set(action, A_PE_INVOKE)) {
665         crm_trace("Action %.16llx (A_PE_INVOKE) %s", A_PE_INVOKE, text);
666     }
667     if (pcmk_is_set(action, A_PE_START)) {
668         crm_trace("Action %.16llx (A_PE_START) %s", A_PE_START, text);
669     }
670     if (pcmk_is_set(action, A_PE_STOP)) {
671         crm_trace("Action %.16llx (A_PE_STOP) %s", A_PE_STOP, text);
672     }
673     if (pcmk_is_set(action, A_NODE_BLOCK)) {
674         crm_trace("Action %.16llx (A_NODE_BLOCK) %s", A_NODE_BLOCK, text);
675     }
676     if (pcmk_is_set(action, A_UPDATE_NODESTATUS)) {
677         crm_trace("Action %.16llx (A_UPDATE_NODESTATUS) %s", A_UPDATE_NODESTATUS, text);
678     }
679     if (pcmk_is_set(action, A_LOG)) {
680         crm_trace("Action %.16llx (A_LOG   ) %s", A_LOG, text);
681     }
682     if (pcmk_is_set(action, A_ERROR)) {
683         crm_trace("Action %.16llx (A_ERROR ) %s", A_ERROR, text);
684     }
685     if (pcmk_is_set(action, A_WARN)) {
686         crm_trace("Action %.16llx (A_WARN  ) %s", A_WARN, text);
687     }
688 }
689 
690 gboolean
update_dc(xmlNode * msg)691 update_dc(xmlNode * msg)
692 {
693     char *last_dc = fsa_our_dc;
694     const char *dc_version = NULL;
695     const char *welcome_from = NULL;
696 
697     if (msg != NULL) {
698         gboolean invalid = FALSE;
699 
700         dc_version = crm_element_value(msg, F_CRM_VERSION);
701         welcome_from = crm_element_value(msg, F_CRM_HOST_FROM);
702 
703         CRM_CHECK(dc_version != NULL, return FALSE);
704         CRM_CHECK(welcome_from != NULL, return FALSE);
705 
706         if (AM_I_DC && !pcmk__str_eq(welcome_from, fsa_our_uname, pcmk__str_casei)) {
707             invalid = TRUE;
708 
709         } else if (fsa_our_dc && !pcmk__str_eq(welcome_from, fsa_our_dc, pcmk__str_casei)) {
710             invalid = TRUE;
711         }
712 
713         if (invalid) {
714             CRM_CHECK(fsa_our_dc != NULL, crm_err("We have no DC"));
715             if (AM_I_DC) {
716                 crm_err("Not updating DC to %s (%s): we are also a DC", welcome_from, dc_version);
717             } else {
718                 crm_warn("New DC %s is not %s", welcome_from, fsa_our_dc);
719             }
720 
721             controld_set_fsa_action_flags(A_CL_JOIN_QUERY | A_DC_TIMER_START);
722             trigger_fsa();
723             return FALSE;
724         }
725     }
726 
727     free(fsa_our_dc_version);
728     fsa_our_dc_version = NULL;
729 
730     fsa_our_dc = NULL;          /* Free'd as last_dc */
731 
732     if (welcome_from != NULL) {
733         fsa_our_dc = strdup(welcome_from);
734     }
735     if (dc_version != NULL) {
736         fsa_our_dc_version = strdup(dc_version);
737     }
738 
739     if (pcmk__str_eq(fsa_our_dc, last_dc, pcmk__str_casei)) {
740         /* do nothing */
741 
742     } else if (fsa_our_dc != NULL) {
743         crm_node_t *dc_node = crm_get_peer(0, fsa_our_dc);
744 
745         crm_info("Set DC to %s (%s)", crm_str(fsa_our_dc), crm_str(fsa_our_dc_version));
746         pcmk__update_peer_expected(__func__, dc_node, CRMD_JOINSTATE_MEMBER);
747 
748     } else if (last_dc != NULL) {
749         crm_info("Unset DC. Was %s", crm_str(last_dc));
750     }
751 
752     free(last_dc);
753     return TRUE;
754 }
755 
crmd_peer_down(crm_node_t * peer,bool full)756 void crmd_peer_down(crm_node_t *peer, bool full)
757 {
758     if(full && peer->state == NULL) {
759         pcmk__update_peer_state(__func__, peer, CRM_NODE_LOST, 0);
760         crm_update_peer_proc(__func__, peer, crm_proc_none, NULL);
761     }
762     crm_update_peer_join(__func__, peer, crm_join_none);
763     pcmk__update_peer_expected(__func__, peer, CRMD_JOINSTATE_DOWN);
764 }
765 
766 #define MIN_CIB_OP_TIMEOUT (30)
767 
768 unsigned int
cib_op_timeout()769 cib_op_timeout()
770 {
771     static int env_timeout = -1;
772     unsigned int calculated_timeout = 0;
773 
774     if (env_timeout == -1) {
775         const char *env = getenv("PCMK_cib_timeout");
776 
777         pcmk__scan_min_int(env, &env_timeout, MIN_CIB_OP_TIMEOUT);
778         crm_trace("Minimum CIB op timeout: %ds (environment: %s)",
779                   env_timeout, (env? env : "none"));
780     }
781 
782     calculated_timeout = 1 + crm_active_peers();
783     if (crm_remote_peer_cache) {
784         calculated_timeout += g_hash_table_size(crm_remote_peer_cache);
785     }
786     calculated_timeout *= 10;
787 
788     calculated_timeout = QB_MAX(calculated_timeout, env_timeout);
789     crm_trace("Calculated timeout: %us", calculated_timeout);
790 
791     if (fsa_cib_conn) {
792         fsa_cib_conn->call_timeout = calculated_timeout;
793     }
794     return calculated_timeout;
795 }
796 
797 /*!
798  * \internal
799  * \brief Check feature set compatibility of DC and joining node
800  *
801  * Return true if a joining node's CRM feature set is compatible with the
802  * current DC's. The feature sets are compatible if they have the same major
803  * version number, and the DC's minor version number is the same or older than
804  * the joining node's. The minor-minor version is intended solely to allow
805  * resource agents to detect feature support, and so is ignored.
806  *
807  * \param[in] dc_version    DC's feature set
808  * \param[in] join_version  Joining node's version
809  */
810 bool
feature_set_compatible(const char * dc_version,const char * join_version)811 feature_set_compatible(const char *dc_version, const char *join_version)
812 {
813     char *dc_minor = NULL;
814     char *join_minor = NULL;
815     long dc_v = 0;
816     long join_v = 0;
817 
818     // Get DC's major version
819     errno = 0;
820     dc_v = strtol(dc_version, &dc_minor, 10);
821     if (errno) {
822         return FALSE;
823     }
824 
825     // Get joining node's major version
826     errno = 0;
827     join_v = strtol(join_version, &join_minor, 10);
828     if (errno) {
829         return FALSE;
830     }
831 
832     // Major version component must be identical
833     if (dc_v != join_v) {
834         return FALSE;
835     }
836 
837     // Get DC's minor version
838     if (*dc_minor == '.') {
839         ++dc_minor;
840     }
841     errno = 0;
842     dc_v = strtol(dc_minor, NULL, 10);
843     if (errno) {
844         return FALSE;
845     }
846 
847     // Get joining node's minor version
848     if (*join_minor == '.') {
849         ++join_minor;
850     }
851     errno = 0;
852     join_v = strtol(join_minor, NULL, 10);
853     if (errno) {
854         return FALSE;
855     }
856 
857     // DC's minor version must be the same or older
858     return dc_v <= join_v;
859 }
860 
861 const char *
get_node_id(xmlNode * lrm_rsc_op)862 get_node_id(xmlNode *lrm_rsc_op)
863 {
864     xmlNode *node = lrm_rsc_op;
865 
866     while (node != NULL && !pcmk__str_eq(XML_CIB_TAG_STATE, TYPE(node), pcmk__str_casei)) {
867         node = node->parent;
868     }
869 
870     CRM_CHECK(node != NULL, return NULL);
871     return ID(node);
872 }
873