This source file includes following definitions.
- register_fsa_error_adv
- register_fsa_input_adv
- fsa_dump_queue
- copy_ha_msg_input
- delete_fsa_input
- get_message
- fsa_typed_data_adv
- do_msg_route
- route_message
- relay_message
- authorize_version
- controld_authorize_ipc_message
- handle_message
- handle_failcount_op
- handle_lrm_delete
- handle_remote_state
- handle_ping
- handle_node_list
- handle_node_info_request
- verify_feature_set
- handle_shutdown_self_ack
- handle_shutdown_ack
- handle_request
- handle_response
- handle_shutdown_request
- send_msg_via_ipc
- delete_ha_msg_input
- broadcast_remote_state_message
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <sys/param.h>
13 #include <string.h>
14 #include <time.h>
15
16 #include <crm/crm.h>
17 #include <crm/msg_xml.h>
18 #include <crm/common/xml.h>
19 #include <crm/cluster/internal.h>
20 #include <crm/cib.h>
21 #include <crm/common/ipc_internal.h>
22
23 #include <pacemaker-controld.h>
24
25 extern void crm_shutdown(int nsig);
26
27 static enum crmd_fsa_input handle_message(xmlNode *msg,
28 enum crmd_fsa_cause cause);
29 static void handle_response(xmlNode *stored_msg);
30 static enum crmd_fsa_input handle_request(xmlNode *stored_msg,
31 enum crmd_fsa_cause cause);
32 static enum crmd_fsa_input handle_shutdown_request(xmlNode *stored_msg);
33 static void send_msg_via_ipc(xmlNode * msg, const char *sys);
34
35
36 static int last_data_id = 0;
37
38 void
39 register_fsa_error_adv(enum crmd_fsa_cause cause, enum crmd_fsa_input input,
40 fsa_data_t * cur_data, void *new_data, const char *raised_from)
41 {
42
43 if (controld_globals.fsa_actions != A_NOTHING) {
44 register_fsa_input_adv(cur_data ? cur_data->fsa_cause : C_FSA_INTERNAL,
45 I_NULL, cur_data ? cur_data->data : NULL,
46 controld_globals.fsa_actions, TRUE, __func__);
47 }
48
49
50 crm_info("Resetting the current action list");
51 fsa_dump_actions(controld_globals.fsa_actions, "Drop");
52 controld_globals.fsa_actions = A_NOTHING;
53
54
55 register_fsa_input_adv(cause, input, new_data, A_NOTHING, TRUE, raised_from);
56 }
57
58 void
59 register_fsa_input_adv(enum crmd_fsa_cause cause, enum crmd_fsa_input input,
60 void *data, uint64_t with_actions,
61 gboolean prepend, const char *raised_from)
62 {
63 unsigned old_len = g_list_length(controld_globals.fsa_message_queue);
64 fsa_data_t *fsa_data = NULL;
65
66 if (raised_from == NULL) {
67 raised_from = "<unknown>";
68 }
69
70 if (input == I_NULL && with_actions == A_NOTHING ) {
71
72 crm_err("Cannot add entry to queue: no input and no action");
73 return;
74 }
75
76 if (input == I_WAIT_FOR_EVENT) {
77 controld_set_global_flags(controld_fsa_is_stalled);
78 crm_debug("Stalling the FSA pending further input: source=%s cause=%s data=%p queue=%d",
79 raised_from, fsa_cause2string(cause), data, old_len);
80
81 if (old_len > 0) {
82 fsa_dump_queue(LOG_TRACE);
83 prepend = FALSE;
84 }
85
86 if (data == NULL) {
87 controld_set_fsa_action_flags(with_actions);
88 fsa_dump_actions(with_actions, "Restored");
89 return;
90 }
91
92
93
94
95 with_actions |= controld_globals.fsa_actions;
96 controld_globals.fsa_actions = A_NOTHING;
97 }
98
99 last_data_id++;
100 crm_trace("%s %s FSA input %d (%s) due to %s, %s data",
101 raised_from, (prepend? "prepended" : "appended"), last_data_id,
102 fsa_input2string(input), fsa_cause2string(cause),
103 (data? "with" : "without"));
104
105 fsa_data = calloc(1, sizeof(fsa_data_t));
106 fsa_data->id = last_data_id;
107 fsa_data->fsa_input = input;
108 fsa_data->fsa_cause = cause;
109 fsa_data->origin = raised_from;
110 fsa_data->data = NULL;
111 fsa_data->data_type = fsa_dt_none;
112 fsa_data->actions = with_actions;
113
114 if (with_actions != A_NOTHING) {
115 crm_trace("Adding actions %.16llx to input",
116 (unsigned long long) with_actions);
117 }
118
119 if (data != NULL) {
120 switch (cause) {
121 case C_FSA_INTERNAL:
122 case C_CRMD_STATUS_CALLBACK:
123 case C_IPC_MESSAGE:
124 case C_HA_MESSAGE:
125 CRM_CHECK(((ha_msg_input_t *) data)->msg != NULL,
126 crm_err("Bogus data from %s", raised_from));
127 crm_trace("Copying %s data from %s as cluster message data",
128 fsa_cause2string(cause), raised_from);
129 fsa_data->data = copy_ha_msg_input(data);
130 fsa_data->data_type = fsa_dt_ha_msg;
131 break;
132
133 case C_LRM_OP_CALLBACK:
134 crm_trace("Copying %s data from %s as lrmd_event_data_t",
135 fsa_cause2string(cause), raised_from);
136 fsa_data->data = lrmd_copy_event((lrmd_event_data_t *) data);
137 fsa_data->data_type = fsa_dt_lrm;
138 break;
139
140 case C_TIMER_POPPED:
141 case C_SHUTDOWN:
142 case C_UNKNOWN:
143 case C_STARTUP:
144 crm_crit("Copying %s data (from %s) is not yet implemented",
145 fsa_cause2string(cause), raised_from);
146 crmd_exit(CRM_EX_SOFTWARE);
147 break;
148 }
149 }
150
151
152 if (prepend) {
153 controld_globals.fsa_message_queue
154 = g_list_prepend(controld_globals.fsa_message_queue, fsa_data);
155 } else {
156 controld_globals.fsa_message_queue
157 = g_list_append(controld_globals.fsa_message_queue, fsa_data);
158 }
159
160 crm_trace("FSA message queue length is %d",
161 g_list_length(controld_globals.fsa_message_queue));
162
163
164
165 if (old_len == g_list_length(controld_globals.fsa_message_queue)) {
166 crm_err("Couldn't add message to the queue");
167 }
168
169 if (input != I_WAIT_FOR_EVENT) {
170 controld_trigger_fsa();
171 }
172 }
173
174 void
175 fsa_dump_queue(int log_level)
176 {
177 int offset = 0;
178
179 for (GList *iter = controld_globals.fsa_message_queue; iter != NULL;
180 iter = iter->next) {
181 fsa_data_t *data = (fsa_data_t *) iter->data;
182
183 do_crm_log_unlikely(log_level,
184 "queue[%d.%d]: input %s raised by %s(%p.%d)\t(cause=%s)",
185 offset++, data->id, fsa_input2string(data->fsa_input),
186 data->origin, data->data, data->data_type,
187 fsa_cause2string(data->fsa_cause));
188 }
189 }
190
191 ha_msg_input_t *
192 copy_ha_msg_input(ha_msg_input_t * orig)
193 {
194 ha_msg_input_t *copy = calloc(1, sizeof(ha_msg_input_t));
195
196 CRM_ASSERT(copy != NULL);
197 copy->msg = (orig && orig->msg)? copy_xml(orig->msg) : NULL;
198 copy->xml = get_message_xml(copy->msg, F_CRM_DATA);
199 return copy;
200 }
201
202 void
203 delete_fsa_input(fsa_data_t * fsa_data)
204 {
205 lrmd_event_data_t *op = NULL;
206 xmlNode *foo = NULL;
207
208 if (fsa_data == NULL) {
209 return;
210 }
211 crm_trace("About to free %s data", fsa_cause2string(fsa_data->fsa_cause));
212
213 if (fsa_data->data != NULL) {
214 switch (fsa_data->data_type) {
215 case fsa_dt_ha_msg:
216 delete_ha_msg_input(fsa_data->data);
217 break;
218
219 case fsa_dt_xml:
220 foo = fsa_data->data;
221 free_xml(foo);
222 break;
223
224 case fsa_dt_lrm:
225 op = (lrmd_event_data_t *) fsa_data->data;
226 lrmd_free_event(op);
227 break;
228
229 case fsa_dt_none:
230 if (fsa_data->data != NULL) {
231 crm_err("Don't know how to free %s data from %s",
232 fsa_cause2string(fsa_data->fsa_cause), fsa_data->origin);
233 crmd_exit(CRM_EX_SOFTWARE);
234 }
235 break;
236 }
237 crm_trace("%s data freed", fsa_cause2string(fsa_data->fsa_cause));
238 }
239
240 free(fsa_data);
241 }
242
243
244 fsa_data_t *
245 get_message(void)
246 {
247 fsa_data_t *message
248 = (fsa_data_t *) controld_globals.fsa_message_queue->data;
249
250 controld_globals.fsa_message_queue
251 = g_list_remove(controld_globals.fsa_message_queue, message);
252 crm_trace("Processing input %d", message->id);
253 return message;
254 }
255
256 void *
257 fsa_typed_data_adv(fsa_data_t * fsa_data, enum fsa_data_type a_type, const char *caller)
258 {
259 void *ret_val = NULL;
260
261 if (fsa_data == NULL) {
262 crm_err("%s: No FSA data available", caller);
263
264 } else if (fsa_data->data == NULL) {
265 crm_err("%s: No message data available. Origin: %s", caller, fsa_data->origin);
266
267 } else if (fsa_data->data_type != a_type) {
268 crm_crit("%s: Message data was the wrong type! %d vs. requested=%d. Origin: %s",
269 caller, fsa_data->data_type, a_type, fsa_data->origin);
270 CRM_ASSERT(fsa_data->data_type == a_type);
271 } else {
272 ret_val = fsa_data->data;
273 }
274
275 return ret_val;
276 }
277
278
279 void
280 do_msg_route(long long action,
281 enum crmd_fsa_cause cause,
282 enum crmd_fsa_state cur_state,
283 enum crmd_fsa_input current_input, fsa_data_t * msg_data)
284 {
285 ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg);
286
287 route_message(msg_data->fsa_cause, input->msg);
288 }
289
290 void
291 route_message(enum crmd_fsa_cause cause, xmlNode * input)
292 {
293 ha_msg_input_t fsa_input;
294 enum crmd_fsa_input result = I_NULL;
295
296 fsa_input.msg = input;
297 CRM_CHECK(cause == C_IPC_MESSAGE || cause == C_HA_MESSAGE, return);
298
299
300 if (relay_message(input, cause == C_IPC_MESSAGE)) {
301 return;
302 }
303
304
305 result = handle_message(input, cause);
306
307
308 switch (result) {
309 case I_NULL:
310 case I_CIB_OP:
311 case I_ROUTER:
312 case I_NODE_JOIN:
313 case I_JOIN_REQUEST:
314 case I_JOIN_RESULT:
315 break;
316 default:
317
318 register_fsa_input_later(cause, result, &fsa_input);
319 return;
320 }
321
322 if (result != I_NULL) {
323
324 register_fsa_input(cause, result, &fsa_input);
325 }
326 }
327
328 gboolean
329 relay_message(xmlNode * msg, gboolean originated_locally)
330 {
331 int dest = 1;
332 bool is_for_dc = false;
333 bool is_for_dcib = false;
334 bool is_for_te = false;
335 bool is_for_crm = false;
336 bool is_for_cib = false;
337 bool is_local = false;
338 const char *host_to = crm_element_value(msg, F_CRM_HOST_TO);
339 const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO);
340 const char *sys_from = crm_element_value(msg, F_CRM_SYS_FROM);
341 const char *type = crm_element_value(msg, F_TYPE);
342 const char *task = crm_element_value(msg, F_CRM_TASK);
343 const char *ref = crm_element_value(msg, XML_ATTR_REFERENCE);
344
345 if (ref == NULL) {
346 ref = "without reference ID";
347 }
348
349 if (msg == NULL) {
350 crm_warn("Cannot route empty message");
351 return TRUE;
352
353 } else if (pcmk__str_eq(task, CRM_OP_HELLO, pcmk__str_casei)) {
354 crm_trace("No routing needed for hello message %s", ref);
355 return TRUE;
356
357 } else if (!pcmk__str_eq(type, T_CRM, pcmk__str_casei)) {
358 crm_warn("Received invalid message %s: type '%s' not '" T_CRM "'",
359 ref, pcmk__s(type, ""));
360 crm_log_xml_warn(msg, "[bad message type]");
361 return TRUE;
362
363 } else if (sys_to == NULL) {
364 crm_warn("Received invalid message %s: no subsystem", ref);
365 crm_log_xml_warn(msg, "[no subsystem]");
366 return TRUE;
367 }
368
369 is_for_dc = (strcasecmp(CRM_SYSTEM_DC, sys_to) == 0);
370 is_for_dcib = (strcasecmp(CRM_SYSTEM_DCIB, sys_to) == 0);
371 is_for_te = (strcasecmp(CRM_SYSTEM_TENGINE, sys_to) == 0);
372 is_for_cib = (strcasecmp(CRM_SYSTEM_CIB, sys_to) == 0);
373 is_for_crm = (strcasecmp(CRM_SYSTEM_CRMD, sys_to) == 0);
374
375 is_local = false;
376 if (pcmk__str_empty(host_to)) {
377 if (is_for_dc || is_for_te) {
378 is_local = false;
379
380 } else if (is_for_crm) {
381 if (pcmk__strcase_any_of(task, CRM_OP_NODE_INFO,
382 PCMK__CONTROLD_CMD_NODES, NULL)) {
383
384
385
386
387
388 is_local = true;
389 } else {
390 is_local = !originated_locally;
391 }
392
393 } else {
394 is_local = true;
395 }
396
397 } else if (pcmk__str_eq(controld_globals.our_nodename, host_to,
398 pcmk__str_casei)) {
399 is_local = true;
400 } else if (is_for_crm && pcmk__str_eq(task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
401 xmlNode *msg_data = get_message_xml(msg, F_CRM_DATA);
402 const char *mode = crm_element_value(msg_data, PCMK__XA_MODE);
403
404 if (pcmk__str_eq(mode, XML_TAG_CIB, pcmk__str_casei)) {
405
406 is_local = true;
407 }
408 }
409
410 if (is_for_dc || is_for_dcib || is_for_te) {
411 if (AM_I_DC && is_for_te) {
412 crm_trace("Route message %s locally as transition request", ref);
413 send_msg_via_ipc(msg, sys_to);
414
415 } else if (AM_I_DC) {
416 crm_trace("Route message %s locally as DC request", ref);
417 return FALSE;
418
419 } else if (originated_locally && !pcmk__strcase_any_of(sys_from, CRM_SYSTEM_PENGINE,
420 CRM_SYSTEM_TENGINE, NULL)) {
421
422 if (is_corosync_cluster()) {
423 dest = text2msg_type(sys_to);
424 }
425 crm_trace("Relay message %s to DC", ref);
426 send_cluster_message(host_to ? crm_get_peer(0, host_to) : NULL, dest, msg, TRUE);
427
428 } else {
429
430
431
432
433 crm_trace("Discard message %s because we are not DC", ref);
434 }
435
436 } else if (is_local && (is_for_crm || is_for_cib)) {
437 crm_trace("Route message %s locally as controller request", ref);
438 return FALSE;
439
440 } else if (is_local) {
441 crm_trace("Relay message %s locally to %s",
442 ref, (sys_to? sys_to : "unknown client"));
443 crm_log_xml_trace(msg, "[IPC relay]");
444 send_msg_via_ipc(msg, sys_to);
445
446 } else {
447 crm_node_t *node_to = NULL;
448
449 if (is_corosync_cluster()) {
450 dest = text2msg_type(sys_to);
451
452 if (dest == crm_msg_none || dest > crm_msg_stonith_ng) {
453 dest = crm_msg_crmd;
454 }
455 }
456
457 if (host_to) {
458 node_to = pcmk__search_cluster_node_cache(0, host_to);
459 if (node_to == NULL) {
460 crm_warn("Cannot route message %s: Unknown node %s",
461 ref, host_to);
462 return TRUE;
463 }
464 crm_trace("Relay message %s to %s",
465 ref, (node_to->uname? node_to->uname : "peer"));
466 } else {
467 crm_trace("Broadcast message %s to all peers", ref);
468 }
469 send_cluster_message(host_to ? node_to : NULL, dest, msg, TRUE);
470 }
471
472 return TRUE;
473 }
474
475
476 static bool
477 authorize_version(xmlNode *message_data, const char *field,
478 const char *client_name, const char *ref, const char *uuid)
479 {
480 const char *version = crm_element_value(message_data, field);
481 long long version_num;
482
483 if ((pcmk__scan_ll(version, &version_num, -1LL) != pcmk_rc_ok)
484 || (version_num < 0LL)) {
485
486 crm_warn("Rejected IPC hello from %s: '%s' is not a valid protocol %s "
487 CRM_XS " ref=%s uuid=%s",
488 client_name, ((version == NULL)? "" : version),
489 field, (ref? ref : "none"), uuid);
490 return false;
491 }
492 return true;
493 }
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510 bool
511 controld_authorize_ipc_message(const xmlNode *client_msg, pcmk__client_t *curr_client,
512 const char *proxy_session)
513 {
514 xmlNode *message_data = NULL;
515 const char *client_name = NULL;
516 const char *op = crm_element_value(client_msg, F_CRM_TASK);
517 const char *ref = crm_element_value(client_msg, XML_ATTR_REFERENCE);
518 const char *uuid = (curr_client? curr_client->id : proxy_session);
519
520 if (uuid == NULL) {
521 crm_warn("IPC message from client rejected: No client identifier "
522 CRM_XS " ref=%s", (ref? ref : "none"));
523 goto rejected;
524 }
525
526 if (!pcmk__str_eq(CRM_OP_HELLO, op, pcmk__str_casei)) {
527
528 return true;
529 }
530
531 message_data = get_message_xml(client_msg, F_CRM_DATA);
532
533 client_name = crm_element_value(message_data, "client_name");
534 if (pcmk__str_empty(client_name)) {
535 crm_warn("IPC hello from client rejected: No client name",
536 CRM_XS " ref=%s uuid=%s", (ref? ref : "none"), uuid);
537 goto rejected;
538 }
539 if (!authorize_version(message_data, "major_version", client_name, ref,
540 uuid)) {
541 goto rejected;
542 }
543 if (!authorize_version(message_data, "minor_version", client_name, ref,
544 uuid)) {
545 goto rejected;
546 }
547
548 crm_trace("Validated IPC hello from client %s", client_name);
549 if (curr_client) {
550 curr_client->userdata = strdup(client_name);
551 }
552 controld_trigger_fsa();
553 return false;
554
555 rejected:
556 if (curr_client) {
557 qb_ipcs_disconnect(curr_client->ipcs);
558 }
559 return false;
560 }
561
562 static enum crmd_fsa_input
563 handle_message(xmlNode *msg, enum crmd_fsa_cause cause)
564 {
565 const char *type = NULL;
566
567 CRM_CHECK(msg != NULL, return I_NULL);
568
569 type = crm_element_value(msg, F_CRM_MSG_TYPE);
570 if (pcmk__str_eq(type, XML_ATTR_REQUEST, pcmk__str_none)) {
571 return handle_request(msg, cause);
572
573 } else if (pcmk__str_eq(type, XML_ATTR_RESPONSE, pcmk__str_none)) {
574 handle_response(msg);
575 return I_NULL;
576 }
577
578 crm_err("Unknown message type: %s", type);
579 return I_NULL;
580 }
581
582 static enum crmd_fsa_input
583 handle_failcount_op(xmlNode * stored_msg)
584 {
585 const char *rsc = NULL;
586 const char *uname = NULL;
587 const char *op = NULL;
588 char *interval_spec = NULL;
589 guint interval_ms = 0;
590 gboolean is_remote_node = FALSE;
591 xmlNode *xml_op = get_message_xml(stored_msg, F_CRM_DATA);
592
593 if (xml_op) {
594 xmlNode *xml_rsc = first_named_child(xml_op, XML_CIB_TAG_RESOURCE);
595 xmlNode *xml_attrs = first_named_child(xml_op, XML_TAG_ATTRS);
596
597 if (xml_rsc) {
598 rsc = ID(xml_rsc);
599 }
600 if (xml_attrs) {
601 op = crm_element_value(xml_attrs,
602 CRM_META "_" XML_RSC_ATTR_CLEAR_OP);
603 crm_element_value_ms(xml_attrs,
604 CRM_META "_" XML_RSC_ATTR_CLEAR_INTERVAL,
605 &interval_ms);
606 }
607 }
608 uname = crm_element_value(xml_op, XML_LRM_ATTR_TARGET);
609
610 if ((rsc == NULL) || (uname == NULL)) {
611 crm_log_xml_warn(stored_msg, "invalid failcount op");
612 return I_NULL;
613 }
614
615 if (crm_element_value(xml_op, XML_LRM_ATTR_ROUTER_NODE)) {
616 is_remote_node = TRUE;
617 }
618
619 crm_debug("Clearing failures for %s-interval %s on %s "
620 "from attribute manager, CIB, and executor state",
621 pcmk__readable_interval(interval_ms), rsc, uname);
622
623 if (interval_ms) {
624 interval_spec = crm_strdup_printf("%ums", interval_ms);
625 }
626 update_attrd_clear_failures(uname, rsc, op, interval_spec, is_remote_node);
627 free(interval_spec);
628
629 controld_cib_delete_last_failure(rsc, uname, op, interval_ms);
630
631 lrm_clear_last_failure(rsc, uname, op, interval_ms);
632
633 return I_NULL;
634 }
635
636 static enum crmd_fsa_input
637 handle_lrm_delete(xmlNode *stored_msg)
638 {
639 const char *mode = NULL;
640 xmlNode *msg_data = get_message_xml(stored_msg, F_CRM_DATA);
641
642 CRM_CHECK(msg_data != NULL, return I_NULL);
643
644
645
646
647
648
649
650
651
652
653
654 mode = crm_element_value(msg_data, PCMK__XA_MODE);
655 if ((mode == NULL) || strcmp(mode, XML_TAG_CIB)) {
656
657 crm_xml_add(stored_msg, F_CRM_SYS_TO, CRM_SYSTEM_LRMD);
658 return I_ROUTER;
659
660 } else {
661
662 const char *from_sys = NULL;
663 const char *user_name = NULL;
664 const char *rsc_id = NULL;
665 const char *node = NULL;
666 xmlNode *rsc_xml = NULL;
667 int rc = pcmk_rc_ok;
668
669 rsc_xml = first_named_child(msg_data, XML_CIB_TAG_RESOURCE);
670 CRM_CHECK(rsc_xml != NULL, return I_NULL);
671
672 rsc_id = ID(rsc_xml);
673 from_sys = crm_element_value(stored_msg, F_CRM_SYS_FROM);
674 node = crm_element_value(msg_data, XML_LRM_ATTR_TARGET);
675 user_name = pcmk__update_acl_user(stored_msg, F_CRM_USER, NULL);
676 crm_debug("Handling " CRM_OP_LRM_DELETE " for %s on %s locally%s%s "
677 "(clearing CIB resource history only)", rsc_id, node,
678 (user_name? " for user " : ""), (user_name? user_name : ""));
679 rc = controld_delete_resource_history(rsc_id, node, user_name,
680 cib_dryrun|cib_sync_call);
681 if (rc == pcmk_rc_ok) {
682 rc = controld_delete_resource_history(rsc_id, node, user_name,
683 crmd_cib_smart_opt());
684 }
685
686
687 if (from_sys) {
688 lrmd_event_data_t *op = NULL;
689 const char *from_host = crm_element_value(stored_msg,
690 F_CRM_HOST_FROM);
691 const char *transition;
692
693 if (strcmp(from_sys, CRM_SYSTEM_TENGINE)) {
694 transition = crm_element_value(msg_data,
695 XML_ATTR_TRANSITION_KEY);
696 } else {
697 transition = crm_element_value(stored_msg,
698 XML_ATTR_TRANSITION_KEY);
699 }
700
701 crm_info("Notifying %s on %s that %s was%s deleted",
702 from_sys, (from_host? from_host : "local node"), rsc_id,
703 ((rc == pcmk_rc_ok)? "" : " not"));
704 op = lrmd_new_event(rsc_id, CRMD_ACTION_DELETE, 0);
705 op->type = lrmd_event_exec_complete;
706 op->user_data = strdup(transition? transition : FAKE_TE_ID);
707 op->params = pcmk__strkey_table(free, free);
708 g_hash_table_insert(op->params, strdup(XML_ATTR_CRM_VERSION),
709 strdup(CRM_FEATURE_SET));
710 controld_rc2event(op, rc);
711 controld_ack_event_directly(from_host, from_sys, NULL, op, rsc_id);
712 lrmd_free_event(op);
713 controld_trigger_delete_refresh(from_sys, rsc_id);
714 }
715 return I_NULL;
716 }
717 }
718
719
720
721
722
723
724
725
726 static enum crmd_fsa_input
727 handle_remote_state(const xmlNode *msg)
728 {
729 const char *conn_host = NULL;
730 const char *remote_uname = ID(msg);
731 crm_node_t *remote_peer;
732 bool remote_is_up = false;
733 int rc = pcmk_rc_ok;
734
735 rc = pcmk__xe_get_bool_attr(msg, XML_NODE_IN_CLUSTER, &remote_is_up);
736
737 CRM_CHECK(remote_uname && rc == pcmk_rc_ok, return I_NULL);
738
739 remote_peer = crm_remote_peer_get(remote_uname);
740 CRM_CHECK(remote_peer, return I_NULL);
741
742 pcmk__update_peer_state(__func__, remote_peer,
743 remote_is_up ? CRM_NODE_MEMBER : CRM_NODE_LOST,
744 0);
745
746 conn_host = crm_element_value(msg, PCMK__XA_CONN_HOST);
747 if (conn_host) {
748 pcmk__str_update(&remote_peer->conn_host, conn_host);
749 } else if (remote_peer->conn_host) {
750 free(remote_peer->conn_host);
751 remote_peer->conn_host = NULL;
752 }
753
754 return I_NULL;
755 }
756
757
758
759
760
761
762
763
764 static enum crmd_fsa_input
765 handle_ping(const xmlNode *msg)
766 {
767 const char *value = NULL;
768 xmlNode *ping = NULL;
769 xmlNode *reply = NULL;
770
771
772
773 ping = create_xml_node(NULL, XML_CRM_TAG_PING);
774 value = crm_element_value(msg, F_CRM_SYS_TO);
775 crm_xml_add(ping, XML_PING_ATTR_SYSFROM, value);
776
777
778 value = fsa_state2string(controld_globals.fsa_state);
779 crm_xml_add(ping, XML_PING_ATTR_CRMDSTATE, value);
780 crm_notice("Current ping state: %s", value);
781
782
783
784 crm_xml_add(ping, XML_PING_ATTR_STATUS, "ok");
785
786
787 reply = create_reply(msg, ping);
788 free_xml(ping);
789 if (reply != NULL) {
790 (void) relay_message(reply, TRUE);
791 free_xml(reply);
792 }
793
794
795 return I_NULL;
796 }
797
798
799
800
801
802
803
804
805 static enum crmd_fsa_input
806 handle_node_list(const xmlNode *request)
807 {
808 GHashTableIter iter;
809 crm_node_t *node = NULL;
810 xmlNode *reply = NULL;
811 xmlNode *reply_data = NULL;
812
813
814 reply_data = create_xml_node(NULL, XML_CIB_TAG_NODES);
815 g_hash_table_iter_init(&iter, crm_peer_cache);
816 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) {
817 xmlNode *xml = create_xml_node(reply_data, XML_CIB_TAG_NODE);
818
819 crm_xml_add_ll(xml, XML_ATTR_ID, (long long) node->id);
820 crm_xml_add(xml, XML_ATTR_UNAME, node->uname);
821 crm_xml_add(xml, XML_NODE_IN_CLUSTER, node->state);
822 }
823
824
825 reply = create_reply(request, reply_data);
826 free_xml(reply_data);
827 if (reply) {
828 (void) relay_message(reply, TRUE);
829 free_xml(reply);
830 }
831
832
833 return I_NULL;
834 }
835
836
837
838
839
840
841
842
843 static enum crmd_fsa_input
844 handle_node_info_request(const xmlNode *msg)
845 {
846 const char *value = NULL;
847 crm_node_t *node = NULL;
848 int node_id = 0;
849 xmlNode *reply = NULL;
850 xmlNode *reply_data = NULL;
851
852
853
854 reply_data = create_xml_node(NULL, XML_CIB_TAG_NODE);
855 crm_xml_add(reply_data, XML_PING_ATTR_SYSFROM, CRM_SYSTEM_CRMD);
856
857
858 pcmk__xe_set_bool_attr(reply_data, XML_ATTR_HAVE_QUORUM,
859 pcmk_is_set(controld_globals.flags,
860 controld_has_quorum));
861
862
863 crm_element_value_int(msg, XML_ATTR_ID, &node_id);
864 if (node_id < 0) {
865 node_id = 0;
866 }
867 value = crm_element_value(msg, XML_ATTR_UNAME);
868
869
870 if ((node_id == 0) && (value == NULL)) {
871 value = controld_globals.our_nodename;
872 }
873
874 node = pcmk__search_node_caches(node_id, value, CRM_GET_PEER_ANY);
875 if (node) {
876 crm_xml_add(reply_data, XML_ATTR_ID, node->uuid);
877 crm_xml_add(reply_data, XML_ATTR_UNAME, node->uname);
878 crm_xml_add(reply_data, XML_NODE_IS_PEER, node->state);
879 pcmk__xe_set_bool_attr(reply_data, XML_NODE_IS_REMOTE,
880 pcmk_is_set(node->flags, crm_remote_node));
881 }
882
883
884 reply = create_reply(msg, reply_data);
885 free_xml(reply_data);
886 if (reply != NULL) {
887 (void) relay_message(reply, TRUE);
888 free_xml(reply);
889 }
890
891
892 return I_NULL;
893 }
894
895 static void
896 verify_feature_set(xmlNode *msg)
897 {
898 const char *dc_version = crm_element_value(msg, XML_ATTR_CRM_VERSION);
899
900 if (dc_version == NULL) {
901
902
903
904 dc_version = "3.0.14";
905 }
906
907 if (feature_set_compatible(dc_version, CRM_FEATURE_SET)) {
908 crm_trace("Local feature set (%s) is compatible with DC's (%s)",
909 CRM_FEATURE_SET, dc_version);
910 } else {
911 crm_err("Local feature set (%s) is incompatible with DC's (%s)",
912 CRM_FEATURE_SET, dc_version);
913
914
915 controld_set_fsa_input_flags(R_STAYDOWN);
916 crmd_exit(CRM_EX_FATAL);
917 }
918 }
919
920
921 static enum crmd_fsa_input
922 handle_shutdown_self_ack(xmlNode *stored_msg)
923 {
924 const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
925
926 if (pcmk_is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
927
928 crm_info("Shutting down controller");
929 return I_STOP;
930 }
931
932 if (pcmk__str_eq(host_from, controld_globals.dc_name, pcmk__str_casei)) {
933
934 crm_err("Shutting down controller immediately due to "
935 "unexpected shutdown confirmation");
936 return I_TERMINATE;
937 }
938
939 if (controld_globals.fsa_state != S_STOPPING) {
940
941 crm_err("Starting new DC election because %s is "
942 "confirming shutdown we did not request",
943 (host_from? host_from : "another node"));
944 return I_ELECTION;
945 }
946
947
948 crm_debug("Ignoring unexpected shutdown confirmation from %s",
949 (host_from? host_from : "another node"));
950 return I_NULL;
951 }
952
953
954 static enum crmd_fsa_input
955 handle_shutdown_ack(xmlNode *stored_msg)
956 {
957 const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
958
959 if (host_from == NULL) {
960 crm_warn("Ignoring shutdown request without origin specified");
961 return I_NULL;
962 }
963
964 if (pcmk__str_eq(host_from, controld_globals.dc_name,
965 pcmk__str_null_matches|pcmk__str_casei)) {
966
967 if (pcmk_is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
968 crm_info("Shutting down controller after confirmation from %s",
969 host_from);
970 } else {
971 crm_err("Shutting down controller after unexpected "
972 "shutdown request from %s", host_from);
973 controld_set_fsa_input_flags(R_STAYDOWN);
974 }
975 return I_STOP;
976 }
977
978 crm_warn("Ignoring shutdown request from %s because DC is %s",
979 host_from, controld_globals.dc_name);
980 return I_NULL;
981 }
982
983 static enum crmd_fsa_input
984 handle_request(xmlNode *stored_msg, enum crmd_fsa_cause cause)
985 {
986 xmlNode *msg = NULL;
987 const char *op = crm_element_value(stored_msg, F_CRM_TASK);
988
989
990
991 if (op == NULL) {
992 crm_log_xml_warn(stored_msg, "[request without " F_CRM_TASK "]");
993 return I_NULL;
994 }
995
996 if (strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) {
997 const char *from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
998 crm_node_t *node = pcmk__search_cluster_node_cache(0, from);
999
1000 pcmk__update_peer_expected(__func__, node, CRMD_JOINSTATE_DOWN);
1001 if(AM_I_DC == FALSE) {
1002 return I_NULL;
1003 }
1004 }
1005
1006
1007 if (AM_I_DC) {
1008 if (strcmp(op, CRM_OP_JOIN_ANNOUNCE) == 0) {
1009 return I_NODE_JOIN;
1010
1011 } else if (strcmp(op, CRM_OP_JOIN_REQUEST) == 0) {
1012 return I_JOIN_REQUEST;
1013
1014 } else if (strcmp(op, CRM_OP_JOIN_CONFIRM) == 0) {
1015 return I_JOIN_RESULT;
1016
1017 } else if (strcmp(op, CRM_OP_SHUTDOWN) == 0) {
1018 return handle_shutdown_self_ack(stored_msg);
1019
1020 } else if (strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) {
1021
1022 return handle_shutdown_request(stored_msg);
1023 }
1024 }
1025
1026
1027 if (strcmp(op, CRM_OP_NOVOTE) == 0) {
1028 ha_msg_input_t fsa_input;
1029
1030 fsa_input.msg = stored_msg;
1031 register_fsa_input_adv(C_HA_MESSAGE, I_NULL, &fsa_input,
1032 A_ELECTION_COUNT | A_ELECTION_CHECK, FALSE,
1033 __func__);
1034
1035 } else if (strcmp(op, CRM_OP_REMOTE_STATE) == 0) {
1036
1037 return handle_remote_state(stored_msg);
1038
1039 } else if (strcmp(op, CRM_OP_THROTTLE) == 0) {
1040 throttle_update(stored_msg);
1041 if (AM_I_DC && (controld_globals.transition_graph != NULL)
1042 && !controld_globals.transition_graph->complete) {
1043
1044 crm_debug("The throttle changed. Trigger a graph.");
1045 trigger_graph();
1046 }
1047 return I_NULL;
1048
1049 } else if (strcmp(op, CRM_OP_CLEAR_FAILCOUNT) == 0) {
1050 return handle_failcount_op(stored_msg);
1051
1052 } else if (strcmp(op, CRM_OP_VOTE) == 0) {
1053
1054 ha_msg_input_t fsa_input;
1055
1056 fsa_input.msg = stored_msg;
1057 register_fsa_input_adv(C_HA_MESSAGE, I_NULL, &fsa_input,
1058 A_ELECTION_COUNT | A_ELECTION_CHECK, FALSE,
1059 __func__);
1060
1061
1062 if (controld_globals.fsa_state == S_HALT) {
1063 crm_debug("Forcing an election from S_HALT");
1064 return I_ELECTION;
1065 #if 0
1066 } else if (AM_I_DC) {
1067
1068 return I_ELECTION;
1069 #endif
1070 }
1071
1072 } else if (strcmp(op, CRM_OP_JOIN_OFFER) == 0) {
1073 verify_feature_set(stored_msg);
1074 crm_debug("Raising I_JOIN_OFFER: join-%s", crm_element_value(stored_msg, F_CRM_JOIN_ID));
1075 return I_JOIN_OFFER;
1076
1077 } else if (strcmp(op, CRM_OP_JOIN_ACKNAK) == 0) {
1078 crm_debug("Raising I_JOIN_RESULT: join-%s", crm_element_value(stored_msg, F_CRM_JOIN_ID));
1079 return I_JOIN_RESULT;
1080
1081 } else if (strcmp(op, CRM_OP_LRM_DELETE) == 0) {
1082 return handle_lrm_delete(stored_msg);
1083
1084 } else if ((strcmp(op, CRM_OP_LRM_FAIL) == 0)
1085 || (strcmp(op, CRM_OP_LRM_REFRESH) == 0)
1086 || (strcmp(op, CRM_OP_REPROBE) == 0)) {
1087
1088 crm_xml_add(stored_msg, F_CRM_SYS_TO, CRM_SYSTEM_LRMD);
1089 return I_ROUTER;
1090
1091 } else if (strcmp(op, CRM_OP_NOOP) == 0) {
1092 return I_NULL;
1093
1094 } else if (strcmp(op, CRM_OP_LOCAL_SHUTDOWN) == 0) {
1095
1096 crm_shutdown(SIGTERM);
1097
1098 return I_NULL;
1099
1100 } else if (strcmp(op, CRM_OP_PING) == 0) {
1101 return handle_ping(stored_msg);
1102
1103 } else if (strcmp(op, CRM_OP_NODE_INFO) == 0) {
1104 return handle_node_info_request(stored_msg);
1105
1106 } else if (strcmp(op, CRM_OP_RM_NODE_CACHE) == 0) {
1107 int id = 0;
1108 const char *name = NULL;
1109
1110 crm_element_value_int(stored_msg, XML_ATTR_ID, &id);
1111 name = crm_element_value(stored_msg, XML_ATTR_UNAME);
1112
1113 if(cause == C_IPC_MESSAGE) {
1114 msg = create_request(CRM_OP_RM_NODE_CACHE, NULL, NULL, CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL);
1115 if (send_cluster_message(NULL, crm_msg_crmd, msg, TRUE) == FALSE) {
1116 crm_err("Could not instruct peers to remove references to node %s/%u", name, id);
1117 } else {
1118 crm_notice("Instructing peers to remove references to node %s/%u", name, id);
1119 }
1120 free_xml(msg);
1121
1122 } else {
1123 reap_crm_member(id, name);
1124
1125
1126
1127
1128
1129 st_fail_count_reset(name);
1130 }
1131
1132 } else if (strcmp(op, CRM_OP_MAINTENANCE_NODES) == 0) {
1133 xmlNode *xml = get_message_xml(stored_msg, F_CRM_DATA);
1134
1135 remote_ra_process_maintenance_nodes(xml);
1136
1137 } else if (strcmp(op, PCMK__CONTROLD_CMD_NODES) == 0) {
1138 return handle_node_list(stored_msg);
1139
1140
1141 } else if (!AM_I_DC) {
1142
1143 if (strcmp(op, CRM_OP_SHUTDOWN) == 0) {
1144 return handle_shutdown_ack(stored_msg);
1145 }
1146
1147 } else {
1148 crm_err("Unexpected request (%s) sent to %s", op, AM_I_DC ? "the DC" : "non-DC node");
1149 crm_log_xml_err(stored_msg, "Unexpected");
1150 }
1151
1152 return I_NULL;
1153 }
1154
1155 static void
1156 handle_response(xmlNode *stored_msg)
1157 {
1158 const char *op = crm_element_value(stored_msg, F_CRM_TASK);
1159
1160 if (op == NULL) {
1161 crm_log_xml_err(stored_msg, "Bad message");
1162
1163 } else if (AM_I_DC && strcmp(op, CRM_OP_PECALC) == 0) {
1164
1165 const char *msg_ref = crm_element_value(stored_msg, XML_ATTR_REFERENCE);
1166
1167 if (msg_ref == NULL) {
1168 crm_err("%s - Ignoring calculation with no reference", op);
1169
1170 } else if (pcmk__str_eq(msg_ref, controld_globals.fsa_pe_ref,
1171 pcmk__str_none)) {
1172 ha_msg_input_t fsa_input;
1173
1174 controld_stop_sched_timer();
1175 fsa_input.msg = stored_msg;
1176 register_fsa_input_later(C_IPC_MESSAGE, I_PE_SUCCESS, &fsa_input);
1177
1178 } else {
1179 crm_info("%s calculation %s is obsolete", op, msg_ref);
1180 }
1181
1182 } else if (strcmp(op, CRM_OP_VOTE) == 0
1183 || strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0 || strcmp(op, CRM_OP_SHUTDOWN) == 0) {
1184
1185 } else {
1186 const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
1187
1188 crm_err("Unexpected response (op=%s, src=%s) sent to the %s",
1189 op, host_from, AM_I_DC ? "DC" : "controller");
1190 }
1191 }
1192
1193 static enum crmd_fsa_input
1194 handle_shutdown_request(xmlNode * stored_msg)
1195 {
1196
1197
1198
1199
1200
1201
1202
1203 char *now_s = NULL;
1204 const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
1205
1206 if (host_from == NULL) {
1207
1208 host_from = controld_globals.our_nodename;
1209 }
1210
1211 crm_info("Creating shutdown request for %s (state=%s)", host_from,
1212 fsa_state2string(controld_globals.fsa_state));
1213 crm_log_xml_trace(stored_msg, "message");
1214
1215 now_s = pcmk__ttoa(time(NULL));
1216 update_attrd(host_from, XML_CIB_ATTR_SHUTDOWN, now_s, NULL, FALSE);
1217 free(now_s);
1218
1219
1220 return I_NULL;
1221 }
1222
1223 static void
1224 send_msg_via_ipc(xmlNode * msg, const char *sys)
1225 {
1226 pcmk__client_t *client_channel = NULL;
1227
1228 CRM_CHECK(sys != NULL, return);
1229
1230 client_channel = pcmk__find_client_by_id(sys);
1231
1232 if (crm_element_value(msg, F_CRM_HOST_FROM) == NULL) {
1233 crm_xml_add(msg, F_CRM_HOST_FROM, controld_globals.our_nodename);
1234 }
1235
1236 if (client_channel != NULL) {
1237
1238 pcmk__ipc_send_xml(client_channel, 0, msg, crm_ipc_server_event);
1239
1240 } else if (pcmk__str_eq(sys, CRM_SYSTEM_TENGINE, pcmk__str_none)) {
1241 xmlNode *data = get_message_xml(msg, F_CRM_DATA);
1242
1243 process_te_message(msg, data);
1244
1245 } else if (pcmk__str_eq(sys, CRM_SYSTEM_LRMD, pcmk__str_none)) {
1246 fsa_data_t fsa_data;
1247 ha_msg_input_t fsa_input;
1248
1249 fsa_input.msg = msg;
1250 fsa_input.xml = get_message_xml(msg, F_CRM_DATA);
1251
1252 fsa_data.id = 0;
1253 fsa_data.actions = 0;
1254 fsa_data.data = &fsa_input;
1255 fsa_data.fsa_input = I_MESSAGE;
1256 fsa_data.fsa_cause = C_IPC_MESSAGE;
1257 fsa_data.origin = __func__;
1258 fsa_data.data_type = fsa_dt_ha_msg;
1259
1260 do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE, controld_globals.fsa_state,
1261 I_MESSAGE, &fsa_data);
1262
1263 } else if (crmd_is_proxy_session(sys)) {
1264 crmd_proxy_send(sys, msg);
1265
1266 } else {
1267 crm_info("Received invalid request: unknown subsystem '%s'", sys);
1268 }
1269 }
1270
1271 void
1272 delete_ha_msg_input(ha_msg_input_t * orig)
1273 {
1274 if (orig == NULL) {
1275 return;
1276 }
1277 free_xml(orig->msg);
1278 free(orig);
1279 }
1280
1281
1282
1283
1284
1285
1286
1287
1288 void
1289 broadcast_remote_state_message(const char *node_name, bool node_up)
1290 {
1291 xmlNode *msg = create_request(CRM_OP_REMOTE_STATE, NULL, NULL,
1292 CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL);
1293
1294 crm_info("Notifying cluster of Pacemaker Remote node %s %s",
1295 node_name, node_up? "coming up" : "going down");
1296
1297 crm_xml_add(msg, XML_ATTR_ID, node_name);
1298 pcmk__xe_set_bool_attr(msg, XML_NODE_IN_CLUSTER, node_up);
1299
1300 if (node_up) {
1301 crm_xml_add(msg, PCMK__XA_CONN_HOST, controld_globals.our_nodename);
1302 }
1303
1304 send_cluster_message(NULL, crm_msg_crmd, msg, TRUE);
1305 free_xml(msg);
1306 }
1307