LCOV - code coverage report
Current view: top level - lrmd - proxy_common.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 160 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 11 0.0 %

          Line data    Source code
       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           0 : remote_proxy_notify_destroy(lrmd_t *lrmd, const char *session_id)
      30             : {
      31             :     /* sending to the remote node that an ipc connection has been destroyed */
      32           0 :     xmlNode *msg = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
      33           0 :     crm_xml_add(msg, PCMK__XA_LRMD_IPC_OP, LRMD_IPC_OP_DESTROY);
      34           0 :     crm_xml_add(msg, PCMK__XA_LRMD_IPC_SESSION, session_id);
      35           0 :     lrmd_internal_proxy_send(lrmd, msg);
      36           0 :     free_xml(msg);
      37           0 : }
      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           0 : remote_proxy_ack_shutdown(lrmd_t *lrmd)
      47             : {
      48           0 :     xmlNode *msg = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
      49           0 :     crm_xml_add(msg, PCMK__XA_LRMD_IPC_OP, LRMD_IPC_OP_SHUTDOWN_ACK);
      50           0 :     lrmd_internal_proxy_send(lrmd, msg);
      51           0 :     free_xml(msg);
      52           0 : }
      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           0 : remote_proxy_nack_shutdown(lrmd_t *lrmd)
      62             : {
      63           0 :     xmlNode *msg = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
      64           0 :     crm_xml_add(msg, PCMK__XA_LRMD_IPC_OP, LRMD_IPC_OP_SHUTDOWN_NACK);
      65           0 :     lrmd_internal_proxy_send(lrmd, msg);
      66           0 :     free_xml(msg);
      67           0 : }
      68             : 
      69             : void
      70           0 : remote_proxy_relay_event(remote_proxy_t *proxy, xmlNode *msg)
      71             : {
      72             :     /* sending to the remote node an event msg. */
      73           0 :     xmlNode *event = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
      74           0 :     xmlNode *wrapper = NULL;
      75             : 
      76           0 :     crm_xml_add(event, PCMK__XA_LRMD_IPC_OP, LRMD_IPC_OP_EVENT);
      77           0 :     crm_xml_add(event, PCMK__XA_LRMD_IPC_SESSION, proxy->session_id);
      78             : 
      79           0 :     wrapper = pcmk__xe_create(event, PCMK__XE_LRMD_IPC_MSG);
      80           0 :     pcmk__xml_copy(wrapper, msg);
      81             : 
      82           0 :     crm_log_xml_explicit(event, "EventForProxy");
      83           0 :     lrmd_internal_proxy_send(proxy->lrm, event);
      84           0 :     free_xml(event);
      85           0 : }
      86             : 
      87             : void
      88           0 : remote_proxy_relay_response(remote_proxy_t *proxy, xmlNode *msg, int msg_id)
      89             : {
      90             :     /* sending to the remote node a response msg. */
      91           0 :     xmlNode *response = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
      92           0 :     xmlNode *wrapper = NULL;
      93             : 
      94           0 :     crm_xml_add(response, PCMK__XA_LRMD_IPC_OP, LRMD_IPC_OP_RESPONSE);
      95           0 :     crm_xml_add(response, PCMK__XA_LRMD_IPC_SESSION, proxy->session_id);
      96           0 :     crm_xml_add_int(response, PCMK__XA_LRMD_IPC_MSG_ID, msg_id);
      97             : 
      98           0 :     wrapper = pcmk__xe_create(response, PCMK__XE_LRMD_IPC_MSG);
      99           0 :     pcmk__xml_copy(wrapper, msg);
     100             : 
     101           0 :     lrmd_internal_proxy_send(proxy->lrm, response);
     102           0 :     free_xml(response);
     103           0 : }
     104             : 
     105             : static void
     106           0 : remote_proxy_end_session(remote_proxy_t *proxy)
     107             : {
     108           0 :     if (proxy == NULL) {
     109           0 :         return;
     110             :     }
     111           0 :     crm_trace("ending session ID %s", proxy->session_id);
     112             : 
     113           0 :     if (proxy->source) {
     114           0 :         mainloop_del_ipc_client(proxy->source);
     115             :     }
     116             : }
     117             : 
     118             : void
     119           0 : remote_proxy_free(gpointer data)
     120             : {
     121           0 :     remote_proxy_t *proxy = data;
     122             : 
     123           0 :     crm_trace("freed proxy session ID %s", proxy->session_id);
     124           0 :     free(proxy->node_name);
     125           0 :     free(proxy->session_id);
     126           0 :     free(proxy);
     127           0 : }
     128             : 
     129             : int
     130           0 : remote_proxy_dispatch(const char *buffer, ssize_t length, gpointer userdata)
     131             : {
     132             :     // Async responses from cib and friends to clients via pacemaker-remoted
     133           0 :     xmlNode *xml = NULL;
     134           0 :     uint32_t flags = 0;
     135           0 :     remote_proxy_t *proxy = userdata;
     136             : 
     137           0 :     xml = pcmk__xml_parse(buffer);
     138           0 :     if (xml == NULL) {
     139           0 :         crm_warn("Received a NULL msg from IPC service.");
     140           0 :         return 1;
     141             :     }
     142             : 
     143           0 :     flags = crm_ipc_buffer_flags(proxy->ipc);
     144           0 :     if (flags & crm_ipc_proxied_relay_response) {
     145           0 :         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           0 :         remote_proxy_relay_response(proxy, xml, proxy->last_request_id);
     147           0 :         proxy->last_request_id = 0;
     148             : 
     149             :     } else {
     150           0 :         crm_trace("Passing event back to %.8s on %s: %.200s", proxy->session_id, proxy->node_name, buffer);
     151           0 :         remote_proxy_relay_event(proxy, xml);
     152             :     }
     153           0 :     free_xml(xml);
     154           0 :     return 1;
     155             : }
     156             : 
     157             : 
     158             : void
     159           0 : remote_proxy_disconnected(gpointer userdata)
     160             : {
     161           0 :     remote_proxy_t *proxy = userdata;
     162             : 
     163           0 :     crm_trace("destroying %p", proxy);
     164             : 
     165           0 :     proxy->source = NULL;
     166           0 :     proxy->ipc = NULL;
     167             : 
     168           0 :     if(proxy->lrm) {
     169           0 :         remote_proxy_notify_destroy(proxy->lrm, proxy->session_id);
     170           0 :         proxy->lrm = NULL;
     171             :     }
     172             : 
     173           0 :     g_hash_table_remove(proxy_table, proxy->session_id);
     174           0 : }
     175             : 
     176             : remote_proxy_t *
     177           0 : remote_proxy_new(lrmd_t *lrmd, struct ipc_client_callbacks *proxy_callbacks,
     178             :                  const char *node_name, const char *session_id, const char *channel)
     179             : {
     180           0 :     remote_proxy_t *proxy = NULL;
     181             : 
     182           0 :     if(channel == NULL) {
     183           0 :         crm_err("No channel specified to proxy");
     184           0 :         remote_proxy_notify_destroy(lrmd, session_id);
     185           0 :         return NULL;
     186             :     }
     187             : 
     188           0 :     proxy = pcmk__assert_alloc(1, sizeof(remote_proxy_t));
     189             : 
     190           0 :     proxy->node_name = strdup(node_name);
     191           0 :     proxy->session_id = strdup(session_id);
     192           0 :     proxy->lrm = lrmd;
     193             : 
     194           0 :     if (!strcmp(pcmk__message_name(crm_system_name), CRM_SYSTEM_CRMD)
     195           0 :         && !strcmp(pcmk__message_name(channel), CRM_SYSTEM_CRMD)) {
     196             :         // The controller doesn't need to connect to itself
     197           0 :         proxy->is_local = TRUE;
     198             : 
     199             :     } else {
     200           0 :         proxy->source = mainloop_add_ipc_client(channel, G_PRIORITY_LOW, 0, proxy, proxy_callbacks);
     201           0 :         proxy->ipc = mainloop_get_ipc_client(proxy->source);
     202           0 :         if (proxy->source == NULL) {
     203           0 :             remote_proxy_free(proxy);
     204           0 :             remote_proxy_notify_destroy(lrmd, session_id);
     205           0 :             return NULL;
     206             :         }
     207             :     }
     208             : 
     209           0 :     crm_trace("new remote proxy client established to %s on %s, session id %s",
     210             :               channel, node_name, session_id);
     211           0 :     g_hash_table_insert(proxy_table, proxy->session_id, proxy);
     212             : 
     213           0 :     return proxy;
     214             : }
     215             : 
     216             : void
     217           0 : remote_proxy_cb(lrmd_t *lrmd, const char *node_name, xmlNode *msg)
     218             : {
     219           0 :     const char *op = crm_element_value(msg, PCMK__XA_LRMD_IPC_OP);
     220           0 :     const char *session = crm_element_value(msg, PCMK__XA_LRMD_IPC_SESSION);
     221           0 :     remote_proxy_t *proxy = g_hash_table_lookup(proxy_table, session);
     222           0 :     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           0 :     CRM_CHECK(op != NULL, return);
     229           0 :     CRM_CHECK(session != NULL, return);
     230             : 
     231           0 :     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           0 :     if (pcmk__str_eq(op, LRMD_IPC_OP_DESTROY, pcmk__str_casei)) {
     235           0 :         remote_proxy_end_session(proxy);
     236             : 
     237           0 :     } else if (pcmk__str_eq(op, LRMD_IPC_OP_REQUEST, pcmk__str_casei)) {
     238           0 :         int flags = 0;
     239           0 :         const char *name = crm_element_value(msg, PCMK__XA_LRMD_IPC_CLIENT);
     240             : 
     241           0 :         xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_LRMD_IPC_MSG,
     242             :                                                 NULL, NULL);
     243           0 :         xmlNode *request = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
     244             : 
     245           0 :         CRM_CHECK(request != NULL, return);
     246             : 
     247           0 :         if (proxy == NULL) {
     248             :             /* proxy connection no longer exists */
     249           0 :             remote_proxy_notify_destroy(lrmd, session);
     250           0 :             return;
     251             :         }
     252             : 
     253             :         // Controller requests MUST be handled by the controller, not us
     254           0 :         CRM_CHECK(proxy->is_local == FALSE,
     255             :                   remote_proxy_end_session(proxy); return);
     256             : 
     257           0 :         if (!crm_ipc_connected(proxy->ipc)) {
     258           0 :             remote_proxy_end_session(proxy);
     259           0 :             return;
     260             :         }
     261           0 :         proxy->last_request_id = 0;
     262           0 :         crm_element_value_int(msg, PCMK__XA_LRMD_IPC_MSG_FLAGS, &flags);
     263           0 :         crm_xml_add(request, PCMK_XE_ACL_ROLE, "pacemaker-remote");
     264             : 
     265           0 :         CRM_ASSERT(node_name);
     266           0 :         pcmk__update_acl_user(request, PCMK__XA_LRMD_IPC_USER, node_name);
     267             : 
     268           0 :         if (pcmk_is_set(flags, crm_ipc_proxied)) {
     269           0 :             const char *type = crm_element_value(request, PCMK__XA_T);
     270           0 :             int rc = 0;
     271             : 
     272           0 :             if (pcmk__str_eq(type, PCMK__VALUE_ATTRD, pcmk__str_none)
     273           0 :                 && (crm_element_value(request, PCMK__XA_ATTR_HOST) == NULL)
     274           0 :                 && pcmk__str_any_of(crm_element_value(request, PCMK_XA_TASK),
     275             :                                     PCMK__ATTRD_CMD_UPDATE,
     276             :                                     PCMK__ATTRD_CMD_UPDATE_BOTH,
     277             :                                     PCMK__ATTRD_CMD_UPDATE_DELAY, NULL)) {
     278           0 :                 pcmk__xe_add_node(request, proxy->node_name, 0);
     279             :             }
     280             : 
     281           0 :             rc = crm_ipc_send(proxy->ipc, request, flags, 5000, NULL);
     282             : 
     283           0 :             if(rc < 0) {
     284           0 :                 xmlNode *op_reply = pcmk__xe_create(NULL, PCMK__XE_NACK);
     285             : 
     286           0 :                 crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
     287             :                          op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
     288             : 
     289             :                 /* Send a n'ack so the caller doesn't block */
     290           0 :                 crm_xml_add(op_reply, PCMK_XA_FUNCTION, __func__);
     291           0 :                 crm_xml_add_int(op_reply, PCMK__XA_LINE, __LINE__);
     292           0 :                 crm_xml_add_int(op_reply, PCMK_XA_RC, rc);
     293           0 :                 remote_proxy_relay_response(proxy, op_reply, msg_id);
     294           0 :                 free_xml(op_reply);
     295             : 
     296             :             } else {
     297           0 :                 crm_trace("Relayed %s request %d from %s to %s for %s",
     298             :                           op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
     299           0 :                 proxy->last_request_id = msg_id;
     300             :             }
     301             : 
     302             :         } else {
     303           0 :             int rc = pcmk_ok;
     304           0 :             xmlNode *op_reply = NULL;
     305             :             // @COMPAT pacemaker_remoted <= 1.1.10
     306             : 
     307           0 :             crm_trace("Relaying %s request %d from %s to %s for %s",
     308             :                       op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
     309             : 
     310           0 :             rc = crm_ipc_send(proxy->ipc, request, flags, 10000, &op_reply);
     311           0 :             if(rc < 0) {
     312           0 :                 crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
     313             :                          op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
     314             :             } else {
     315           0 :                 crm_trace("Relayed %s request %d from %s to %s for %s",
     316             :                           op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
     317             :             }
     318             : 
     319           0 :             if(op_reply) {
     320           0 :                 remote_proxy_relay_response(proxy, op_reply, msg_id);
     321           0 :                 free_xml(op_reply);
     322             :             }
     323             :         }
     324             :     } else {
     325           0 :         crm_err("Unknown proxy operation: %s", op);
     326             :     }
     327             : }

Generated by: LCOV version 1.14