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-2024 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/common/xml.h>
  18 #include <crm/cluster/internal.h>
  19 #include <crm/cib.h>
  20 #include <crm/common/ipc_internal.h>
  21 
  22 #include <pacemaker-controld.h>
  23 
  24 static enum crmd_fsa_input handle_message(xmlNode *msg,
  25                                           enum crmd_fsa_cause cause);
  26 static void handle_response(xmlNode *stored_msg);
  27 static enum crmd_fsa_input handle_request(xmlNode *stored_msg,
  28                                           enum crmd_fsa_cause cause);
  29 static enum crmd_fsa_input handle_shutdown_request(xmlNode *stored_msg);
  30 static void send_msg_via_ipc(xmlNode * msg, const char *sys);
  31 
  32 /* debug only, can wrap all it likes */
  33 static int last_data_id = 0;
  34 
  35 void
  36 register_fsa_error_adv(enum crmd_fsa_cause cause, enum crmd_fsa_input input,
     /* [previous][next][first][last][top][bottom][index][help] */
  37                        fsa_data_t * cur_data, void *new_data, const char *raised_from)
  38 {
  39     /* save the current actions if any */
  40     if (controld_globals.fsa_actions != A_NOTHING) {
  41         register_fsa_input_adv(cur_data ? cur_data->fsa_cause : C_FSA_INTERNAL,
  42                                I_NULL, cur_data ? cur_data->data : NULL,
  43                                controld_globals.fsa_actions, TRUE, __func__);
  44     }
  45 
  46     /* reset the action list */
  47     crm_info("Resetting the current action list");
  48     fsa_dump_actions(controld_globals.fsa_actions, "Drop");
  49     controld_globals.fsa_actions = A_NOTHING;
  50 
  51     /* register the error */
  52     register_fsa_input_adv(cause, input, new_data, A_NOTHING, TRUE, raised_from);
  53 }
  54 
  55 void
  56 register_fsa_input_adv(enum crmd_fsa_cause cause, enum crmd_fsa_input input,
     /* [previous][next][first][last][top][bottom][index][help] */
  57                        void *data, uint64_t with_actions,
  58                        gboolean prepend, const char *raised_from)
  59 {
  60     unsigned old_len = g_list_length(controld_globals.fsa_message_queue);
  61     fsa_data_t *fsa_data = NULL;
  62 
  63     if (raised_from == NULL) {
  64         raised_from = "<unknown>";
  65     }
  66 
  67     if (input == I_NULL && with_actions == A_NOTHING /* && data == NULL */ ) {
  68         /* no point doing anything */
  69         crm_err("Cannot add entry to queue: no input and no action");
  70         return;
  71     }
  72 
  73     if (input == I_WAIT_FOR_EVENT) {
  74         controld_set_global_flags(controld_fsa_is_stalled);
  75         crm_debug("Stalling the FSA pending further input: source=%s cause=%s data=%p queue=%d",
  76                   raised_from, fsa_cause2string(cause), data, old_len);
  77 
  78         if (old_len > 0) {
  79             fsa_dump_queue(LOG_TRACE);
  80             prepend = FALSE;
  81         }
  82 
  83         if (data == NULL) {
  84             controld_set_fsa_action_flags(with_actions);
  85             fsa_dump_actions(with_actions, "Restored");
  86             return;
  87         }
  88 
  89         /* Store everything in the new event and reset
  90          * controld_globals.fsa_actions
  91          */
  92         with_actions |= controld_globals.fsa_actions;
  93         controld_globals.fsa_actions = A_NOTHING;
  94     }
  95 
  96     last_data_id++;
  97     crm_trace("%s %s FSA input %d (%s) due to %s, %s data",
  98               raised_from, (prepend? "prepended" : "appended"), last_data_id,
  99               fsa_input2string(input), fsa_cause2string(cause),
 100               (data? "with" : "without"));
 101 
 102     fsa_data = pcmk__assert_alloc(1, sizeof(fsa_data_t));
 103     fsa_data->id = last_data_id;
 104     fsa_data->fsa_input = input;
 105     fsa_data->fsa_cause = cause;
 106     fsa_data->origin = raised_from;
 107     fsa_data->data = NULL;
 108     fsa_data->data_type = fsa_dt_none;
 109     fsa_data->actions = with_actions;
 110 
 111     if (with_actions != A_NOTHING) {
 112         crm_trace("Adding actions %.16llx to input",
 113                   (unsigned long long) with_actions);
 114     }
 115 
 116     if (data != NULL) {
 117         switch (cause) {
 118             case C_FSA_INTERNAL:
 119             case C_CRMD_STATUS_CALLBACK:
 120             case C_IPC_MESSAGE:
 121             case C_HA_MESSAGE:
 122                 CRM_CHECK(((ha_msg_input_t *) data)->msg != NULL,
 123                           crm_err("Bogus data from %s", raised_from));
 124                 crm_trace("Copying %s data from %s as cluster message data",
 125                           fsa_cause2string(cause), raised_from);
 126                 fsa_data->data = copy_ha_msg_input(data);
 127                 fsa_data->data_type = fsa_dt_ha_msg;
 128                 break;
 129 
 130             case C_LRM_OP_CALLBACK:
 131                 crm_trace("Copying %s data from %s as lrmd_event_data_t",
 132                           fsa_cause2string(cause), raised_from);
 133                 fsa_data->data = lrmd_copy_event((lrmd_event_data_t *) data);
 134                 fsa_data->data_type = fsa_dt_lrm;
 135                 break;
 136 
 137             case C_TIMER_POPPED:
 138             case C_SHUTDOWN:
 139             case C_UNKNOWN:
 140             case C_STARTUP:
 141                 crm_crit("Copying %s data (from %s) is not yet implemented",
 142                          fsa_cause2string(cause), raised_from);
 143                 crmd_exit(CRM_EX_SOFTWARE);
 144                 break;
 145         }
 146     }
 147 
 148     /* make sure to free it properly later */
 149     if (prepend) {
 150         controld_globals.fsa_message_queue
 151             = g_list_prepend(controld_globals.fsa_message_queue, fsa_data);
 152     } else {
 153         controld_globals.fsa_message_queue
 154             = g_list_append(controld_globals.fsa_message_queue, fsa_data);
 155     }
 156 
 157     crm_trace("FSA message queue length is %d",
 158               g_list_length(controld_globals.fsa_message_queue));
 159 
 160     /* fsa_dump_queue(LOG_TRACE); */
 161 
 162     if (old_len == g_list_length(controld_globals.fsa_message_queue)) {
 163         crm_err("Couldn't add message to the queue");
 164     }
 165 
 166     if (input != I_WAIT_FOR_EVENT) {
 167         controld_trigger_fsa();
 168     }
 169 }
 170 
 171 void
 172 fsa_dump_queue(int log_level)
     /* [previous][next][first][last][top][bottom][index][help] */
 173 {
 174     int offset = 0;
 175 
 176     for (GList *iter = controld_globals.fsa_message_queue; iter != NULL;
 177          iter = iter->next) {
 178         fsa_data_t *data = (fsa_data_t *) iter->data;
 179 
 180         do_crm_log_unlikely(log_level,
 181                             "queue[%d.%d]: input %s raised by %s(%p.%d)\t(cause=%s)",
 182                             offset++, data->id, fsa_input2string(data->fsa_input),
 183                             data->origin, data->data, data->data_type,
 184                             fsa_cause2string(data->fsa_cause));
 185     }
 186 }
 187 
 188 ha_msg_input_t *
 189 copy_ha_msg_input(ha_msg_input_t * orig)
     /* [previous][next][first][last][top][bottom][index][help] */
 190 {
 191     xmlNode *wrapper = NULL;
 192 
 193     ha_msg_input_t *copy = pcmk__assert_alloc(1, sizeof(ha_msg_input_t));
 194 
 195     copy->msg = (orig != NULL)? pcmk__xml_copy(NULL, orig->msg) : NULL;
 196 
 197     wrapper = pcmk__xe_first_child(copy->msg, PCMK__XE_CRM_XML, NULL, NULL);
 198     copy->xml = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
 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_none;
 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, PCMK__XA_CRM_HOST_TO);
 350     sys_to = crm_element_value(msg, PCMK__XA_CRM_SYS_TO);
 351     sys_from = crm_element_value(msg, PCMK__XA_CRM_SYS_FROM);
 352     type = crm_element_value(msg, PCMK__XA_T);
 353     task = crm_element_value(msg, PCMK__XA_CRM_TASK);
 354     ref = crm_element_value(msg, PCMK_XA_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, PCMK__VALUE_CRMD, pcmk__str_none)) {
 371         crm_warn("Ignoring invalid message %s with type '%s' "
 372                  "(not '" PCMK__VALUE_CRMD "')",
 373                  ref, pcmk__s(type, ""));
 374         crm_log_xml_trace(msg, "ignored");
 375         return TRUE;
 376     }
 377 
 378     // Require a destination subsystem (also set by create_request())
 379     if (sys_to == NULL) {
 380         crm_warn("Ignoring invalid message %s with no " PCMK__XA_CRM_SYS_TO,
 381                  ref);
 382         crm_log_xml_trace(msg, "ignored");
 383         return TRUE;
 384     }
 385 
 386     // Get the message type appropriate to the destination subsystem
 387     if (pcmk_get_cluster_layer() == pcmk_cluster_layer_corosync) {
 388         dest = pcmk__cluster_parse_msg_type(sys_to);
 389         if (dest == crm_msg_none) {
 390             /* Unrecognized value, use a sane default
 391              *
 392              * @TODO Maybe we should bail instead
 393              */
 394             dest = crm_msg_crmd;
 395         }
 396     }
 397 
 398     is_for_dc = (strcasecmp(CRM_SYSTEM_DC, sys_to) == 0);
 399     is_for_dcib = (strcasecmp(CRM_SYSTEM_DCIB, sys_to) == 0);
 400     is_for_te = (strcasecmp(CRM_SYSTEM_TENGINE, sys_to) == 0);
 401     is_for_cib = (strcasecmp(CRM_SYSTEM_CIB, sys_to) == 0);
 402     is_for_crm = (strcasecmp(CRM_SYSTEM_CRMD, sys_to) == 0);
 403 
 404     // Check whether message should be processed locally
 405     is_local = false;
 406     if (broadcast) {
 407         if (is_for_dc || is_for_te) {
 408             is_local = false;
 409 
 410         } else if (is_for_crm) {
 411             if (pcmk__strcase_any_of(task, CRM_OP_NODE_INFO,
 412                                      PCMK__CONTROLD_CMD_NODES, NULL)) {
 413                 /* Node info requests do not specify a host, which is normally
 414                  * treated as "all hosts", because the whole point is that the
 415                  * client may not know the local node name. Always handle these
 416                  * requests locally.
 417                  */
 418                 is_local = true;
 419             } else {
 420                 is_local = !originated_locally;
 421             }
 422 
 423         } else {
 424             is_local = true;
 425         }
 426 
 427     } else if (pcmk__str_eq(controld_globals.our_nodename, host_to,
 428                             pcmk__str_casei)) {
 429         is_local = true;
 430 
 431     } else if (is_for_crm && pcmk__str_eq(task, CRM_OP_LRM_DELETE, pcmk__str_casei)) {
 432         xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_CRM_XML, NULL,
 433                                                 NULL);
 434         xmlNode *msg_data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
 435         const char *mode = crm_element_value(msg_data, PCMK__XA_MODE);
 436 
 437         if (pcmk__str_eq(mode, PCMK__VALUE_CIB, pcmk__str_none)) {
 438             // Local delete of an offline node's resource history
 439             is_local = true;
 440         }
 441     }
 442 
 443     // Check whether message should be relayed
 444 
 445     if (is_for_dc || is_for_dcib || is_for_te) {
 446         if (AM_I_DC) {
 447             if (is_for_te) {
 448                 crm_trace("Route message %s locally as transition request",
 449                           ref);
 450                 crm_log_xml_trace(msg, sys_to);
 451                 send_msg_via_ipc(msg, sys_to);
 452                 return TRUE; // No further processing of message is needed
 453             }
 454             crm_trace("Route message %s locally as DC request", ref);
 455             return FALSE; // More to be done by caller
 456         }
 457 
 458         if (originated_locally
 459             && !pcmk__strcase_any_of(sys_from, CRM_SYSTEM_PENGINE,
 460                                      CRM_SYSTEM_TENGINE, NULL)) {
 461             crm_trace("Relay message %s to DC (via %s)",
 462                       ref, pcmk__s(host_to, "broadcast"));
 463             crm_log_xml_trace(msg, "relayed");
 464             if (!broadcast) {
 465                 node_to = pcmk__get_node(0, host_to, NULL,
 466                                          pcmk__node_search_cluster_member);
 467             }
 468             pcmk__cluster_send_message(node_to, dest, msg);
 469             return TRUE;
 470         }
 471 
 472         /* Transition engine and scheduler messages are sent only to the DC on
 473          * the same node. If we are no longer the DC, discard this message.
 474          */
 475         crm_trace("Ignoring message %s because we are no longer DC", ref);
 476         crm_log_xml_trace(msg, "ignored");
 477         return TRUE; // No further processing of message is needed
 478     }
 479 
 480     if (is_local) {
 481         if (is_for_crm || is_for_cib) {
 482             crm_trace("Route message %s locally as controller request", ref);
 483             return FALSE; // More to be done by caller
 484         }
 485         crm_trace("Relay message %s locally to %s", ref, sys_to);
 486         crm_log_xml_trace(msg, "IPC-relay");
 487         send_msg_via_ipc(msg, sys_to);
 488         return TRUE;
 489     }
 490 
 491     if (!broadcast) {
 492         node_to = pcmk__search_node_caches(0, host_to,
 493                                            pcmk__node_search_cluster_member);
 494         if (node_to == NULL) {
 495             crm_warn("Ignoring message %s because node %s is unknown",
 496                      ref, host_to);
 497             crm_log_xml_trace(msg, "ignored");
 498             return TRUE;
 499         }
 500     }
 501 
 502     crm_trace("Relay message %s to %s",
 503               ref, pcmk__s(host_to, "all peers"));
 504     crm_log_xml_trace(msg, "relayed");
 505     pcmk__cluster_send_message(node_to, dest, msg);
 506     return TRUE;
 507 }
 508 
 509 // Return true if field contains a positive integer
 510 static bool
 511 authorize_version(xmlNode *message_data, const char *field,
     /* [previous][next][first][last][top][bottom][index][help] */
 512                   const char *client_name, const char *ref, const char *uuid)
 513 {
 514     const char *version = crm_element_value(message_data, field);
 515     long long version_num;
 516 
 517     if ((pcmk__scan_ll(version, &version_num, -1LL) != pcmk_rc_ok)
 518         || (version_num < 0LL)) {
 519 
 520         crm_warn("Rejected IPC hello from %s: '%s' is not a valid protocol %s "
 521                  CRM_XS " ref=%s uuid=%s",
 522                  client_name, ((version == NULL)? "" : version),
 523                  field, (ref? ref : "none"), uuid);
 524         return false;
 525     }
 526     return true;
 527 }
 528 
 529 /*!
 530  * \internal
 531  * \brief Check whether a client IPC message is acceptable
 532  *
 533  * If a given client IPC message is a hello, "authorize" it by ensuring it has
 534  * valid information such as a protocol version, and return false indicating
 535  * that nothing further needs to be done with the message. If the message is not
 536  * a hello, just return true to indicate it needs further processing.
 537  *
 538  * \param[in]     client_msg     XML of IPC message
 539  * \param[in,out] curr_client    If IPC is not proxied, client that sent message
 540  * \param[in]     proxy_session  If IPC is proxied, the session ID
 541  *
 542  * \return true if message needs further processing, false if it doesn't
 543  */
 544 bool
 545 controld_authorize_ipc_message(const xmlNode *client_msg, pcmk__client_t *curr_client,
     /* [previous][next][first][last][top][bottom][index][help] */
 546                                const char *proxy_session)
 547 {
 548     xmlNode *wrapper = NULL;
 549     xmlNode *message_data = NULL;
 550     const char *client_name = NULL;
 551     const char *op = crm_element_value(client_msg, PCMK__XA_CRM_TASK);
 552     const char *ref = crm_element_value(client_msg, PCMK_XA_REFERENCE);
 553     const char *uuid = (curr_client? curr_client->id : proxy_session);
 554 
 555     if (uuid == NULL) {
 556         crm_warn("IPC message from client rejected: No client identifier "
 557                  CRM_XS " ref=%s", (ref? ref : "none"));
 558         goto rejected;
 559     }
 560 
 561     if (!pcmk__str_eq(CRM_OP_HELLO, op, pcmk__str_casei)) {
 562         // Only hello messages need to be authorized
 563         return true;
 564     }
 565 
 566     wrapper = pcmk__xe_first_child(client_msg, PCMK__XE_CRM_XML, NULL, NULL);
 567     message_data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
 568 
 569     client_name = crm_element_value(message_data, PCMK__XA_CLIENT_NAME);
 570     if (pcmk__str_empty(client_name)) {
 571         crm_warn("IPC hello from client rejected: No client name",
 572                  CRM_XS " ref=%s uuid=%s", (ref? ref : "none"), uuid);
 573         goto rejected;
 574     }
 575     if (!authorize_version(message_data, PCMK__XA_MAJOR_VERSION, client_name,
 576                            ref, uuid)) {
 577         goto rejected;
 578     }
 579     if (!authorize_version(message_data, PCMK__XA_MINOR_VERSION, client_name,
 580                            ref, uuid)) {
 581         goto rejected;
 582     }
 583 
 584     crm_trace("Validated IPC hello from client %s", client_name);
 585     crm_log_xml_trace(client_msg, "hello");
 586     if (curr_client) {
 587         curr_client->userdata = pcmk__str_copy(client_name);
 588     }
 589     controld_trigger_fsa();
 590     return false;
 591 
 592 rejected:
 593     crm_log_xml_trace(client_msg, "rejected");
 594     if (curr_client) {
 595         qb_ipcs_disconnect(curr_client->ipcs);
 596     }
 597     return false;
 598 }
 599 
 600 static enum crmd_fsa_input
 601 handle_message(xmlNode *msg, enum crmd_fsa_cause cause)
     /* [previous][next][first][last][top][bottom][index][help] */
 602 {
 603     const char *type = NULL;
 604 
 605     CRM_CHECK(msg != NULL, return I_NULL);
 606 
 607     type = crm_element_value(msg, PCMK__XA_SUBT);
 608     if (pcmk__str_eq(type, PCMK__VALUE_REQUEST, pcmk__str_none)) {
 609         return handle_request(msg, cause);
 610     }
 611 
 612     if (pcmk__str_eq(type, PCMK__VALUE_RESPONSE, pcmk__str_none)) {
 613         handle_response(msg);
 614         return I_NULL;
 615     }
 616 
 617     crm_warn("Ignoring message with unknown " PCMK__XA_SUBT" '%s'",
 618              pcmk__s(type, ""));
 619     crm_log_xml_trace(msg, "bad");
 620     return I_NULL;
 621 }
 622 
 623 static enum crmd_fsa_input
 624 handle_failcount_op(xmlNode * stored_msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 625 {
 626     const char *rsc = NULL;
 627     const char *uname = NULL;
 628     const char *op = NULL;
 629     char *interval_spec = NULL;
 630     guint interval_ms = 0;
 631     gboolean is_remote_node = FALSE;
 632 
 633     xmlNode *wrapper = pcmk__xe_first_child(stored_msg, PCMK__XE_CRM_XML, NULL,
 634                                             NULL);
 635     xmlNode *xml_op = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
 636 
 637     if (xml_op) {
 638         xmlNode *xml_rsc = pcmk__xe_first_child(xml_op, PCMK_XE_PRIMITIVE, NULL,
 639                                                 NULL);
 640         xmlNode *xml_attrs = pcmk__xe_first_child(xml_op, PCMK__XE_ATTRIBUTES,
 641                                                   NULL, NULL);
 642 
 643         if (xml_rsc) {
 644             rsc = pcmk__xe_id(xml_rsc);
 645         }
 646         if (xml_attrs) {
 647             op = crm_element_value(xml_attrs,
 648                                    CRM_META "_" PCMK__META_CLEAR_FAILURE_OP);
 649             crm_element_value_ms(xml_attrs,
 650                                  CRM_META "_" PCMK__META_CLEAR_FAILURE_INTERVAL,
 651                                  &interval_ms);
 652         }
 653     }
 654     uname = crm_element_value(xml_op, PCMK__META_ON_NODE);
 655 
 656     if ((rsc == NULL) || (uname == NULL)) {
 657         crm_log_xml_warn(stored_msg, "invalid failcount op");
 658         return I_NULL;
 659     }
 660 
 661     if (crm_element_value(xml_op, PCMK__XA_ROUTER_NODE)) {
 662         is_remote_node = TRUE;
 663     }
 664 
 665     crm_debug("Clearing failures for %s-interval %s on %s "
 666               "from attribute manager, CIB, and executor state",
 667               pcmk__readable_interval(interval_ms), rsc, uname);
 668 
 669     if (interval_ms) {
 670         interval_spec = crm_strdup_printf("%ums", interval_ms);
 671     }
 672     update_attrd_clear_failures(uname, rsc, op, interval_spec, is_remote_node);
 673     free(interval_spec);
 674 
 675     controld_cib_delete_last_failure(rsc, uname, op, interval_ms);
 676 
 677     lrm_clear_last_failure(rsc, uname, op, interval_ms);
 678 
 679     return I_NULL;
 680 }
 681 
 682 static enum crmd_fsa_input
 683 handle_lrm_delete(xmlNode *stored_msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 684 {
 685     const char *mode = NULL;
 686     xmlNode *wrapper = pcmk__xe_first_child(stored_msg, PCMK__XE_CRM_XML, NULL,
 687                                             NULL);
 688     xmlNode *msg_data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
 689 
 690     CRM_CHECK(msg_data != NULL, return I_NULL);
 691 
 692     /* CRM_OP_LRM_DELETE has two distinct modes. The default behavior is to
 693      * relay the operation to the affected node, which will unregister the
 694      * resource from the local executor, clear the resource's history from the
 695      * CIB, and do some bookkeeping in the controller.
 696      *
 697      * However, if the affected node is offline, the client will specify
 698      * mode=PCMK__VALUE_CIB which means the controller receiving the operation
 699      * should clear the resource's history from the CIB and nothing else. This
 700      * is used to clear shutdown locks.
 701      */
 702     mode = crm_element_value(msg_data, PCMK__XA_MODE);
 703     if (!pcmk__str_eq(mode, PCMK__VALUE_CIB, pcmk__str_none)) {
 704         // Relay to affected node
 705         crm_xml_add(stored_msg, PCMK__XA_CRM_SYS_TO, CRM_SYSTEM_LRMD);
 706         return I_ROUTER;
 707 
 708     } else {
 709         // Delete CIB history locally (compare with do_lrm_delete())
 710         const char *from_sys = NULL;
 711         const char *user_name = NULL;
 712         const char *rsc_id = NULL;
 713         const char *node = NULL;
 714         xmlNode *rsc_xml = NULL;
 715         int rc = pcmk_rc_ok;
 716 
 717         rsc_xml = pcmk__xe_first_child(msg_data, PCMK_XE_PRIMITIVE, NULL, NULL);
 718         CRM_CHECK(rsc_xml != NULL, return I_NULL);
 719 
 720         rsc_id = pcmk__xe_id(rsc_xml);
 721         from_sys = crm_element_value(stored_msg, PCMK__XA_CRM_SYS_FROM);
 722         node = crm_element_value(msg_data, PCMK__META_ON_NODE);
 723         user_name = pcmk__update_acl_user(stored_msg, PCMK__XA_CRM_USER, NULL);
 724         crm_debug("Handling " CRM_OP_LRM_DELETE " for %s on %s locally%s%s "
 725                   "(clearing CIB resource history only)", rsc_id, node,
 726                   (user_name? " for user " : ""), (user_name? user_name : ""));
 727         rc = controld_delete_resource_history(rsc_id, node, user_name,
 728                                               cib_dryrun|cib_sync_call);
 729         if (rc == pcmk_rc_ok) {
 730             rc = controld_delete_resource_history(rsc_id, node, user_name,
 731                                                   crmd_cib_smart_opt());
 732         }
 733 
 734         /* Notify client. Also notify tengine if mode=PCMK__VALUE_CIB and
 735          * op=CRM_OP_LRM_DELETE.
 736          */
 737         if (from_sys) {
 738             lrmd_event_data_t *op = NULL;
 739             const char *from_host = crm_element_value(stored_msg, PCMK__XA_SRC);
 740             const char *transition;
 741 
 742             if (strcmp(from_sys, CRM_SYSTEM_TENGINE)) {
 743                 transition = crm_element_value(msg_data,
 744                                                PCMK__XA_TRANSITION_KEY);
 745             } else {
 746                 transition = crm_element_value(stored_msg,
 747                                                PCMK__XA_TRANSITION_KEY);
 748             }
 749 
 750             crm_info("Notifying %s on %s that %s was%s deleted",
 751                      from_sys, (from_host? from_host : "local node"), rsc_id,
 752                      ((rc == pcmk_rc_ok)? "" : " not"));
 753             op = lrmd_new_event(rsc_id, PCMK_ACTION_DELETE, 0);
 754             op->type = lrmd_event_exec_complete;
 755             op->user_data = pcmk__str_copy(pcmk__s(transition, FAKE_TE_ID));
 756             op->params = pcmk__strkey_table(free, free);
 757             pcmk__insert_dup(op->params, PCMK_XA_CRM_FEATURE_SET,
 758                              CRM_FEATURE_SET);
 759             controld_rc2event(op, rc);
 760             controld_ack_event_directly(from_host, from_sys, NULL, op, rsc_id);
 761             lrmd_free_event(op);
 762             controld_trigger_delete_refresh(from_sys, rsc_id);
 763         }
 764         return I_NULL;
 765     }
 766 }
 767 
 768 /*!
 769  * \brief Handle a CRM_OP_REMOTE_STATE message by updating remote peer cache
 770  *
 771  * \param[in] msg  Message XML
 772  *
 773  * \return Next FSA input
 774  */
 775 static enum crmd_fsa_input
 776 handle_remote_state(const xmlNode *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 777 {
 778     const char *conn_host = NULL;
 779     const char *remote_uname = pcmk__xe_id(msg);
 780     crm_node_t *remote_peer;
 781     bool remote_is_up = false;
 782     int rc = pcmk_rc_ok;
 783 
 784     rc = pcmk__xe_get_bool_attr(msg, PCMK__XA_IN_CCM, &remote_is_up);
 785 
 786     CRM_CHECK(remote_uname && rc == pcmk_rc_ok, return I_NULL);
 787 
 788     remote_peer = pcmk__cluster_lookup_remote_node(remote_uname);
 789     CRM_CHECK(remote_peer, return I_NULL);
 790 
 791     pcmk__update_peer_state(__func__, remote_peer,
 792                             remote_is_up ? CRM_NODE_MEMBER : CRM_NODE_LOST,
 793                             0);
 794 
 795     conn_host = crm_element_value(msg, PCMK__XA_CONNECTION_HOST);
 796     if (conn_host) {
 797         pcmk__str_update(&remote_peer->conn_host, conn_host);
 798     } else if (remote_peer->conn_host) {
 799         free(remote_peer->conn_host);
 800         remote_peer->conn_host = NULL;
 801     }
 802 
 803     return I_NULL;
 804 }
 805 
 806 /*!
 807  * \brief Handle a CRM_OP_PING message
 808  *
 809  * \param[in] msg  Message XML
 810  *
 811  * \return Next FSA input
 812  */
 813 static enum crmd_fsa_input
 814 handle_ping(const xmlNode *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 815 {
 816     const char *value = NULL;
 817     xmlNode *ping = NULL;
 818     xmlNode *reply = NULL;
 819 
 820     // Build reply
 821 
 822     ping = pcmk__xe_create(NULL, PCMK__XE_PING_RESPONSE);
 823     value = crm_element_value(msg, PCMK__XA_CRM_SYS_TO);
 824     crm_xml_add(ping, PCMK__XA_CRM_SUBSYSTEM, value);
 825 
 826     // Add controller state
 827     value = fsa_state2string(controld_globals.fsa_state);
 828     crm_xml_add(ping, PCMK__XA_CRMD_STATE, value);
 829     crm_notice("Current ping state: %s", value); // CTS needs this
 830 
 831     // Add controller health
 832     // @TODO maybe do some checks to determine meaningful status
 833     crm_xml_add(ping, PCMK_XA_RESULT, "ok");
 834 
 835     // Send reply
 836     reply = create_reply(msg, ping);
 837     free_xml(ping);
 838     if (reply != NULL) {
 839         (void) relay_message(reply, TRUE);
 840         free_xml(reply);
 841     }
 842 
 843     // Nothing further to do
 844     return I_NULL;
 845 }
 846 
 847 /*!
 848  * \brief Handle a PCMK__CONTROLD_CMD_NODES message
 849  *
 850  * \param[in] request  Message XML
 851  *
 852  * \return Next FSA input
 853  */
 854 static enum crmd_fsa_input
 855 handle_node_list(const xmlNode *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 856 {
 857     GHashTableIter iter;
 858     crm_node_t *node = NULL;
 859     xmlNode *reply = NULL;
 860     xmlNode *reply_data = NULL;
 861 
 862     // Create message data for reply
 863     reply_data = pcmk__xe_create(NULL, PCMK_XE_NODES);
 864     g_hash_table_iter_init(&iter, crm_peer_cache);
 865     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) {
 866         xmlNode *xml = pcmk__xe_create(reply_data, PCMK_XE_NODE);
 867 
 868         crm_xml_add_ll(xml, PCMK_XA_ID, (long long) node->id); // uint32_t
 869         crm_xml_add(xml, PCMK_XA_UNAME, node->uname);
 870         crm_xml_add(xml, PCMK__XA_IN_CCM, node->state);
 871     }
 872 
 873     // Create and send reply
 874     reply = create_reply(request, reply_data);
 875     free_xml(reply_data);
 876     if (reply) {
 877         (void) relay_message(reply, TRUE);
 878         free_xml(reply);
 879     }
 880 
 881     // Nothing further to do
 882     return I_NULL;
 883 }
 884 
 885 /*!
 886  * \brief Handle a CRM_OP_NODE_INFO request
 887  *
 888  * \param[in] msg  Message XML
 889  *
 890  * \return Next FSA input
 891  */
 892 static enum crmd_fsa_input
 893 handle_node_info_request(const xmlNode *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 894 {
 895     const char *value = NULL;
 896     crm_node_t *node = NULL;
 897     int node_id = 0;
 898     xmlNode *reply = NULL;
 899     xmlNode *reply_data = NULL;
 900 
 901     // Build reply
 902 
 903     reply_data = pcmk__xe_create(NULL, PCMK_XE_NODE);
 904     crm_xml_add(reply_data, PCMK__XA_CRM_SUBSYSTEM, CRM_SYSTEM_CRMD);
 905 
 906     // Add whether current partition has quorum
 907     pcmk__xe_set_bool_attr(reply_data, PCMK_XA_HAVE_QUORUM,
 908                            pcmk_is_set(controld_globals.flags,
 909                                        controld_has_quorum));
 910 
 911     /* Check whether client requested node info by ID and/or name
 912      *
 913      * @TODO A Corosync-layer node ID is of type uint32_t. We should be able to
 914      * handle legitimate node IDs greater than INT_MAX, but currently we do not.
 915      */
 916     crm_element_value_int(msg, PCMK_XA_ID, &node_id);
 917     if (node_id < 0) {
 918         node_id = 0;
 919     }
 920     value = crm_element_value(msg, PCMK_XA_UNAME);
 921 
 922     // Default to local node if none given
 923     if ((node_id == 0) && (value == NULL)) {
 924         value = controld_globals.our_nodename;
 925     }
 926 
 927     node = pcmk__search_node_caches(node_id, value, pcmk__node_search_any);
 928     if (node) {
 929         crm_xml_add(reply_data, PCMK_XA_ID, node->uuid);
 930         crm_xml_add(reply_data, PCMK_XA_UNAME, node->uname);
 931         crm_xml_add(reply_data, PCMK_XA_CRMD, node->state);
 932         pcmk__xe_set_bool_attr(reply_data, PCMK_XA_REMOTE_NODE,
 933                                pcmk_is_set(node->flags, crm_remote_node));
 934     }
 935 
 936     // Send reply
 937     reply = create_reply(msg, reply_data);
 938     free_xml(reply_data);
 939     if (reply != NULL) {
 940         (void) relay_message(reply, TRUE);
 941         free_xml(reply);
 942     }
 943 
 944     // Nothing further to do
 945     return I_NULL;
 946 }
 947 
 948 static void
 949 verify_feature_set(xmlNode *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 950 {
 951     const char *dc_version = crm_element_value(msg, PCMK_XA_CRM_FEATURE_SET);
 952 
 953     if (dc_version == NULL) {
 954         /* All we really know is that the DC feature set is older than 3.1.0,
 955          * but that's also all that really matters.
 956          */
 957         dc_version = "3.0.14";
 958     }
 959 
 960     if (feature_set_compatible(dc_version, CRM_FEATURE_SET)) {
 961         crm_trace("Local feature set (%s) is compatible with DC's (%s)",
 962                   CRM_FEATURE_SET, dc_version);
 963     } else {
 964         crm_err("Local feature set (%s) is incompatible with DC's (%s)",
 965                 CRM_FEATURE_SET, dc_version);
 966 
 967         // Nothing is likely to improve without administrator involvement
 968         controld_set_fsa_input_flags(R_STAYDOWN);
 969         crmd_exit(CRM_EX_FATAL);
 970     }
 971 }
 972 
 973 // DC gets own shutdown all-clear
 974 static enum crmd_fsa_input
 975 handle_shutdown_self_ack(xmlNode *stored_msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 976 {
 977     const char *host_from = crm_element_value(stored_msg, PCMK__XA_SRC);
 978 
 979     if (pcmk_is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
 980         // The expected case -- we initiated own shutdown sequence
 981         crm_info("Shutting down controller");
 982         return I_STOP;
 983     }
 984 
 985     if (pcmk__str_eq(host_from, controld_globals.dc_name, pcmk__str_casei)) {
 986         // Must be logic error -- DC confirming its own unrequested shutdown
 987         crm_err("Shutting down controller immediately due to "
 988                 "unexpected shutdown confirmation");
 989         return I_TERMINATE;
 990     }
 991 
 992     if (controld_globals.fsa_state != S_STOPPING) {
 993         // Shouldn't happen -- non-DC confirming unrequested shutdown
 994         crm_err("Starting new DC election because %s is "
 995                 "confirming shutdown we did not request",
 996                 (host_from? host_from : "another node"));
 997         return I_ELECTION;
 998     }
 999 
1000     // Shouldn't happen, but we are already stopping anyway
1001     crm_debug("Ignoring unexpected shutdown confirmation from %s",
1002               (host_from? host_from : "another node"));
1003     return I_NULL;
1004 }
1005 
1006 // Non-DC gets shutdown all-clear from DC
1007 static enum crmd_fsa_input
1008 handle_shutdown_ack(xmlNode *stored_msg)
     /* [previous][next][first][last][top][bottom][index][help] */
1009 {
1010     const char *host_from = crm_element_value(stored_msg, PCMK__XA_SRC);
1011 
1012     if (host_from == NULL) {
1013         crm_warn("Ignoring shutdown request without origin specified");
1014         return I_NULL;
1015     }
1016 
1017     if (pcmk__str_eq(host_from, controld_globals.dc_name,
1018                      pcmk__str_null_matches|pcmk__str_casei)) {
1019 
1020         if (pcmk_is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
1021             crm_info("Shutting down controller after confirmation from %s",
1022                      host_from);
1023         } else {
1024             crm_err("Shutting down controller after unexpected "
1025                     "shutdown request from %s", host_from);
1026             controld_set_fsa_input_flags(R_STAYDOWN);
1027         }
1028         return I_STOP;
1029     }
1030 
1031     crm_warn("Ignoring shutdown request from %s because DC is %s",
1032              host_from, controld_globals.dc_name);
1033     return I_NULL;
1034 }
1035 
1036 static enum crmd_fsa_input
1037 handle_request(xmlNode *stored_msg, enum crmd_fsa_cause cause)
     /* [previous][next][first][last][top][bottom][index][help] */
1038 {
1039     xmlNode *msg = NULL;
1040     const char *op = crm_element_value(stored_msg, PCMK__XA_CRM_TASK);
1041 
1042     /* Optimize this for the DC - it has the most to do */
1043 
1044     crm_log_xml_trace(stored_msg, "request");
1045     if (op == NULL) {
1046         crm_warn("Ignoring request without " PCMK__XA_CRM_TASK);
1047         return I_NULL;
1048     }
1049 
1050     if (strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) {
1051         const char *from = crm_element_value(stored_msg, PCMK__XA_SRC);
1052         crm_node_t *node =
1053             pcmk__search_node_caches(0, from, pcmk__node_search_cluster_member);
1054 
1055         pcmk__update_peer_expected(__func__, node, CRMD_JOINSTATE_DOWN);
1056         if(AM_I_DC == FALSE) {
1057             return I_NULL; /* Done */
1058         }
1059     }
1060 
1061     /*========== DC-Only Actions ==========*/
1062     if (AM_I_DC) {
1063         if (strcmp(op, CRM_OP_JOIN_ANNOUNCE) == 0) {
1064             return I_NODE_JOIN;
1065 
1066         } else if (strcmp(op, CRM_OP_JOIN_REQUEST) == 0) {
1067             return I_JOIN_REQUEST;
1068 
1069         } else if (strcmp(op, CRM_OP_JOIN_CONFIRM) == 0) {
1070             return I_JOIN_RESULT;
1071 
1072         } else if (strcmp(op, CRM_OP_SHUTDOWN) == 0) {
1073             return handle_shutdown_self_ack(stored_msg);
1074 
1075         } else if (strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0) {
1076             // Another controller wants to shut down its node
1077             return handle_shutdown_request(stored_msg);
1078         }
1079     }
1080 
1081     /*========== common actions ==========*/
1082     if (strcmp(op, CRM_OP_NOVOTE) == 0) {
1083         ha_msg_input_t fsa_input;
1084 
1085         fsa_input.msg = stored_msg;
1086         register_fsa_input_adv(C_HA_MESSAGE, I_NULL, &fsa_input,
1087                                A_ELECTION_COUNT | A_ELECTION_CHECK, FALSE,
1088                                __func__);
1089 
1090     } else if (strcmp(op, CRM_OP_REMOTE_STATE) == 0) {
1091         /* a remote connection host is letting us know the node state */
1092         return handle_remote_state(stored_msg);
1093 
1094     } else if (strcmp(op, CRM_OP_THROTTLE) == 0) {
1095         throttle_update(stored_msg);
1096         if (AM_I_DC && (controld_globals.transition_graph != NULL)
1097             && !controld_globals.transition_graph->complete) {
1098 
1099             crm_debug("The throttle changed. Trigger a graph.");
1100             trigger_graph();
1101         }
1102         return I_NULL;
1103 
1104     } else if (strcmp(op, CRM_OP_CLEAR_FAILCOUNT) == 0) {
1105         return handle_failcount_op(stored_msg);
1106 
1107     } else if (strcmp(op, CRM_OP_VOTE) == 0) {
1108         /* count the vote and decide what to do after that */
1109         ha_msg_input_t fsa_input;
1110 
1111         fsa_input.msg = stored_msg;
1112         register_fsa_input_adv(C_HA_MESSAGE, I_NULL, &fsa_input,
1113                                A_ELECTION_COUNT | A_ELECTION_CHECK, FALSE,
1114                                __func__);
1115 
1116         /* Sometimes we _must_ go into S_ELECTION */
1117         if (controld_globals.fsa_state == S_HALT) {
1118             crm_debug("Forcing an election from S_HALT");
1119             return I_ELECTION;
1120         }
1121 
1122     } else if (strcmp(op, CRM_OP_JOIN_OFFER) == 0) {
1123         verify_feature_set(stored_msg);
1124         crm_debug("Raising I_JOIN_OFFER: join-%s",
1125                   crm_element_value(stored_msg, PCMK__XA_JOIN_ID));
1126         return I_JOIN_OFFER;
1127 
1128     } else if (strcmp(op, CRM_OP_JOIN_ACKNAK) == 0) {
1129         crm_debug("Raising I_JOIN_RESULT: join-%s",
1130                   crm_element_value(stored_msg, PCMK__XA_JOIN_ID));
1131         return I_JOIN_RESULT;
1132 
1133     } else if (strcmp(op, CRM_OP_LRM_DELETE) == 0) {
1134         return handle_lrm_delete(stored_msg);
1135 
1136     } else if ((strcmp(op, CRM_OP_LRM_FAIL) == 0)
1137                || (strcmp(op, CRM_OP_LRM_REFRESH) == 0) // @COMPAT
1138                || (strcmp(op, CRM_OP_REPROBE) == 0)) {
1139 
1140         crm_xml_add(stored_msg, PCMK__XA_CRM_SYS_TO, CRM_SYSTEM_LRMD);
1141         return I_ROUTER;
1142 
1143     } else if (strcmp(op, CRM_OP_NOOP) == 0) {
1144         return I_NULL;
1145 
1146     } else if (strcmp(op, CRM_OP_PING) == 0) {
1147         return handle_ping(stored_msg);
1148 
1149     } else if (strcmp(op, CRM_OP_NODE_INFO) == 0) {
1150         return handle_node_info_request(stored_msg);
1151 
1152     } else if (strcmp(op, CRM_OP_RM_NODE_CACHE) == 0) {
1153         int id = 0;
1154         const char *name = NULL;
1155 
1156         crm_element_value_int(stored_msg, PCMK_XA_ID, &id);
1157         name = crm_element_value(stored_msg, PCMK_XA_UNAME);
1158 
1159         if(cause == C_IPC_MESSAGE) {
1160             msg = create_request(CRM_OP_RM_NODE_CACHE, NULL, NULL, CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL);
1161             if (!pcmk__cluster_send_message(NULL, crm_msg_crmd, msg)) {
1162                 crm_err("Could not instruct peers to remove references to node %s/%u", name, id);
1163             } else {
1164                 crm_notice("Instructing peers to remove references to node %s/%u", name, id);
1165             }
1166             free_xml(msg);
1167 
1168         } else {
1169             pcmk__cluster_forget_cluster_node(id, name);
1170 
1171             /* If we're forgetting this node, also forget any failures to fence
1172              * it, so we don't carry that over to any node added later with the
1173              * same name.
1174              */
1175             st_fail_count_reset(name);
1176         }
1177 
1178     } else if (strcmp(op, CRM_OP_MAINTENANCE_NODES) == 0) {
1179         xmlNode *wrapper = pcmk__xe_first_child(stored_msg, PCMK__XE_CRM_XML,
1180                                                 NULL, NULL);
1181         xmlNode *xml = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
1182 
1183         remote_ra_process_maintenance_nodes(xml);
1184 
1185     } else if (strcmp(op, PCMK__CONTROLD_CMD_NODES) == 0) {
1186         return handle_node_list(stored_msg);
1187 
1188         /*========== (NOT_DC)-Only Actions ==========*/
1189     } else if (!AM_I_DC) {
1190 
1191         if (strcmp(op, CRM_OP_SHUTDOWN) == 0) {
1192             return handle_shutdown_ack(stored_msg);
1193         }
1194 
1195     } else {
1196         crm_err("Unexpected request (%s) sent to %s", op, AM_I_DC ? "the DC" : "non-DC node");
1197         crm_log_xml_err(stored_msg, "Unexpected");
1198     }
1199 
1200     return I_NULL;
1201 }
1202 
1203 static void
1204 handle_response(xmlNode *stored_msg)
     /* [previous][next][first][last][top][bottom][index][help] */
1205 {
1206     const char *op = crm_element_value(stored_msg, PCMK__XA_CRM_TASK);
1207 
1208     crm_log_xml_trace(stored_msg, "reply");
1209     if (op == NULL) {
1210         crm_warn("Ignoring reply without " PCMK__XA_CRM_TASK);
1211 
1212     } else if (AM_I_DC && strcmp(op, CRM_OP_PECALC) == 0) {
1213         // Check whether scheduler answer been superseded by subsequent request
1214         const char *msg_ref = crm_element_value(stored_msg, PCMK_XA_REFERENCE);
1215 
1216         if (msg_ref == NULL) {
1217             crm_err("%s - Ignoring calculation with no reference", op);
1218 
1219         } else if (pcmk__str_eq(msg_ref, controld_globals.fsa_pe_ref,
1220                                 pcmk__str_none)) {
1221             ha_msg_input_t fsa_input;
1222 
1223             controld_stop_sched_timer();
1224             fsa_input.msg = stored_msg;
1225             register_fsa_input_later(C_IPC_MESSAGE, I_PE_SUCCESS, &fsa_input);
1226 
1227         } else {
1228             crm_info("%s calculation %s is obsolete", op, msg_ref);
1229         }
1230 
1231     } else if (strcmp(op, CRM_OP_VOTE) == 0
1232                || strcmp(op, CRM_OP_SHUTDOWN_REQ) == 0 || strcmp(op, CRM_OP_SHUTDOWN) == 0) {
1233 
1234     } else {
1235         const char *host_from = crm_element_value(stored_msg, PCMK__XA_SRC);
1236 
1237         crm_err("Unexpected response (op=%s, src=%s) sent to the %s",
1238                 op, host_from, AM_I_DC ? "DC" : "controller");
1239     }
1240 }
1241 
1242 static enum crmd_fsa_input
1243 handle_shutdown_request(xmlNode * stored_msg)
     /* [previous][next][first][last][top][bottom][index][help] */
1244 {
1245     /* handle here to avoid potential version issues
1246      *   where the shutdown message/procedure may have
1247      *   been changed in later versions.
1248      *
1249      * This way the DC is always in control of the shutdown
1250      */
1251 
1252     char *now_s = NULL;
1253     const char *host_from = crm_element_value(stored_msg, PCMK__XA_SRC);
1254 
1255     if (host_from == NULL) {
1256         /* we're shutting down and the DC */
1257         host_from = controld_globals.our_nodename;
1258     }
1259 
1260     crm_info("Creating shutdown request for %s (state=%s)", host_from,
1261              fsa_state2string(controld_globals.fsa_state));
1262     crm_log_xml_trace(stored_msg, "message");
1263 
1264     now_s = pcmk__ttoa(time(NULL));
1265     update_attrd(host_from, PCMK__NODE_ATTR_SHUTDOWN, now_s, NULL, FALSE);
1266     free(now_s);
1267 
1268     /* will be picked up by the TE as long as its running */
1269     return I_NULL;
1270 }
1271 
1272 static void
1273 send_msg_via_ipc(xmlNode * msg, const char *sys)
     /* [previous][next][first][last][top][bottom][index][help] */
1274 {
1275     pcmk__client_t *client_channel = NULL;
1276 
1277     CRM_CHECK(sys != NULL, return);
1278 
1279     client_channel = pcmk__find_client_by_id(sys);
1280 
1281     if (crm_element_value(msg, PCMK__XA_SRC) == NULL) {
1282         crm_xml_add(msg, PCMK__XA_SRC, controld_globals.our_nodename);
1283     }
1284 
1285     if (client_channel != NULL) {
1286         /* Transient clients such as crmadmin */
1287         pcmk__ipc_send_xml(client_channel, 0, msg, crm_ipc_server_event);
1288 
1289     } else if (pcmk__str_eq(sys, CRM_SYSTEM_TENGINE, pcmk__str_none)) {
1290         xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_CRM_XML, NULL,
1291                                                 NULL);
1292         xmlNode *data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
1293 
1294         process_te_message(msg, data);
1295 
1296     } else if (pcmk__str_eq(sys, CRM_SYSTEM_LRMD, pcmk__str_none)) {
1297         fsa_data_t fsa_data;
1298         ha_msg_input_t fsa_input;
1299         xmlNode *wrapper = NULL;
1300 
1301         fsa_input.msg = msg;
1302 
1303         wrapper = pcmk__xe_first_child(msg, PCMK__XE_CRM_XML, NULL, NULL);
1304         fsa_input.xml = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
1305 
1306         fsa_data.id = 0;
1307         fsa_data.actions = 0;
1308         fsa_data.data = &fsa_input;
1309         fsa_data.fsa_input = I_MESSAGE;
1310         fsa_data.fsa_cause = C_IPC_MESSAGE;
1311         fsa_data.origin = __func__;
1312         fsa_data.data_type = fsa_dt_ha_msg;
1313 
1314         do_lrm_invoke(A_LRM_INVOKE, C_IPC_MESSAGE, controld_globals.fsa_state,
1315                       I_MESSAGE, &fsa_data);
1316 
1317     } else if (crmd_is_proxy_session(sys)) {
1318         crmd_proxy_send(sys, msg);
1319 
1320     } else {
1321         crm_info("Received invalid request: unknown subsystem '%s'", sys);
1322     }
1323 }
1324 
1325 void
1326 delete_ha_msg_input(ha_msg_input_t * orig)
     /* [previous][next][first][last][top][bottom][index][help] */
1327 {
1328     if (orig == NULL) {
1329         return;
1330     }
1331     free_xml(orig->msg);
1332     free(orig);
1333 }
1334 
1335 /*!
1336  * \internal
1337  * \brief Notify the cluster of a remote node state change
1338  *
1339  * \param[in] node_name  Node's name
1340  * \param[in] node_up    true if node is up, false if down
1341  */
1342 void
1343 broadcast_remote_state_message(const char *node_name, bool node_up)
     /* [previous][next][first][last][top][bottom][index][help] */
1344 {
1345     xmlNode *msg = create_request(CRM_OP_REMOTE_STATE, NULL, NULL,
1346                                   CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL);
1347 
1348     crm_info("Notifying cluster of Pacemaker Remote node %s %s",
1349              node_name, node_up? "coming up" : "going down");
1350 
1351     crm_xml_add(msg, PCMK_XA_ID, node_name);
1352     pcmk__xe_set_bool_attr(msg, PCMK__XA_IN_CCM, node_up);
1353 
1354     if (node_up) {
1355         crm_xml_add(msg, PCMK__XA_CONNECTION_HOST,
1356                     controld_globals.our_nodename);
1357     }
1358 
1359     pcmk__cluster_send_message(NULL, crm_msg_crmd, msg);
1360     free_xml(msg);
1361 }
1362 

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