root/daemons/attrd/attrd_messages.c

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

DEFINITIONS

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

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