root/daemons/attrd/attrd_messages.c

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

DEFINITIONS

This source file includes following definitions.
  1. is_sync_point_attr
  2. remove_sync_point_attribute
  3. remove_unsupported_sync_points
  4. handle_unknown_request
  5. handle_clear_failure_request
  6. handle_confirm_request
  7. handle_flush_request
  8. handle_query_request
  9. handle_remove_request
  10. handle_refresh_request
  11. handle_sync_request
  12. handle_sync_response_request
  13. handle_update_request
  14. attrd_register_handlers
  15. attrd_unregister_handlers
  16. attrd_handle_request
  17. attrd_broadcast_protocol
  18. attrd_send_message

   1 /*
   2  * Copyright 2022 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 <glib.h>
  13 
  14 #include <crm/common/messages_internal.h>
  15 #include <crm/msg_xml.h>
  16 
  17 #include "pacemaker-attrd.h"
  18 
  19 int minimum_protocol_version = -1;
  20 
  21 static GHashTable *attrd_handlers = NULL;
  22 
  23 static bool
  24 is_sync_point_attr(xmlAttrPtr attr, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
  25 {
  26     return pcmk__str_eq((const char *) attr->name, PCMK__XA_ATTR_SYNC_POINT, pcmk__str_none);
  27 }
  28 
  29 static int
  30 remove_sync_point_attribute(xmlNode *xml, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
  31 {
  32     pcmk__xe_remove_matching_attrs(xml, is_sync_point_attr, NULL);
  33     pcmk__xe_foreach_child(xml, XML_ATTR_OP, remove_sync_point_attribute, NULL);
  34     return pcmk_rc_ok;
  35 }
  36 
  37 /* Sync points on a multi-update IPC message to an attrd too old to support
  38  * multi-update messages won't work.  Strip the sync point attribute off here
  39  * so we don't pretend to support this situation and instead ACK the client
  40  * immediately.
  41  */
  42 static void
  43 remove_unsupported_sync_points(pcmk__request_t *request)
     /* [previous][next][first][last][top][bottom][index][help] */
  44 {
  45     if (request->xml->children != NULL && !ATTRD_SUPPORTS_MULTI_MESSAGE(minimum_protocol_version) &&
  46         attrd_request_has_sync_point(request->xml)) {
  47         crm_warn("Ignoring sync point in request from %s because not all nodes support it",
  48                  pcmk__request_origin(request));
  49         remove_sync_point_attribute(request->xml, NULL);
  50     }
  51 }
  52 
  53 static xmlNode *
  54 handle_unknown_request(pcmk__request_t *request)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {
  56     crm_err("Unknown IPC request %s from %s %s",
  57             request->op, pcmk__request_origin_type(request),
  58             pcmk__request_origin(request));
  59     pcmk__format_result(&request->result, CRM_EX_PROTOCOL, PCMK_EXEC_INVALID,
  60                         "Unknown request type '%s' (bug?)", request->op);
  61     return NULL;
  62 }
  63 
  64 static xmlNode *
  65 handle_clear_failure_request(pcmk__request_t *request)
     /* [previous][next][first][last][top][bottom][index][help] */
  66 {
  67     if (request->peer != NULL) {
  68         /* It is not currently possible to receive this as a peer command,
  69          * but will be, if we one day enable propagating this operation.
  70          */
  71         attrd_peer_clear_failure(request);
  72         pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
  73         return NULL;
  74     } else {
  75         remove_unsupported_sync_points(request);
  76 
  77         if (attrd_request_has_sync_point(request->xml)) {
  78             /* If this client supplied a sync point it wants to wait for, add it to
  79              * the wait list.  Clients on this list will not receive an ACK until
  80              * their sync point is hit which will result in the client stalled there
  81              * until it receives a response.
  82              *
  83              * All other clients will receive the expected response as normal.
  84              */
  85             attrd_add_client_to_waitlist(request);
  86 
  87         } else {
  88             /* If the client doesn't want to wait for a sync point, go ahead and send
  89              * the ACK immediately.  Otherwise, we'll send the ACK when the appropriate
  90              * sync point is reached.
  91              */
  92             attrd_send_ack(request->ipc_client, request->ipc_id,
  93                            request->ipc_flags);
  94         }
  95 
  96         return attrd_client_clear_failure(request);
  97     }
  98 }
  99 
 100 static xmlNode *
 101 handle_confirm_request(pcmk__request_t *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 102 {
 103     if (request->peer != NULL) {
 104         int callid;
 105 
 106         crm_debug("Received confirmation from %s", request->peer);
 107 
 108         if (crm_element_value_int(request->xml, XML_LRM_ATTR_CALLID, &callid) == -1) {
 109             pcmk__set_result(&request->result, CRM_EX_PROTOCOL, PCMK_EXEC_INVALID,
 110                              "Could not get callid from XML");
 111         } else {
 112             attrd_handle_confirmation(callid, request->peer);
 113         }
 114 
 115         pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
 116         return NULL;
 117     } else {
 118         return handle_unknown_request(request);
 119     }
 120 }
 121 
 122 static xmlNode *
 123 handle_flush_request(pcmk__request_t *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125     if (request->peer != NULL) {
 126         /* Ignore. The flush command was removed in 2.0.0 but may be
 127          * received from peers running older versions.
 128          */
 129         pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
 130         return NULL;
 131     } else {
 132         return handle_unknown_request(request);
 133     }
 134 }
 135 
 136 static xmlNode *
 137 handle_query_request(pcmk__request_t *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 138 {
 139     if (request->peer != NULL) {
 140         return handle_unknown_request(request);
 141     } else {
 142         return attrd_client_query(request);
 143     }
 144 }
 145 
 146 static xmlNode *
 147 handle_remove_request(pcmk__request_t *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 148 {
 149     if (request->peer != NULL) {
 150         const char *host = crm_element_value(request->xml, PCMK__XA_ATTR_NODE_NAME);
 151         attrd_peer_remove(host, true, request->peer);
 152         pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
 153         return NULL;
 154     } else {
 155         return attrd_client_peer_remove(request);
 156     }
 157 }
 158 
 159 static xmlNode *
 160 handle_refresh_request(pcmk__request_t *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 161 {
 162     if (request->peer != NULL) {
 163         return handle_unknown_request(request);
 164     } else {
 165         return attrd_client_refresh(request);
 166     }
 167 }
 168 
 169 static xmlNode *
 170 handle_sync_request(pcmk__request_t *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 171 {
 172     if (request->peer != NULL) {
 173         crm_node_t *peer = crm_get_peer(0, request->peer);
 174 
 175         attrd_peer_sync(peer, request->xml);
 176         pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
 177         return NULL;
 178     } else {
 179         return handle_unknown_request(request);
 180     }
 181 }
 182 
 183 static xmlNode *
 184 handle_sync_response_request(pcmk__request_t *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 185 {
 186     if (request->ipc_client != NULL) {
 187         return handle_unknown_request(request);
 188     } else {
 189         if (request->peer != NULL) {
 190             crm_node_t *peer = crm_get_peer(0, request->peer);
 191             bool peer_won = attrd_check_for_new_writer(peer, request->xml);
 192 
 193             if (!pcmk__str_eq(peer->uname, attrd_cluster->uname, pcmk__str_casei)) {
 194                 attrd_peer_sync_response(peer, peer_won, request->xml);
 195             }
 196         }
 197 
 198         pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
 199         return NULL;
 200     }
 201 }
 202 
 203 static xmlNode *
 204 handle_update_request(pcmk__request_t *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 205 {
 206     if (request->peer != NULL) {
 207         const char *host = crm_element_value(request->xml, PCMK__XA_ATTR_NODE_NAME);
 208         crm_node_t *peer = crm_get_peer(0, request->peer);
 209 
 210         attrd_peer_update(peer, request->xml, host, false);
 211         pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
 212         return NULL;
 213 
 214     } else {
 215         remove_unsupported_sync_points(request);
 216 
 217         if (attrd_request_has_sync_point(request->xml)) {
 218             /* If this client supplied a sync point it wants to wait for, add it to
 219              * the wait list.  Clients on this list will not receive an ACK until
 220              * their sync point is hit which will result in the client stalled there
 221              * until it receives a response.
 222              *
 223              * All other clients will receive the expected response as normal.
 224              */
 225             attrd_add_client_to_waitlist(request);
 226 
 227         } else {
 228             /* If the client doesn't want to wait for a sync point, go ahead and send
 229              * the ACK immediately.  Otherwise, we'll send the ACK when the appropriate
 230              * sync point is reached.
 231              *
 232              * In the normal case, attrd_client_update can be called recursively which
 233              * makes where to send the ACK tricky.  Doing it here ensures the client
 234              * only ever receives one.
 235              */
 236             attrd_send_ack(request->ipc_client, request->ipc_id,
 237                            request->flags|crm_ipc_client_response);
 238         }
 239 
 240         return attrd_client_update(request);
 241     }
 242 }
 243 
 244 static void
 245 attrd_register_handlers(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 246 {
 247     pcmk__server_command_t handlers[] = {
 248         { PCMK__ATTRD_CMD_CLEAR_FAILURE, handle_clear_failure_request },
 249         { PCMK__ATTRD_CMD_CONFIRM, handle_confirm_request },
 250         { PCMK__ATTRD_CMD_FLUSH, handle_flush_request },
 251         { PCMK__ATTRD_CMD_PEER_REMOVE, handle_remove_request },
 252         { PCMK__ATTRD_CMD_QUERY, handle_query_request },
 253         { PCMK__ATTRD_CMD_REFRESH, handle_refresh_request },
 254         { PCMK__ATTRD_CMD_SYNC, handle_sync_request },
 255         { PCMK__ATTRD_CMD_SYNC_RESPONSE, handle_sync_response_request },
 256         { PCMK__ATTRD_CMD_UPDATE, handle_update_request },
 257         { PCMK__ATTRD_CMD_UPDATE_DELAY, handle_update_request },
 258         { PCMK__ATTRD_CMD_UPDATE_BOTH, handle_update_request },
 259         { NULL, handle_unknown_request },
 260     };
 261 
 262     attrd_handlers = pcmk__register_handlers(handlers);
 263 }
 264 
 265 void
 266 attrd_unregister_handlers(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 267 {
 268     if (attrd_handlers != NULL) {
 269         g_hash_table_destroy(attrd_handlers);
 270         attrd_handlers = NULL;
 271     }
 272 }
 273 
 274 void
 275 attrd_handle_request(pcmk__request_t *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 276 {
 277     xmlNode *reply = NULL;
 278     char *log_msg = NULL;
 279     const char *reason = NULL;
 280 
 281     if (attrd_handlers == NULL) {
 282         attrd_register_handlers();
 283     }
 284 
 285     reply = pcmk__process_request(request, attrd_handlers);
 286 
 287     if (reply != NULL) {
 288         crm_log_xml_trace(reply, "Reply");
 289 
 290         if (request->ipc_client != NULL) {
 291             pcmk__ipc_send_xml(request->ipc_client, request->ipc_id, reply,
 292                                request->ipc_flags);
 293         } else {
 294             crm_err("Not sending CPG reply to client");
 295         }
 296 
 297         free_xml(reply);
 298     }
 299 
 300     reason = request->result.exit_reason;
 301     log_msg = crm_strdup_printf("Processed %s request from %s %s: %s%s%s%s",
 302                                 request->op, pcmk__request_origin_type(request),
 303                                 pcmk__request_origin(request),
 304                                 pcmk_exec_status_str(request->result.execution_status),
 305                                 (reason == NULL)? "" : " (",
 306                                 pcmk__s(reason, ""),
 307                                 (reason == NULL)? "" : ")");
 308 
 309     if (!pcmk__result_ok(&request->result)) {
 310         crm_warn("%s", log_msg);
 311     } else {
 312         crm_debug("%s", log_msg);
 313     }
 314 
 315     free(log_msg);
 316     pcmk__reset_request(request);
 317 }
 318 
 319 /*!
 320     \internal
 321     \brief Broadcast private attribute for local node with protocol version
 322 */
 323 void
 324 attrd_broadcast_protocol(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 325 {
 326     xmlNode *attrd_op = create_xml_node(NULL, __func__);
 327 
 328     crm_xml_add(attrd_op, F_TYPE, T_ATTRD);
 329     crm_xml_add(attrd_op, F_ORIG, crm_system_name);
 330     crm_xml_add(attrd_op, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE);
 331     crm_xml_add(attrd_op, PCMK__XA_ATTR_NAME, CRM_ATTR_PROTOCOL);
 332     crm_xml_add(attrd_op, PCMK__XA_ATTR_VALUE, ATTRD_PROTOCOL_VERSION);
 333     crm_xml_add_int(attrd_op, PCMK__XA_ATTR_IS_PRIVATE, 1);
 334     pcmk__xe_add_node(attrd_op, attrd_cluster->uname, attrd_cluster->nodeid);
 335 
 336     crm_debug("Broadcasting attrd protocol version %s for node %s",
 337               ATTRD_PROTOCOL_VERSION, attrd_cluster->uname);
 338 
 339     attrd_send_message(NULL, attrd_op, false); /* ends up at attrd_peer_message() */
 340 
 341     free_xml(attrd_op);
 342 }
 343 
 344 gboolean
 345 attrd_send_message(crm_node_t *node, xmlNode *data, bool confirm)
     /* [previous][next][first][last][top][bottom][index][help] */
 346 {
 347     const char *op = crm_element_value(data, PCMK__XA_TASK);
 348 
 349     crm_xml_add(data, F_TYPE, T_ATTRD);
 350     crm_xml_add(data, PCMK__XA_ATTR_VERSION, ATTRD_PROTOCOL_VERSION);
 351 
 352     /* Request a confirmation from the destination peer node (which could
 353      * be all if node is NULL) that the message has been received and
 354      * acted upon.
 355      */
 356     if (!pcmk__str_eq(op, PCMK__ATTRD_CMD_CONFIRM, pcmk__str_none)) {
 357         pcmk__xe_set_bool_attr(data, PCMK__XA_CONFIRM, confirm);
 358     }
 359 
 360     attrd_xml_add_writer(data);
 361     return send_cluster_message(node, crm_msg_attrd, data, TRUE);
 362 }

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