root/lib/lrmd/proxy_common.c

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

DEFINITIONS

This source file includes following definitions.
  1. remote_proxy_notify_destroy
  2. remote_proxy_ack_shutdown
  3. remote_proxy_nack_shutdown
  4. remote_proxy_relay_event
  5. remote_proxy_relay_response
  6. remote_proxy_end_session
  7. remote_proxy_free
  8. remote_proxy_dispatch
  9. remote_proxy_disconnected
  10. remote_proxy_new
  11. remote_proxy_cb

   1 /*
   2  * Copyright 2015-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 Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <glib.h>
  13 #include <unistd.h>
  14 
  15 #include <crm/crm.h>
  16 #include <crm/common/xml.h>
  17 #include <crm/services.h>
  18 #include <crm/common/mainloop.h>
  19 
  20 #include <crm/pengine/status.h>
  21 #include <crm/cib.h>
  22 #include <crm/lrmd.h>
  23 #include <crm/lrmd_internal.h>
  24 
  25 int lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg);
  26 GHashTable *proxy_table = NULL;
  27 
  28 static void
  29 remote_proxy_notify_destroy(lrmd_t *lrmd, const char *session_id)
     /* [previous][next][first][last][top][bottom][index][help] */
  30 {
  31     /* sending to the remote node that an ipc connection has been destroyed */
  32     xmlNode *msg = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
  33     crm_xml_add(msg, PCMK__XA_LRMD_IPC_OP, LRMD_IPC_OP_DESTROY);
  34     crm_xml_add(msg, PCMK__XA_LRMD_IPC_SESSION, session_id);
  35     lrmd_internal_proxy_send(lrmd, msg);
  36     free_xml(msg);
  37 }
  38 
  39 /*!
  40  * \internal
  41  * \brief Acknowledge a remote proxy shutdown request
  42  *
  43  * \param[in,out] lrmd  Connection to proxy
  44  */
  45 void
  46 remote_proxy_ack_shutdown(lrmd_t *lrmd)
     /* [previous][next][first][last][top][bottom][index][help] */
  47 {
  48     xmlNode *msg = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
  49     crm_xml_add(msg, PCMK__XA_LRMD_IPC_OP, LRMD_IPC_OP_SHUTDOWN_ACK);
  50     lrmd_internal_proxy_send(lrmd, msg);
  51     free_xml(msg);
  52 }
  53 
  54 /*!
  55  * \internal
  56  * \brief Reject a remote proxy shutdown request
  57  *
  58  * \param[in,out] lrmd  Connection to proxy
  59  */
  60 void
  61 remote_proxy_nack_shutdown(lrmd_t *lrmd)
     /* [previous][next][first][last][top][bottom][index][help] */
  62 {
  63     xmlNode *msg = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
  64     crm_xml_add(msg, PCMK__XA_LRMD_IPC_OP, LRMD_IPC_OP_SHUTDOWN_NACK);
  65     lrmd_internal_proxy_send(lrmd, msg);
  66     free_xml(msg);
  67 }
  68 
  69 void
  70 remote_proxy_relay_event(remote_proxy_t *proxy, xmlNode *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
  71 {
  72     /* sending to the remote node an event msg. */
  73     xmlNode *event = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
  74     xmlNode *wrapper = NULL;
  75 
  76     crm_xml_add(event, PCMK__XA_LRMD_IPC_OP, LRMD_IPC_OP_EVENT);
  77     crm_xml_add(event, PCMK__XA_LRMD_IPC_SESSION, proxy->session_id);
  78 
  79     wrapper = pcmk__xe_create(event, PCMK__XE_LRMD_IPC_MSG);
  80     pcmk__xml_copy(wrapper, msg);
  81 
  82     crm_log_xml_explicit(event, "EventForProxy");
  83     lrmd_internal_proxy_send(proxy->lrm, event);
  84     free_xml(event);
  85 }
  86 
  87 void
  88 remote_proxy_relay_response(remote_proxy_t *proxy, xmlNode *msg, int msg_id)
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90     /* sending to the remote node a response msg. */
  91     xmlNode *response = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
  92     xmlNode *wrapper = NULL;
  93 
  94     crm_xml_add(response, PCMK__XA_LRMD_IPC_OP, LRMD_IPC_OP_RESPONSE);
  95     crm_xml_add(response, PCMK__XA_LRMD_IPC_SESSION, proxy->session_id);
  96     crm_xml_add_int(response, PCMK__XA_LRMD_IPC_MSG_ID, msg_id);
  97 
  98     wrapper = pcmk__xe_create(response, PCMK__XE_LRMD_IPC_MSG);
  99     pcmk__xml_copy(wrapper, msg);
 100 
 101     lrmd_internal_proxy_send(proxy->lrm, response);
 102     free_xml(response);
 103 }
 104 
 105 static void
 106 remote_proxy_end_session(remote_proxy_t *proxy)
     /* [previous][next][first][last][top][bottom][index][help] */
 107 {
 108     if (proxy == NULL) {
 109         return;
 110     }
 111     crm_trace("ending session ID %s", proxy->session_id);
 112 
 113     if (proxy->source) {
 114         mainloop_del_ipc_client(proxy->source);
 115     }
 116 }
 117 
 118 void
 119 remote_proxy_free(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 120 {
 121     remote_proxy_t *proxy = data;
 122 
 123     crm_trace("freed proxy session ID %s", proxy->session_id);
 124     free(proxy->node_name);
 125     free(proxy->session_id);
 126     free(proxy);
 127 }
 128 
 129 int
 130 remote_proxy_dispatch(const char *buffer, ssize_t length, gpointer userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
 131 {
 132     // Async responses from cib and friends to clients via pacemaker-remoted
 133     xmlNode *xml = NULL;
 134     uint32_t flags = 0;
 135     remote_proxy_t *proxy = userdata;
 136 
 137     xml = pcmk__xml_parse(buffer);
 138     if (xml == NULL) {
 139         crm_warn("Received a NULL msg from IPC service.");
 140         return 1;
 141     }
 142 
 143     flags = crm_ipc_buffer_flags(proxy->ipc);
 144     if (flags & crm_ipc_proxied_relay_response) {
 145         crm_trace("Passing response back to %.8s on %s: %.200s - request id: %d", proxy->session_id, proxy->node_name, buffer, proxy->last_request_id);
 146         remote_proxy_relay_response(proxy, xml, proxy->last_request_id);
 147         proxy->last_request_id = 0;
 148 
 149     } else {
 150         crm_trace("Passing event back to %.8s on %s: %.200s", proxy->session_id, proxy->node_name, buffer);
 151         remote_proxy_relay_event(proxy, xml);
 152     }
 153     free_xml(xml);
 154     return 1;
 155 }
 156 
 157 
 158 void
 159 remote_proxy_disconnected(gpointer userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
 160 {
 161     remote_proxy_t *proxy = userdata;
 162 
 163     crm_trace("destroying %p", proxy);
 164 
 165     proxy->source = NULL;
 166     proxy->ipc = NULL;
 167 
 168     if(proxy->lrm) {
 169         remote_proxy_notify_destroy(proxy->lrm, proxy->session_id);
 170         proxy->lrm = NULL;
 171     }
 172 
 173     g_hash_table_remove(proxy_table, proxy->session_id);
 174 }
 175 
 176 remote_proxy_t *
 177 remote_proxy_new(lrmd_t *lrmd, struct ipc_client_callbacks *proxy_callbacks,
     /* [previous][next][first][last][top][bottom][index][help] */
 178                  const char *node_name, const char *session_id, const char *channel)
 179 {
 180     remote_proxy_t *proxy = NULL;
 181 
 182     if(channel == NULL) {
 183         crm_err("No channel specified to proxy");
 184         remote_proxy_notify_destroy(lrmd, session_id);
 185         return NULL;
 186     }
 187 
 188     proxy = pcmk__assert_alloc(1, sizeof(remote_proxy_t));
 189 
 190     proxy->node_name = strdup(node_name);
 191     proxy->session_id = strdup(session_id);
 192     proxy->lrm = lrmd;
 193 
 194     if (!strcmp(pcmk__message_name(crm_system_name), CRM_SYSTEM_CRMD)
 195         && !strcmp(pcmk__message_name(channel), CRM_SYSTEM_CRMD)) {
 196         // The controller doesn't need to connect to itself
 197         proxy->is_local = TRUE;
 198 
 199     } else {
 200         proxy->source = mainloop_add_ipc_client(channel, G_PRIORITY_LOW, 0, proxy, proxy_callbacks);
 201         proxy->ipc = mainloop_get_ipc_client(proxy->source);
 202         if (proxy->source == NULL) {
 203             remote_proxy_free(proxy);
 204             remote_proxy_notify_destroy(lrmd, session_id);
 205             return NULL;
 206         }
 207     }
 208 
 209     crm_trace("new remote proxy client established to %s on %s, session id %s",
 210               channel, node_name, session_id);
 211     g_hash_table_insert(proxy_table, proxy->session_id, proxy);
 212 
 213     return proxy;
 214 }
 215 
 216 void
 217 remote_proxy_cb(lrmd_t *lrmd, const char *node_name, xmlNode *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 218 {
 219     const char *op = crm_element_value(msg, PCMK__XA_LRMD_IPC_OP);
 220     const char *session = crm_element_value(msg, PCMK__XA_LRMD_IPC_SESSION);
 221     remote_proxy_t *proxy = g_hash_table_lookup(proxy_table, session);
 222     int msg_id = 0;
 223 
 224     /* sessions are raw ipc connections to IPC,
 225      * all we do is proxy requests/responses exactly
 226      * like they are given to us at the ipc level. */
 227 
 228     CRM_CHECK(op != NULL, return);
 229     CRM_CHECK(session != NULL, return);
 230 
 231     crm_element_value_int(msg, PCMK__XA_LRMD_IPC_MSG_ID, &msg_id);
 232     /* This is msg from remote ipc client going to real ipc server */
 233 
 234     if (pcmk__str_eq(op, LRMD_IPC_OP_DESTROY, pcmk__str_casei)) {
 235         remote_proxy_end_session(proxy);
 236 
 237     } else if (pcmk__str_eq(op, LRMD_IPC_OP_REQUEST, pcmk__str_casei)) {
 238         uint32_t flags = 0U;
 239         int rc = pcmk_rc_ok;
 240         const char *name = crm_element_value(msg, PCMK__XA_LRMD_IPC_CLIENT);
 241 
 242         xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_LRMD_IPC_MSG,
 243                                                 NULL, NULL);
 244         xmlNode *request = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
 245 
 246         CRM_CHECK(request != NULL, return);
 247 
 248         if (proxy == NULL) {
 249             /* proxy connection no longer exists */
 250             remote_proxy_notify_destroy(lrmd, session);
 251             return;
 252         }
 253 
 254         // Controller requests MUST be handled by the controller, not us
 255         CRM_CHECK(proxy->is_local == FALSE,
 256                   remote_proxy_end_session(proxy); return);
 257 
 258         if (!crm_ipc_connected(proxy->ipc)) {
 259             remote_proxy_end_session(proxy);
 260             return;
 261         }
 262         proxy->last_request_id = 0;
 263         crm_xml_add(request, PCMK_XE_ACL_ROLE, "pacemaker-remote");
 264 
 265         rc = pcmk__xe_get_flags(msg, PCMK__XA_LRMD_IPC_MSG_FLAGS, &flags, 0U);
 266         if (rc != pcmk_rc_ok) {
 267             crm_warn("Couldn't parse controller flags from remote request: %s",
 268                      pcmk_rc_str(rc));
 269         }
 270 
 271         pcmk__assert(node_name != NULL);
 272         pcmk__update_acl_user(request, PCMK__XA_LRMD_IPC_USER, node_name);
 273 
 274         if (pcmk_is_set(flags, crm_ipc_proxied)) {
 275             const char *type = crm_element_value(request, PCMK__XA_T);
 276             int rc = 0;
 277 
 278             if (pcmk__str_eq(type, PCMK__VALUE_ATTRD, pcmk__str_none)
 279                 && (crm_element_value(request, PCMK__XA_ATTR_HOST) == NULL)
 280                 && pcmk__str_any_of(crm_element_value(request, PCMK_XA_TASK),
 281                                     PCMK__ATTRD_CMD_UPDATE,
 282                                     PCMK__ATTRD_CMD_UPDATE_BOTH,
 283                                     PCMK__ATTRD_CMD_UPDATE_DELAY, NULL)) {
 284                 pcmk__xe_add_node(request, proxy->node_name, 0);
 285             }
 286 
 287             rc = crm_ipc_send(proxy->ipc, request, flags, 5000, NULL);
 288 
 289             if(rc < 0) {
 290                 xmlNode *op_reply = pcmk__xe_create(NULL, PCMK__XE_NACK);
 291 
 292                 crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
 293                          op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
 294 
 295                 /* Send a n'ack so the caller doesn't block */
 296                 crm_xml_add(op_reply, PCMK_XA_FUNCTION, __func__);
 297                 crm_xml_add_int(op_reply, PCMK__XA_LINE, __LINE__);
 298                 crm_xml_add_int(op_reply, PCMK_XA_RC, rc);
 299                 remote_proxy_relay_response(proxy, op_reply, msg_id);
 300                 free_xml(op_reply);
 301 
 302             } else {
 303                 crm_trace("Relayed %s request %d from %s to %s for %s",
 304                           op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
 305                 proxy->last_request_id = msg_id;
 306             }
 307 
 308         } else {
 309             int rc = pcmk_ok;
 310             xmlNode *op_reply = NULL;
 311             // @COMPAT pacemaker_remoted <= 1.1.10
 312 
 313             crm_trace("Relaying %s request %d from %s to %s for %s",
 314                       op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
 315 
 316             rc = crm_ipc_send(proxy->ipc, request, flags, 10000, &op_reply);
 317             if(rc < 0) {
 318                 crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
 319                          op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
 320             } else {
 321                 crm_trace("Relayed %s request %d from %s to %s for %s",
 322                           op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
 323             }
 324 
 325             if(op_reply) {
 326                 remote_proxy_relay_response(proxy, op_reply, msg_id);
 327                 free_xml(op_reply);
 328             }
 329         }
 330     } else {
 331         crm_err("Unknown proxy operation: %s", op);
 332     }
 333 }

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