root/daemons/controld/controld_messages.c

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

DEFINITIONS

This source file includes following definitions.
  1. register_fsa_error_adv
  2. register_fsa_input_adv
  3. fsa_dump_queue
  4. copy_ha_msg_input
  5. delete_fsa_input
  6. get_message
  7. fsa_typed_data_adv
  8. do_msg_route
  9. route_message
  10. relay_message
  11. authorize_version
  12. controld_authorize_ipc_message
  13. handle_message
  14. handle_failcount_op
  15. handle_lrm_delete
  16. handle_remote_state
  17. handle_ping
  18. handle_node_list
  19. handle_node_info_request
  20. verify_feature_set
  21. handle_shutdown_self_ack
  22. handle_shutdown_ack
  23. handle_request
  24. handle_response
  25. handle_shutdown_request
  26. send_msg_via_ipc
  27. delete_ha_msg_input
  28. send_remote_state_message

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

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