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_response_request
  12. handle_update_request
  13. attrd_register_handlers
  14. attrd_unregister_handlers
  15. attrd_handle_request
  16. attrd_broadcast_protocol
  17. attrd_send_message

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

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