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. broadcast_remote_state_message

   1 /*
   2  * Copyright 2004-2023 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 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 /* debug only, can wrap all it likes */
  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,
     /* [previous][next][first][last][top][bottom][index][help] */
  40                        fsa_data_t * cur_data, void *new_data, const char *raised_from)
  41 {
  42     /* save the current actions if any */
  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     /* reset the action list */
  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     /* register the error */
  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,
     /* [previous][next][first][last][top][bottom][index][help] */
  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 /* && data == NULL */ ) {
  71         /* no point doing anything */
  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         /* Store everything in the new event and reset
  93          * controld_globals.fsa_actions
  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     /* make sure to free it properly later */
 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     /* fsa_dump_queue(LOG_TRACE); */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /* returns the next message */
 244 fsa_data_t *
 245 get_message(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /*      A_MSG_ROUTE     */
 279 void
 280 do_msg_route(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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     /* try passing the buck first */
 300     if (relay_message(input, cause == C_IPC_MESSAGE)) {
 301         return;
 302     }
 303 
 304     /* handle locally */
 305     result = handle_message(input, cause);
 306 
 307     /* done or process later? */
 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             /* Defering local processing of message */
 318             register_fsa_input_later(cause, result, &fsa_input);
 319             return;
 320     }
 321 
 322     if (result != I_NULL) {
 323         /* add to the front of the queue */
 324         register_fsa_input(cause, result, &fsa_input);
 325     }
 326 }
 327 
 328 gboolean
 329 relay_message(xmlNode * msg, gboolean originated_locally)
     /* [previous][next][first][last][top][bottom][index][help] */
 330 {
 331     enum crm_ais_msg_types dest = crm_msg_ais;
 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     bool broadcast = false;
 339     const char *host_to = NULL;
 340     const char *sys_to = NULL;
 341     const char *sys_from = NULL;
 342     const char *type = NULL;
 343     const char *task = NULL;
 344     const char *ref = NULL;
 345     crm_node_t *node_to = NULL;
 346 
 347     CRM_CHECK(msg != NULL, return TRUE);
 348 
 349     host_to = crm_element_value(msg, F_CRM_HOST_TO);
 350     sys_to = crm_element_value(msg, F_CRM_SYS_TO);
 351     sys_from = crm_element_value(msg, F_CRM_SYS_FROM);
 352     type = crm_element_value(msg, F_TYPE);
 353     task = crm_element_value(msg, F_CRM_TASK);
 354     ref = crm_element_value(msg, XML_ATTR_REFERENCE);
 355 
 356     broadcast = pcmk__str_empty(host_to);
 357 
 358     if (ref == NULL) {
 359         ref = "without reference ID";
 360     }
 361 
 362     if (pcmk__str_eq(task, CRM_OP_HELLO, pcmk__str_casei)) {
 363         crm_trace("Received hello %s from %s (no processing needed)",
 364                   ref, pcmk__s(sys_from, "unidentified source"));
 365         crm_log_xml_trace(msg, "hello");
 366         return TRUE;
 367     }
 368 
 369     // Require message type (set by create_request())
 370     if (!pcmk__str_eq(type, T_CRM, pcmk__str_casei)) {
 371         crm_warn("Ignoring invalid message %s with type '%s' (not '" T_CRM "')",
 372                  ref, pcmk__s(type, ""));
 373         crm_log_xml_trace(msg, "ignored");
 374         return TRUE;
 375     }
 376 
 377     // Require a destination subsystem (also set by create_request())
 378     if (sys_to == NULL) {
 379         crm_warn("Ignoring invalid message %s with no " F_CRM_SYS_TO, ref);
 380         crm_log_xml_trace(msg, "ignored");
 381         return TRUE;
 382     }
 383 
 384     // Get the message type appropriate to the destination subsystem
 385     if (is_corosync_cluster()) {
 386         dest = text2msg_type(sys_to);
 387         if ((dest < crm_msg_ais) || (dest > crm_msg_stonith_ng)) {
 388             /* Unrecognized value, use a sane default
 389              *
 390              * @TODO Maybe we should bail instead
 391              */
 392             dest = crm_msg_crmd;
 393         }
 394     }
 395 
 396     is_for_dc = (strcasecmp(CRM_SYSTEM_DC, sys_to) == 0);
 397     is_for_dcib = (strcasecmp(CRM_SYSTEM_DCIB, sys_to) == 0);
 398     is_for_te = (strcasecmp(CRM_SYSTEM_TENGINE, sys_to) == 0);
 399     is_for_cib = (strcasecmp(CRM_SYSTEM_CIB, sys_to) == 0);
 400     is_for_crm = (strcasecmp(CRM_SYSTEM_CRMD, sys_to) == 0);
 401 
 402     // Check whether message should be processed locally
 403     is_local = false;
 404     if (broadcast) {
 405         if (is_for_dc || is_for_te) {
 406             is_local = false;
 407 
 408         } else if (is_for_crm) {
 409             if (pcmk__strcase_any_of(task, CRM_OP_NODE_INFO,
 410                                      PCMK__CONTROLD_CMD_NODES, NULL)) {
 411                 /* Node info requests do not specify a host, which is normally
 412                  * treated as "all hosts", because the whole point is that the
 413                  * client may not know the local node name. Always handle these
 414                  * requests locally.
 415                  */
 416                 is_local = true;
 417             } else {
 418                 is_local = !originated_locally;
 419             }
 420 
 421         } else {
 422             is_local = true;
 423         }
 424 
 425     } else if (pcmk__str_eq(controld_globals.our_nodename, host_to,
 426                             pcmk__str_casei)) {
 427         is_local = true;
 428 
 429     } else if (is_for_crm && pcmk__str_eq(task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
 430         xmlNode *msg_data = get_message_xml(msg, F_CRM_DATA);
 431         const char *mode = crm_element_value(msg_data, PCMK__XA_MODE);
 432 
 433         if (pcmk__str_eq(mode, XML_TAG_CIB, pcmk__str_casei)) {
 434             // Local delete of an offline node's resource history
 435             is_local = true;
 436         }
 437     }
 438 
 439     // Check whether message should be relayed
 440 
 441     if (is_for_dc || is_for_dcib || is_for_te) {
 442         if (AM_I_DC) {
 443             if (is_for_te) {
 444                 crm_trace("Route message %s locally as transition request",
 445                           ref);
 446                 crm_log_xml_trace(msg, sys_to);
 447                 send_msg_via_ipc(msg, sys_to);
 448                 return TRUE; // No further processing of message is needed
 449             }
 450             crm_trace("Route message %s locally as DC request", ref);
 451             return FALSE; // More to be done by caller
 452         }
 453 
 454         if (originated_locally
 455             && !pcmk__strcase_any_of(sys_from, CRM_SYSTEM_PENGINE,
 456                                      CRM_SYSTEM_TENGINE, NULL)) {
 457             crm_trace("Relay message %s to DC (via %s)",
 458                       ref, pcmk__s(host_to, "broadcast"));
 459             crm_log_xml_trace(msg, "relayed");
 460             if (!broadcast) {
 461                 node_to = crm_get_peer(0, host_to);
 462             }
 463             send_cluster_message(node_to, dest, msg, TRUE);
 464             return TRUE;
 465         }
 466 
 467         /* Transition engine and scheduler messages are sent only to the DC on
 468          * the same node. If we are no longer the DC, discard this message.
 469          */
 470         crm_trace("Ignoring message %s because we are no longer DC", ref);
 471         crm_log_xml_trace(msg, "ignored");
 472         return TRUE; // No further processing of message is needed
 473     }
 474 
 475     if (is_local) {
 476         if (is_for_crm || is_for_cib) {
 477             crm_trace("Route message %s locally as controller request", ref);
 478             return FALSE; // More to be done by caller
 479         }
 480         crm_trace("Relay message %s locally to %s", ref, sys_to);
 481         crm_log_xml_trace(msg, "IPC-relay");
 482         send_msg_via_ipc(msg, sys_to);
 483         return TRUE;
 484     }
 485 
 486     if (!broadcast) {
 487         node_to = pcmk__search_cluster_node_cache(0, host_to, NULL);
 488         if (node_to == NULL) {
 489             crm_warn("Ignoring message %s because node %s is unknown",
 490                      ref, host_to);
 491             crm_log_xml_trace(msg, "ignored");
 492             return TRUE;
 493         }
 494     }
 495 
 496     crm_trace("Relay message %s to %s",
 497               ref, pcmk__s(host_to, "all peers"));
 498     crm_log_xml_trace(msg, "relayed");
 499     send_cluster_message(node_to, dest, msg, TRUE);
 500     return TRUE;
 501 }
 502 
 503 // Return true if field contains a positive integer
 504 static bool
 505 authorize_version(xmlNode *message_data, const char *field,
     /* [previous][next][first][last][top][bottom][index][help] */
 506                   const char *client_name, const char *ref, const char *uuid)
 507 {
 508     const char *version = crm_element_value(message_data, field);
 509     long long version_num;
 510 
 511     if ((pcmk__scan_ll(version, &version_num, -1LL) != pcmk_rc_ok)
 512         || (version_num < 0LL)) {
 513 
 514         crm_warn("Rejected IPC hello from %s: '%s' is not a valid protocol %s "
 515                  CRM_XS " ref=%s uuid=%s",
 516                  client_name, ((version == NULL)? "" : version),
 517                  field, (ref? ref : "none"), uuid);
 518         return false;
 519     }
 520     return true;
 521 }
 522 
 523 /*!
 524  * \internal
 525  * \brief Check whether a client IPC message is acceptable
 526  *
 527  * If a given client IPC message is a hello, "authorize" it by ensuring it has
 528  * valid information such as a protocol version, and return false indicating
 529  * that nothing further needs to be done with the message. If the message is not
 530  * a hello, just return true to indicate it needs further processing.
 531  *
 532  * \param[in]     client_msg     XML of IPC message
 533  * \param[in,out] curr_client    If IPC is not proxied, client that sent message
 534  * \param[in]     proxy_session  If IPC is proxied, the session ID
 535  *
 536  * \return true if message needs further processing, false if it doesn't
 537  */
 538 bool
 539 controld_authorize_ipc_message(const xmlNode *client_msg, pcmk__client_t *curr_client,
     /* [previous][next][first][last][top][bottom][index][help] */
 540                                const char *proxy_session)
 541 {
 542     xmlNode *message_data = NULL;
 543     const char *client_name = NULL;
 544     const char *op = crm_element_value(client_msg, F_CRM_TASK);
 545     const char *ref = crm_element_value(client_msg, XML_ATTR_REFERENCE);
 546     const char *uuid = (curr_client? curr_client->id : proxy_session);
 547 
 548     if (uuid == NULL) {
 549         crm_warn("IPC message from client rejected: No client identifier "
 550                  CRM_XS " ref=%s", (ref? ref : "none"));
 551         goto rejected;
 552     }
 553 
 554     if (!pcmk__str_eq(CRM_OP_HELLO, op, pcmk__str_casei)) {
 555         // Only hello messages need to be authorized
 556         return true;
 557     }
 558 
 559     message_data = get_message_xml(client_msg, F_CRM_DATA);
 560 
 561     client_name = crm_element_value(message_data, "client_name");
 562     if (pcmk__str_empty(client_name)) {
 563         crm_warn("IPC hello from client rejected: No client name",
 564                  CRM_XS " ref=%s uuid=%s", (ref? ref : "none"), uuid);
 565         goto rejected;
 566     }
 567     if (!authorize_version(message_data, "major_version", client_name, ref,
 568                            uuid)) {
 569         goto rejected;
 570     }
 571     if (!authorize_version(message_data, "minor_version", client_name, ref,
 572                            uuid)) {
 573         goto rejected;
 574     }
 575 
 576     crm_trace("Validated IPC hello from client %s", client_name);
 577     crm_log_xml_trace(client_msg, "hello");
 578     if (curr_client) {
 579         curr_client->userdata = strdup(client_name);
 580     }
 581     controld_trigger_fsa();
 582     return false;
 583 
 584 rejected:
 585     crm_log_xml_trace(client_msg, "rejected");
 586     if (curr_client) {
 587         qb_ipcs_disconnect(curr_client->ipcs);
 588     }
 589     return false;
 590 }
 591 
 592 static enum crmd_fsa_input
 593 handle_message(xmlNode *msg, enum crmd_fsa_cause cause)
     /* [previous][next][first][last][top][bottom][index][help] */
 594 {
 595     const char *type = NULL;
 596 
 597     CRM_CHECK(msg != NULL, return I_NULL);
 598 
 599     type = crm_element_value(msg, F_CRM_MSG_TYPE);
 600     if (pcmk__str_eq(type, XML_ATTR_REQUEST, pcmk__str_none)) {
 601         return handle_request(msg, cause);
 602 
 603     } else if (pcmk__str_eq(type, XML_ATTR_RESPONSE, pcmk__str_none)) {
 604         handle_response(msg);
 605         return I_NULL;
 606     }
 607 
 608     crm_warn("Ignoring message with unknown " F_CRM_MSG_TYPE " '%s'",
 609              pcmk__s(type, ""));
 610     crm_log_xml_trace(msg, "bad");
 611     return I_NULL;
 612 }
 613 
 614 static enum crmd_fsa_input
 615 handle_failcount_op(xmlNode * stored_msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 616 {
 617     const char *rsc = NULL;
 618     const char *uname = NULL;
 619     const char *op = NULL;
 620     char *interval_spec = NULL;
 621     guint interval_ms = 0;
 622     gboolean is_remote_node = FALSE;
 623     xmlNode *xml_op = get_message_xml(stored_msg, F_CRM_DATA);
 624 
 625     if (xml_op) {
 626         xmlNode *xml_rsc = first_named_child(xml_op, XML_CIB_TAG_RESOURCE);
 627         xmlNode *xml_attrs = first_named_child(xml_op, XML_TAG_ATTRS);
 628 
 629         if (xml_rsc) {
 630             rsc = ID(xml_rsc);
 631         }
 632         if (xml_attrs) {
 633             op = crm_element_value(xml_attrs,
 634                                    CRM_META "_" XML_RSC_ATTR_CLEAR_OP);
 635             crm_element_value_ms(xml_attrs,
 636                                  CRM_META "_" XML_RSC_ATTR_CLEAR_INTERVAL,
 637                                  &interval_ms);
 638         }
 639     }
 640     uname = crm_element_value(xml_op, XML_LRM_ATTR_TARGET);
 641 
 642     if ((rsc == NULL) || (uname == NULL)) {
 643         crm_log_xml_warn(stored_msg, "invalid failcount op");
 644         return I_NULL;
 645     }
 646 
 647     if (crm_element_value(xml_op, XML_LRM_ATTR_ROUTER_NODE)) {
 648         is_remote_node = TRUE;
 649     }
 650 
 651     crm_debug("Clearing failures for %s-interval %s on %s "
 652               "from attribute manager, CIB, and executor state",
 653               pcmk__readable_interval(interval_ms), rsc, uname);
 654 
 655     if (interval_ms) {
 656         interval_spec = crm_strdup_printf("%ums", interval_ms);
 657     }
 658     update_attrd_clear_failures(uname, rsc, op, interval_spec, is_remote_node);
 659     free(interval_spec);
 660 
 661     controld_cib_delete_last_failure(rsc, uname, op, interval_ms);
 662 
 663     lrm_clear_last_failure(rsc, uname, op, interval_ms);
 664 
 665     return I_NULL;
 666 }
 667 
 668 static enum crmd_fsa_input
 669 handle_lrm_delete(xmlNode *stored_msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 670 {
 671     const char *mode = NULL;
 672     xmlNode *msg_data = get_message_xml(stored_msg, F_CRM_DATA);
 673 
 674     CRM_CHECK(msg_data != NULL, return I_NULL);
 675 
 676     /* CRM_OP_LRM_DELETE has two distinct modes. The default behavior is to
 677      * relay the operation to the affected node, which will unregister the
 678      * resource from the local executor, clear the resource's history from the
 679      * CIB, and do some bookkeeping in the controller.
 680      *
 681      * However, if the affected node is offline, the client will specify
 682      * mode="cib" which means the controller receiving the operation should
 683      * clear the resource's history from the CIB and nothing else. This is used
 684      * to clear shutdown locks.
 685      */
 686     mode = crm_element_value(msg_data, PCMK__XA_MODE);
 687     if ((mode == NULL) || strcmp(mode, XML_TAG_CIB)) {
 688         // Relay to affected node
 689         crm_xml_add(stored_msg, F_CRM_SYS_TO, CRM_SYSTEM_LRMD);
 690         return I_ROUTER;
 691 
 692     } else {
 693         // Delete CIB history locally (compare with do_lrm_delete())
 694         const char *from_sys = NULL;
 695         const char *user_name = NULL;
 696         const char *rsc_id = NULL;
 697         const char *node = NULL;
 698         xmlNode *rsc_xml = NULL;
 699         int rc = pcmk_rc_ok;
 700 
 701         rsc_xml = first_named_child(msg_data, XML_CIB_TAG_RESOURCE);
 702         CRM_CHECK(rsc_xml != NULL, return I_NULL);
 703 
 704         rsc_id = ID(rsc_xml);
 705         from_sys = crm_element_value(stored_msg, F_CRM_SYS_FROM);
 706         node = crm_element_value(msg_data, XML_LRM_ATTR_TARGET);
 707         user_name = pcmk__update_acl_user(stored_msg, F_CRM_USER, NULL);
 708         crm_debug("Handling " CRM_OP_LRM_DELETE " for %s on %s locally%s%s "
 709                   "(clearing CIB resource history only)", rsc_id, node,
 710                   (user_name? " for user " : ""), (user_name? user_name : ""));
 711         rc = controld_delete_resource_history(rsc_id, node, user_name,
 712                                               cib_dryrun|cib_sync_call);
 713         if (rc == pcmk_rc_ok) {
 714             rc = controld_delete_resource_history(rsc_id, node, user_name,
 715                                                   crmd_cib_smart_opt());
 716         }
 717 
 718         //Notify client and tengine.(Only notify tengine if mode = "cib" and CRM_OP_LRM_DELETE.)
 719         if (from_sys) {
 720             lrmd_event_data_t *op = NULL;
 721             const char *from_host = crm_element_value(stored_msg,
 722                                                       F_CRM_HOST_FROM);
 723             const char *transition;
 724 
 725             if (strcmp(from_sys, CRM_SYSTEM_TENGINE)) {
 726                 transition = crm_element_value(msg_data,
 727                                                        XML_ATTR_TRANSITION_KEY);
 728             } else {
 729                 transition = crm_element_value(stored_msg,
 730                                                        XML_ATTR_TRANSITION_KEY);
 731             }
 732 
 733             crm_info("Notifying %s on %s that %s was%s deleted",
 734                      from_sys, (from_host? from_host : "local node"), rsc_id,
 735                      ((rc == pcmk_rc_ok)? "" : " not"));
 736             op = lrmd_new_event(rsc_id, PCMK_ACTION_DELETE, 0);
 737             op->type = lrmd_event_exec_complete;
 738             op->user_data = strdup(transition? transition : FAKE_TE_ID);
 739             op->params = pcmk__strkey_table(free, free);
 740             g_hash_table_insert(op->params, strdup(XML_ATTR_CRM_VERSION),
 741                                 strdup(CRM_FEATURE_SET));
 742             controld_rc2event(op, rc);
 743             controld_ack_event_directly(from_host, from_sys, NULL, op, rsc_id);
 744             lrmd_free_event(op);
 745             controld_trigger_delete_refresh(from_sys, rsc_id);
 746         }
 747         return I_NULL;
 748     }
 749 }
 750 
 751 /*!
 752  * \brief Handle a CRM_OP_REMOTE_STATE message by updating remote peer cache
 753  *
 754  * \param[in] msg  Message XML
 755  *
 756  * \return Next FSA input
 757  */
 758 static enum crmd_fsa_input
 759 handle_remote_state(const xmlNode *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 760 {
 761     const char *conn_host = NULL;
 762     const char *remote_uname = ID(msg);
 763     crm_node_t *remote_peer;
 764     bool remote_is_up = false;
 765     int rc = pcmk_rc_ok;
 766 
 767     rc = pcmk__xe_get_bool_attr(msg, PCMK__XA_IN_CCM, &remote_is_up);
 768 
 769     CRM_CHECK(remote_uname && rc == pcmk_rc_ok, return I_NULL);
 770 
 771     remote_peer = crm_remote_peer_get(remote_uname);
 772     CRM_CHECK(remote_peer, return I_NULL);
 773 
 774     pcmk__update_peer_state(__func__, remote_peer,
 775                             remote_is_up ? CRM_NODE_MEMBER : CRM_NODE_LOST,
 776                             0);
 777 
 778     conn_host = crm_element_value(msg, PCMK__XA_CONN_HOST);
 779     if (conn_host) {
 780         pcmk__str_update(&remote_peer->conn_host, conn_host);
 781     } else if (remote_peer->conn_host) {
 782         free(remote_peer->conn_host);
 783         remote_peer->conn_host = NULL;
 784     }
 785 
 786     return I_NULL;
 787 }
 788 
 789 /*!
 790  * \brief Handle a CRM_OP_PING message
 791  *
 792  * \param[in] msg  Message XML
 793  *
 794  * \return Next FSA input
 795  */
 796 static enum crmd_fsa_input
 797 handle_ping(const xmlNode *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 798 {
 799     const char *value = NULL;
 800     xmlNode *ping = NULL;
 801     xmlNode *reply = NULL;
 802 
 803     // Build reply
 804 
 805     ping = create_xml_node(NULL, XML_CRM_TAG_PING);
 806     value = crm_element_value(msg, F_CRM_SYS_TO);
 807     crm_xml_add(ping, XML_PING_ATTR_SYSFROM, value);
 808 
 809     // Add controller state
 810     value = fsa_state2string(controld_globals.fsa_state);
 811     crm_xml_add(ping, XML_PING_ATTR_CRMDSTATE, value);
 812     crm_notice("Current ping state: %s", value); // CTS needs this
 813 
 814     // Add controller health
 815     // @TODO maybe do some checks to determine meaningful status
 816     crm_xml_add(ping, XML_PING_ATTR_STATUS, "ok");
 817 
 818     // Send reply
 819     reply = create_reply(msg, ping);
 820     free_xml(ping);
 821     if (reply != NULL) {
 822         (void) relay_message(reply, TRUE);
 823         free_xml(reply);
 824     }
 825 
 826     // Nothing further to do
 827     return I_NULL;
 828 }
 829 
 830 /*!
 831  * \brief Handle a PCMK__CONTROLD_CMD_NODES message
 832  *
 833  * \param[in] request  Message XML
 834  *
 835  * \return Next FSA input
 836  */
 837 static enum crmd_fsa_input
 838 handle_node_list(const xmlNode *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 839 {
 840     GHashTableIter iter;
 841     crm_node_t *node = NULL;
 842     xmlNode *reply = NULL;
 843     xmlNode *reply_data = NULL;
 844 
 845     // Create message data for reply
 846     reply_data = create_xml_node(NULL, XML_CIB_TAG_NODES);
 847     g_hash_table_iter_init(&iter, crm_peer_cache);
 848     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) {
 849         xmlNode *xml = create_xml_node(reply_data, XML_CIB_TAG_NODE);
 850 
 851         crm_xml_add_ll(xml, XML_ATTR_ID, (long long) node->id); // uint32_t
 852         crm_xml_add(xml, XML_ATTR_UNAME, node->uname);
 853         crm_xml_add(xml, PCMK__XA_IN_CCM, node->state);
 854     }
 855 
 856     // Create and send reply
 857     reply = create_reply(request, reply_data);
 858     free_xml(reply_data);
 859     if (reply) {
 860         (void) relay_message(reply, TRUE);
 861         free_xml(reply);
 862     }
 863 
 864     // Nothing further to do
 865     return I_NULL;
 866 }
 867 
 868 /*!
 869  * \brief Handle a CRM_OP_NODE_INFO request
 870  *
 871  * \param[in] msg  Message XML
 872  *
 873  * \return Next FSA input
 874  */
 875 static enum crmd_fsa_input
 876 handle_node_info_request(const xmlNode *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 877 {
 878     const char *value = NULL;
 879     crm_node_t *node = NULL;
 880     int node_id = 0;
 881     xmlNode *reply = NULL;
 882     xmlNode *reply_data = NULL;
 883 
 884     // Build reply
 885 
 886     reply_data = create_xml_node(NULL, XML_CIB_TAG_NODE);
 887     crm_xml_add(reply_data, XML_PING_ATTR_SYSFROM, CRM_SYSTEM_CRMD);
 888 
 889     // Add whether current partition has quorum
 890     pcmk__xe_set_bool_attr(reply_data, XML_ATTR_HAVE_QUORUM,
 891                            pcmk_is_set(controld_globals.flags,
 892                                        controld_has_quorum));
 893 
 894     // Check whether client requested node info by ID and/or name
 895     crm_element_value_int(msg, XML_ATTR_ID, &node_id);
 896     if (node_id < 0) {
 897         node_id = 0;
 898     }
 899     value = crm_element_value(msg, XML_ATTR_UNAME);
 900 
 901     // Default to local node if none given
 902     if ((node_id == 0) && (value == NULL)) {
 903         value = controld_globals.our_nodename;
 904     }
 905 
 906     node = pcmk__search_node_caches(node_id, value, CRM_GET_PEER_ANY);
 907     if (node) {
 908         crm_xml_add(reply_data, XML_ATTR_ID, node->uuid);
 909         crm_xml_add(reply_data, XML_ATTR_UNAME, node->uname);
 910         crm_xml_add(reply_data, PCMK__XA_CRMD, node->state);
 911         pcmk__xe_set_bool_attr(reply_data, XML_NODE_IS_REMOTE,
 912                                pcmk_is_set(node->flags, crm_remote_node));
 913     }
 914 
 915     // Send reply
 916     reply = create_reply(msg, reply_data);
 917     free_xml(reply_data);
 918     if (reply != NULL) {
 919         (void) relay_message(reply, TRUE);
 920         free_xml(reply);
 921     }
 922 
 923     // Nothing further to do
 924     return I_NULL;
 925 }
 926 
 927 static void
 928 verify_feature_set(xmlNode *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 929 {
 930     const char *dc_version = crm_element_value(msg, XML_ATTR_CRM_VERSION);
 931 
 932     if (dc_version == NULL) {
 933         /* All we really know is that the DC feature set is older than 3.1.0,
 934          * but that's also all that really matters.
 935          */
 936         dc_version = "3.0.14";
 937     }
 938 
 939     if (feature_set_compatible(dc_version, CRM_FEATURE_SET)) {
 940         crm_trace("Local feature set (%s) is compatible with DC's (%s)",
 941                   CRM_FEATURE_SET, dc_version);
 942     } else {
 943         crm_err("Local feature set (%s) is incompatible with DC's (%s)",
 944                 CRM_FEATURE_SET, dc_version);
 945 
 946         // Nothing is likely to improve without administrator involvement
 947         controld_set_fsa_input_flags(R_STAYDOWN);
 948         crmd_exit(CRM_EX_FATAL);
 949     }
 950 }
 951 
 952 // DC gets own shutdown all-clear
 953 static enum crmd_fsa_input
 954 handle_shutdown_self_ack(xmlNode *stored_msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 955 {
 956     const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
 957 
 958     if (pcmk_is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
 959         // The expected case -- we initiated own shutdown sequence
 960         crm_info("Shutting down controller");
 961         return I_STOP;
 962     }
 963 
 964     if (pcmk__str_eq(host_from, controld_globals.dc_name, pcmk__str_casei)) {
 965         // Must be logic error -- DC confirming its own unrequested shutdown
 966         crm_err("Shutting down controller immediately due to "
 967                 "unexpected shutdown confirmation");
 968         return I_TERMINATE;
 969     }
 970 
 971     if (controld_globals.fsa_state != S_STOPPING) {
 972         // Shouldn't happen -- non-DC confirming unrequested shutdown
 973         crm_err("Starting new DC election because %s is "
 974                 "confirming shutdown we did not request",
 975                 (host_from? host_from : "another node"));
 976         return I_ELECTION;
 977     }
 978 
 979     // Shouldn't happen, but we are already stopping anyway
 980     crm_debug("Ignoring unexpected shutdown confirmation from %s",
 981               (host_from? host_from : "another node"));
 982     return I_NULL;
 983 }
 984 
 985 // Non-DC gets shutdown all-clear from DC
 986 static enum crmd_fsa_input
 987 handle_shutdown_ack(xmlNode *stored_msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 988 {
 989     const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
 990 
 991     if (host_from == NULL) {
 992         crm_warn("Ignoring shutdown request without origin specified");
 993         return I_NULL;
 994     }
 995 
 996     if (pcmk__str_eq(host_from, controld_globals.dc_name,
 997                      pcmk__str_null_matches|pcmk__str_casei)) {
 998 
 999         if (pcmk_is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
1000             crm_info("Shutting down controller after confirmation from %s",
1001                      host_from);
1002         } else {
1003             crm_err("Shutting down controller after unexpected "
1004                     "shutdown request from %s", host_from);
1005             controld_set_fsa_input_flags(R_STAYDOWN);
1006         }
1007         return I_STOP;
1008     }
1009 
1010     crm_warn("Ignoring shutdown request from %s because DC is %s",
1011              host_from, controld_globals.dc_name);
1012     return I_NULL;
1013 }
1014 
1015 static enum crmd_fsa_input
1016 handle_request(xmlNode *stored_msg, enum crmd_fsa_cause cause)
     /* [previous][next][first][last][top][bottom][index][help] */
1017 {
1018     xmlNode *msg = NULL;
1019     const char *op = crm_element_value(stored_msg, F_CRM_TASK);
1020 
1021     /* Optimize this for the DC - it has the most to do */
1022 
1023     crm_log_xml_trace(stored_msg, "request");
1024     if (op == NULL) {
1025         crm_warn("Ignoring request without " F_CRM_TASK);
1026         return I_NULL;
1027     }
1028 
1029     if (strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) {
1030         const char *from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
1031         crm_node_t *node = pcmk__search_cluster_node_cache(0, from, NULL);
1032 
1033         pcmk__update_peer_expected(__func__, node, CRMD_JOINSTATE_DOWN);
1034         if(AM_I_DC == FALSE) {
1035             return I_NULL; /* Done */
1036         }
1037     }
1038 
1039     /*========== DC-Only Actions ==========*/
1040     if (AM_I_DC) {
1041         if (strcmp(op, CRM_OP_JOIN_ANNOUNCE) == 0) {
1042             return I_NODE_JOIN;
1043 
1044         } else if (strcmp(op, CRM_OP_JOIN_REQUEST) == 0) {
1045             return I_JOIN_REQUEST;
1046 
1047         } else if (strcmp(op, CRM_OP_JOIN_CONFIRM) == 0) {
1048             return I_JOIN_RESULT;
1049 
1050         } else if (strcmp(op, CRM_OP_SHUTDOWN) == 0) {
1051             return handle_shutdown_self_ack(stored_msg);
1052 
1053         } else if (strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) {
1054             // Another controller wants to shut down its node
1055             return handle_shutdown_request(stored_msg);
1056         }
1057     }
1058 
1059     /*========== common actions ==========*/
1060     if (strcmp(op, CRM_OP_NOVOTE) == 0) {
1061         ha_msg_input_t fsa_input;
1062 
1063         fsa_input.msg = stored_msg;
1064         register_fsa_input_adv(C_HA_MESSAGE, I_NULL, &fsa_input,
1065                                A_ELECTION_COUNT | A_ELECTION_CHECK, FALSE,
1066                                __func__);
1067 
1068     } else if (strcmp(op, CRM_OP_REMOTE_STATE) == 0) {
1069         /* a remote connection host is letting us know the node state */
1070         return handle_remote_state(stored_msg);
1071 
1072     } else if (strcmp(op, CRM_OP_THROTTLE) == 0) {
1073         throttle_update(stored_msg);
1074         if (AM_I_DC && (controld_globals.transition_graph != NULL)
1075             && !controld_globals.transition_graph->complete) {
1076 
1077             crm_debug("The throttle changed. Trigger a graph.");
1078             trigger_graph();
1079         }
1080         return I_NULL;
1081 
1082     } else if (strcmp(op, CRM_OP_CLEAR_FAILCOUNT) == 0) {
1083         return handle_failcount_op(stored_msg);
1084 
1085     } else if (strcmp(op, CRM_OP_VOTE) == 0) {
1086         /* count the vote and decide what to do after that */
1087         ha_msg_input_t fsa_input;
1088 
1089         fsa_input.msg = stored_msg;
1090         register_fsa_input_adv(C_HA_MESSAGE, I_NULL, &fsa_input,
1091                                A_ELECTION_COUNT | A_ELECTION_CHECK, FALSE,
1092                                __func__);
1093 
1094         /* Sometimes we _must_ go into S_ELECTION */
1095         if (controld_globals.fsa_state == S_HALT) {
1096             crm_debug("Forcing an election from S_HALT");
1097             return I_ELECTION;
1098         }
1099 
1100     } else if (strcmp(op, CRM_OP_JOIN_OFFER) == 0) {
1101         verify_feature_set(stored_msg);
1102         crm_debug("Raising I_JOIN_OFFER: join-%s", crm_element_value(stored_msg, F_CRM_JOIN_ID));
1103         return I_JOIN_OFFER;
1104 
1105     } else if (strcmp(op, CRM_OP_JOIN_ACKNAK) == 0) {
1106         crm_debug("Raising I_JOIN_RESULT: join-%s", crm_element_value(stored_msg, F_CRM_JOIN_ID));
1107         return I_JOIN_RESULT;
1108 
1109     } else if (strcmp(op, CRM_OP_LRM_DELETE) == 0) {
1110         return handle_lrm_delete(stored_msg);
1111 
1112     } else if ((strcmp(op, CRM_OP_LRM_FAIL) == 0)
1113                || (strcmp(op, CRM_OP_LRM_REFRESH) == 0) // @COMPAT
1114                || (strcmp(op, CRM_OP_REPROBE) == 0)) {
1115 
1116         crm_xml_add(stored_msg, F_CRM_SYS_TO, CRM_SYSTEM_LRMD);
1117         return I_ROUTER;
1118 
1119     } else if (strcmp(op, CRM_OP_NOOP) == 0) {
1120         return I_NULL;
1121 
1122     } else if (strcmp(op, CRM_OP_LOCAL_SHUTDOWN) == 0) {
1123 
1124         crm_shutdown(SIGTERM);
1125         /*return I_SHUTDOWN; */
1126         return I_NULL;
1127 
1128     } else if (strcmp(op, CRM_OP_PING) == 0) {
1129         return handle_ping(stored_msg);
1130 
1131     } else if (strcmp(op, CRM_OP_NODE_INFO) == 0) {
1132         return handle_node_info_request(stored_msg);
1133 
1134     } else if (strcmp(op, CRM_OP_RM_NODE_CACHE) == 0) {
1135         int id = 0;
1136         const char *name = NULL;
1137 
1138         crm_element_value_int(stored_msg, XML_ATTR_ID, &id);
1139         name = crm_element_value(stored_msg, XML_ATTR_UNAME);
1140 
1141         if(cause == C_IPC_MESSAGE) {
1142             msg = create_request(CRM_OP_RM_NODE_CACHE, NULL, NULL, CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL);
1143             if (send_cluster_message(NULL, crm_msg_crmd, msg, TRUE) == FALSE) {
1144                 crm_err("Could not instruct peers to remove references to node %s/%u", name, id);
1145             } else {
1146                 crm_notice("Instructing peers to remove references to node %s/%u", name, id);
1147             }
1148             free_xml(msg);
1149 
1150         } else {
1151             reap_crm_member(id, name);
1152 
1153             /* If we're forgetting this node, also forget any failures to fence
1154              * it, so we don't carry that over to any node added later with the
1155              * same name.
1156              */
1157             st_fail_count_reset(name);
1158         }
1159 
1160     } else if (strcmp(op, CRM_OP_MAINTENANCE_NODES) == 0) {
1161         xmlNode *xml = get_message_xml(stored_msg, F_CRM_DATA);
1162 
1163         remote_ra_process_maintenance_nodes(xml);
1164 
1165     } else if (strcmp(op, PCMK__CONTROLD_CMD_NODES) == 0) {
1166         return handle_node_list(stored_msg);
1167 
1168         /*========== (NOT_DC)-Only Actions ==========*/
1169     } else if (!AM_I_DC) {
1170 
1171         if (strcmp(op, CRM_OP_SHUTDOWN) == 0) {
1172             return handle_shutdown_ack(stored_msg);
1173         }
1174 
1175     } else {
1176         crm_err("Unexpected request (%s) sent to %s", op, AM_I_DC ? "the DC" : "non-DC node");
1177         crm_log_xml_err(stored_msg, "Unexpected");
1178     }
1179 
1180     return I_NULL;
1181 }
1182 
1183 static void
1184 handle_response(xmlNode *stored_msg)
     /* [previous][next][first][last][top][bottom][index][help] */
1185 {
1186     const char *op = crm_element_value(stored_msg, F_CRM_TASK);
1187 
1188     crm_log_xml_trace(stored_msg, "reply");
1189     if (op == NULL) {
1190         crm_warn("Ignoring reply without " F_CRM_TASK);
1191 
1192     } else if (AM_I_DC && strcmp(op, CRM_OP_PECALC) == 0) {
1193         // Check whether scheduler answer been superseded by subsequent request
1194         const char *msg_ref = crm_element_value(stored_msg, XML_ATTR_REFERENCE);
1195 
1196         if (msg_ref == NULL) {
1197             crm_err("%s - Ignoring calculation with no reference", op);
1198 
1199         } else if (pcmk__str_eq(msg_ref, controld_globals.fsa_pe_ref,
1200                                 pcmk__str_none)) {
1201             ha_msg_input_t fsa_input;
1202 
1203             controld_stop_sched_timer();
1204             fsa_input.msg = stored_msg;
1205             register_fsa_input_later(C_IPC_MESSAGE, I_PE_SUCCESS, &fsa_input);
1206 
1207         } else {
1208             crm_info("%s calculation %s is obsolete", op, msg_ref);
1209         }
1210 
1211     } else if (strcmp(op, CRM_OP_VOTE) == 0
1212                || strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0 || strcmp(op, CRM_OP_SHUTDOWN) == 0) {
1213 
1214     } else {
1215         const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
1216 
1217         crm_err("Unexpected response (op=%s, src=%s) sent to the %s",
1218                 op, host_from, AM_I_DC ? "DC" : "controller");
1219     }
1220 }
1221 
1222 static enum crmd_fsa_input
1223 handle_shutdown_request(xmlNode * stored_msg)
     /* [previous][next][first][last][top][bottom][index][help] */
1224 {
1225     /* handle here to avoid potential version issues
1226      *   where the shutdown message/procedure may have
1227      *   been changed in later versions.
1228      *
1229      * This way the DC is always in control of the shutdown
1230      */
1231 
1232     char *now_s = NULL;
1233     const char *host_from = crm_element_value(stored_msg, F_CRM_HOST_FROM);
1234 
1235     if (host_from == NULL) {
1236         /* we're shutting down and the DC */
1237         host_from = controld_globals.our_nodename;
1238     }
1239 
1240     crm_info("Creating shutdown request for %s (state=%s)", host_from,
1241              fsa_state2string(controld_globals.fsa_state));
1242     crm_log_xml_trace(stored_msg, "message");
1243 
1244     now_s = pcmk__ttoa(time(NULL));
1245     update_attrd(host_from, XML_CIB_ATTR_SHUTDOWN, now_s, NULL, FALSE);
1246     free(now_s);
1247 
1248     /* will be picked up by the TE as long as its running */
1249     return I_NULL;
1250 }
1251 
1252 static void
1253 send_msg_via_ipc(xmlNode * msg, const char *sys)
     /* [previous][next][first][last][top][bottom][index][help] */
1254 {
1255     pcmk__client_t *client_channel = NULL;
1256 
1257     CRM_CHECK(sys != NULL, return);
1258 
1259     client_channel = pcmk__find_client_by_id(sys);
1260 
1261     if (crm_element_value(msg, F_CRM_HOST_FROM) == NULL) {
1262         crm_xml_add(msg, F_CRM_HOST_FROM, controld_globals.our_nodename);
1263     }
1264 
1265     if (client_channel != NULL) {
1266         /* Transient clients such as crmadmin */
1267         pcmk__ipc_send_xml(client_channel, 0, msg, crm_ipc_server_event);
1268 
1269     } else if (pcmk__str_eq(sys, CRM_SYSTEM_TENGINE, pcmk__str_none)) {
1270         xmlNode *data = get_message_xml(msg, F_CRM_DATA);
1271 
1272         process_te_message(msg, data);
1273 
1274     } else if (pcmk__str_eq(sys, CRM_SYSTEM_LRMD, pcmk__str_none)) {
1275         fsa_data_t fsa_data;
1276         ha_msg_input_t fsa_input;
1277 
1278         fsa_input.msg = msg;
1279         fsa_input.xml = get_message_xml(msg, F_CRM_DATA);
1280 
1281         fsa_data.id = 0;
1282         fsa_data.actions = 0;
1283         fsa_data.data = &fsa_input;
1284         fsa_data.fsa_input = I_MESSAGE;
1285         fsa_data.fsa_cause = C_IPC_MESSAGE;
1286         fsa_data.origin = __func__;
1287         fsa_data.data_type = fsa_dt_ha_msg;
1288 
1289         do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE, controld_globals.fsa_state,
1290                       I_MESSAGE, &fsa_data);
1291 
1292     } else if (crmd_is_proxy_session(sys)) {
1293         crmd_proxy_send(sys, msg);
1294 
1295     } else {
1296         crm_info("Received invalid request: unknown subsystem '%s'", sys);
1297     }
1298 }
1299 
1300 void
1301 delete_ha_msg_input(ha_msg_input_t * orig)
     /* [previous][next][first][last][top][bottom][index][help] */
1302 {
1303     if (orig == NULL) {
1304         return;
1305     }
1306     free_xml(orig->msg);
1307     free(orig);
1308 }
1309 
1310 /*!
1311  * \internal
1312  * \brief Notify the cluster of a remote node state change
1313  *
1314  * \param[in] node_name  Node's name
1315  * \param[in] node_up    true if node is up, false if down
1316  */
1317 void
1318 broadcast_remote_state_message(const char *node_name, bool node_up)
     /* [previous][next][first][last][top][bottom][index][help] */
1319 {
1320     xmlNode *msg = create_request(CRM_OP_REMOTE_STATE, NULL, NULL,
1321                                   CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL);
1322 
1323     crm_info("Notifying cluster of Pacemaker Remote node %s %s",
1324              node_name, node_up? "coming up" : "going down");
1325 
1326     crm_xml_add(msg, XML_ATTR_ID, node_name);
1327     pcmk__xe_set_bool_attr(msg, PCMK__XA_IN_CCM, node_up);
1328 
1329     if (node_up) {
1330         crm_xml_add(msg, PCMK__XA_CONN_HOST, controld_globals.our_nodename);
1331     }
1332 
1333     send_cluster_message(NULL, crm_msg_crmd, msg, TRUE);
1334     free_xml(msg);
1335 }
1336 

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