root/daemons/execd/remoted_proxy.c

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

DEFINITIONS

This source file includes following definitions.
  1. ipc_proxy_get_provider
  2. ipc_proxy_accept
  3. crmd_proxy_accept
  4. attrd_proxy_accept
  5. stonith_proxy_accept
  6. pacemakerd_proxy_accept
  7. cib_proxy_accept_rw
  8. cib_proxy_accept_ro
  9. ipc_proxy_forward_client
  10. ipc_proxy_dispatch
  11. ipc_proxy_shutdown_req
  12. ipc_proxy_closed
  13. ipc_proxy_destroy
  14. ipc_proxy_add_provider
  15. ipc_proxy_remove_provider
  16. ipc_proxy_init
  17. ipc_proxy_cleanup

   1 /*
   2  * Copyright 2012-2021 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 "pacemaker-execd.h"
  16 #include <crm/crm.h>
  17 #include <crm/msg_xml.h>
  18 #include <crm/services.h>
  19 #include <crm/common/mainloop.h>
  20 #include <crm/common/ipc.h>
  21 #include <crm/common/ipc_internal.h>
  22 #include <crm/cib/internal.h>
  23 #include <crm/fencing/internal.h>
  24 
  25 static qb_ipcs_service_t *cib_ro = NULL;
  26 static qb_ipcs_service_t *cib_rw = NULL;
  27 static qb_ipcs_service_t *cib_shm = NULL;
  28 
  29 static qb_ipcs_service_t *attrd_ipcs = NULL;
  30 static qb_ipcs_service_t *crmd_ipcs = NULL;
  31 static qb_ipcs_service_t *stonith_ipcs = NULL;
  32 static qb_ipcs_service_t *pacemakerd_ipcs = NULL;
  33 
  34 // An IPC provider is a cluster node controller connecting as a client
  35 static GList *ipc_providers = NULL;
  36 /* ipc clients == things like cibadmin, crm_resource, connecting locally */
  37 static GHashTable *ipc_clients = NULL;
  38 
  39 /*!
  40  * \internal
  41  * \brief Get an IPC proxy provider
  42  *
  43  * \return Pointer to a provider if one exists, NULL otherwise
  44  *
  45  * \note Grab the first provider, which is the most recent connection. That way,
  46  *       if we haven't yet timed out an old, failed connection, we don't try to
  47  *       use it.
  48  */
  49 pcmk__client_t *
  50 ipc_proxy_get_provider()
     /* [previous][next][first][last][top][bottom][index][help] */
  51 {
  52     return ipc_providers? (pcmk__client_t *) (ipc_providers->data) : NULL;
  53 }
  54 
  55 /*!
  56  * \internal
  57  * \brief Accept a client connection on a proxy IPC server
  58  *
  59  * \param[in] c            Client's IPC connection
  60  * \param[in] uid          Client's user ID
  61  * \param[in] gid          Client's group ID
  62  * \param[in] ipc_channel  Name of IPC server to proxy
  63  *
  64  * \return pcmk_ok on success, -errno on error
  65  */
  66 static int32_t
  67 ipc_proxy_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid, const char *ipc_channel)
     /* [previous][next][first][last][top][bottom][index][help] */
  68 {
  69     pcmk__client_t *client;
  70     pcmk__client_t *ipc_proxy = ipc_proxy_get_provider();
  71     xmlNode *msg;
  72 
  73     if (ipc_proxy == NULL) {
  74         crm_warn("Cannot proxy IPC connection from uid %d gid %d to %s "
  75                  "because not connected to cluster", uid, gid, ipc_channel);
  76         return -EREMOTEIO;
  77     }
  78 
  79     /* This new client is a local IPC client on a Pacemaker Remote controlled
  80      * node, needing to access cluster node IPC services.
  81      */
  82     client = pcmk__new_client(c, uid, gid);
  83     if (client == NULL) {
  84         return -EREMOTEIO;
  85     }
  86 
  87     /* This ipc client is bound to a single ipc provider. If the
  88      * provider goes away, this client is disconnected */
  89     client->userdata = strdup(ipc_proxy->id);
  90     client->name = crm_strdup_printf("proxy-%s-%d-%.8s", ipc_channel, client->pid, client->id);
  91 
  92     /* Allow remote executor to distinguish between proxied local clients and
  93      * actual executor API clients
  94      */
  95     pcmk__set_client_flags(client, pcmk__client_to_proxy);
  96 
  97     g_hash_table_insert(ipc_clients, client->id, client);
  98 
  99     msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
 100     crm_xml_add(msg, F_LRMD_IPC_OP, LRMD_IPC_OP_NEW);
 101     crm_xml_add(msg, F_LRMD_IPC_IPC_SERVER, ipc_channel);
 102     crm_xml_add(msg, F_LRMD_IPC_SESSION, client->id);
 103     lrmd_server_send_notify(ipc_proxy, msg);
 104     free_xml(msg);
 105     crm_debug("Accepted IPC proxy connection (session ID %s) "
 106               "from uid %d gid %d on channel %s",
 107               client->id, uid, gid, ipc_channel);
 108     return 0;
 109 }
 110 
 111 static int32_t
 112 crmd_proxy_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
     /* [previous][next][first][last][top][bottom][index][help] */
 113 {
 114     return ipc_proxy_accept(c, uid, gid, CRM_SYSTEM_CRMD);
 115 }
 116 
 117 static int32_t
 118 attrd_proxy_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
     /* [previous][next][first][last][top][bottom][index][help] */
 119 {
 120     return ipc_proxy_accept(c, uid, gid, T_ATTRD);
 121 }
 122 
 123 static int32_t
 124 stonith_proxy_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
     /* [previous][next][first][last][top][bottom][index][help] */
 125 {
 126     return ipc_proxy_accept(c, uid, gid, "stonith-ng");
 127 }
 128 
 129 static int32_t
 130 pacemakerd_proxy_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
     /* [previous][next][first][last][top][bottom][index][help] */
 131 {
 132     return -EREMOTEIO;
 133 }
 134 
 135 static int32_t
 136 cib_proxy_accept_rw(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
     /* [previous][next][first][last][top][bottom][index][help] */
 137 {
 138     return ipc_proxy_accept(c, uid, gid, PCMK__SERVER_BASED_RW);
 139 }
 140 
 141 static int32_t
 142 cib_proxy_accept_ro(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144     return ipc_proxy_accept(c, uid, gid, PCMK__SERVER_BASED_RO);
 145 }
 146 
 147 void
 148 ipc_proxy_forward_client(pcmk__client_t *ipc_proxy, xmlNode *xml)
     /* [previous][next][first][last][top][bottom][index][help] */
 149 {
 150     const char *session = crm_element_value(xml, F_LRMD_IPC_SESSION);
 151     const char *msg_type = crm_element_value(xml, F_LRMD_IPC_OP);
 152     xmlNode *msg = get_message_xml(xml, F_LRMD_IPC_MSG);
 153     pcmk__client_t *ipc_client;
 154     int rc = pcmk_rc_ok;
 155 
 156     /* If the IPC provider is acknowledging our shutdown request,
 157      * defuse the short exit timer to give the cluster time to
 158      * stop any resources we're running.
 159      */
 160     if (pcmk__str_eq(msg_type, LRMD_IPC_OP_SHUTDOWN_ACK, pcmk__str_casei)) {
 161         handle_shutdown_ack();
 162         return;
 163     }
 164 
 165     if (pcmk__str_eq(msg_type, LRMD_IPC_OP_SHUTDOWN_NACK, pcmk__str_casei)) {
 166         handle_shutdown_nack();
 167         return;
 168     }
 169 
 170     ipc_client = pcmk__find_client_by_id(session);
 171     if (ipc_client == NULL) {
 172         xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
 173         crm_xml_add(msg, F_LRMD_IPC_OP, LRMD_IPC_OP_DESTROY);
 174         crm_xml_add(msg, F_LRMD_IPC_SESSION, session);
 175         lrmd_server_send_notify(ipc_proxy, msg);
 176         free_xml(msg);
 177         return;
 178     }
 179 
 180     /* This is an event or response from the ipc provider
 181      * going to the local ipc client.
 182      *
 183      * Looking at the chain of events.
 184      *
 185      * -----remote node----------------|---- cluster node ------
 186      * ipc_client <--1--> this code
 187      *    <--2--> pacemaker-controld:remote_proxy_cb/remote_proxy_relay_event()
 188      *    <--3--> ipc server
 189      *
 190      * This function is receiving a msg from connection 2
 191      * and forwarding it to connection 1.
 192      */
 193 
 194     if (pcmk__str_eq(msg_type, LRMD_IPC_OP_EVENT, pcmk__str_casei)) {
 195         crm_trace("Sending event to %s", ipc_client->id);
 196         rc = pcmk__ipc_send_xml(ipc_client, 0, msg, crm_ipc_server_event);
 197 
 198     } else if (pcmk__str_eq(msg_type, LRMD_IPC_OP_RESPONSE, pcmk__str_casei)) {
 199         int msg_id = 0;
 200 
 201         crm_element_value_int(xml, F_LRMD_IPC_MSG_ID, &msg_id);
 202         crm_trace("Sending response to %d - %s", ipc_client->request_id, ipc_client->id);
 203         rc = pcmk__ipc_send_xml(ipc_client, msg_id, msg, FALSE);
 204 
 205         CRM_LOG_ASSERT(msg_id == ipc_client->request_id);
 206         ipc_client->request_id = 0;
 207 
 208     } else if (pcmk__str_eq(msg_type, LRMD_IPC_OP_DESTROY, pcmk__str_casei)) {
 209         qb_ipcs_disconnect(ipc_client->ipcs);
 210 
 211     } else {
 212         crm_err("Unknown ipc proxy msg type %s" , msg_type);
 213     }
 214 
 215     if (rc != pcmk_rc_ok) {
 216         crm_warn("Could not proxy IPC to client %s: %s " CRM_XS " rc=%d",
 217                  ipc_client->id, pcmk_rc_str(rc), rc);
 218     }
 219 }
 220 
 221 static int32_t
 222 ipc_proxy_dispatch(qb_ipcs_connection_t * c, void *data, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224     uint32_t id = 0;
 225     uint32_t flags = 0;
 226     pcmk__client_t *client = pcmk__find_client(c);
 227     pcmk__client_t *ipc_proxy = pcmk__find_client_by_id(client->userdata);
 228     xmlNode *request = NULL;
 229     xmlNode *msg = NULL;
 230 
 231     if (!ipc_proxy) {
 232         qb_ipcs_disconnect(client->ipcs);
 233         return 0;
 234     }
 235 
 236     /* This is a request from the local ipc client going
 237      * to the ipc provider.
 238      *
 239      * Looking at the chain of events.
 240      *
 241      * -----remote node----------------|---- cluster node ------
 242      * ipc_client <--1--> this code
 243      *     <--2--> pacemaker-controld:remote_proxy_dispatch_internal()
 244      *     <--3--> ipc server
 245      *
 246      * This function is receiving a request from connection
 247      * 1 and forwarding it to connection 2.
 248      */
 249     request = pcmk__client_data2xml(client, data, &id, &flags);
 250 
 251     if (!request) {
 252         return 0;
 253     }
 254 
 255     CRM_CHECK(client != NULL, crm_err("Invalid client");
 256               free_xml(request); return FALSE);
 257     CRM_CHECK(client->id != NULL, crm_err("Invalid client: %p", client);
 258               free_xml(request); return FALSE);
 259 
 260     /* This ensures that synced request/responses happen over the event channel
 261      * in the controller, allowing the controller to process the messages async.
 262      */
 263     pcmk__set_ipc_flags(flags, pcmk__client_name(client), crm_ipc_proxied);
 264     client->request_id = id;
 265 
 266     msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
 267     crm_xml_add(msg, F_LRMD_IPC_OP, LRMD_IPC_OP_REQUEST);
 268     crm_xml_add(msg, F_LRMD_IPC_SESSION, client->id);
 269     crm_xml_add(msg, F_LRMD_IPC_CLIENT, pcmk__client_name(client));
 270     crm_xml_add(msg, F_LRMD_IPC_USER, client->user);
 271     crm_xml_add_int(msg, F_LRMD_IPC_MSG_ID, id);
 272     crm_xml_add_int(msg, F_LRMD_IPC_MSG_FLAGS, flags);
 273     add_message_xml(msg, F_LRMD_IPC_MSG, request);
 274     lrmd_server_send_notify(ipc_proxy, msg);
 275     free_xml(request);
 276     free_xml(msg);
 277 
 278     return 0;
 279 }
 280 
 281 /*!
 282  * \internal
 283  * \brief Notify a proxy provider that we wish to shut down
 284  *
 285  * \return 0 on success, -1 on error
 286  */
 287 int
 288 ipc_proxy_shutdown_req(pcmk__client_t *ipc_proxy)
     /* [previous][next][first][last][top][bottom][index][help] */
 289 {
 290     xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
 291     int rc;
 292 
 293     crm_xml_add(msg, F_LRMD_IPC_OP, LRMD_IPC_OP_SHUTDOWN_REQ);
 294 
 295     /* We don't really have a session, but the controller needs this attribute
 296      * to recognize this as proxy communication.
 297      */
 298     crm_xml_add(msg, F_LRMD_IPC_SESSION, "0");
 299 
 300     rc = (lrmd_server_send_notify(ipc_proxy, msg) != pcmk_rc_ok)? -1 : 0;
 301     free_xml(msg);
 302     return rc;
 303 }
 304 
 305 static int32_t
 306 ipc_proxy_closed(qb_ipcs_connection_t * c)
     /* [previous][next][first][last][top][bottom][index][help] */
 307 {
 308     pcmk__client_t *client = pcmk__find_client(c);
 309     pcmk__client_t *ipc_proxy;
 310 
 311     if (client == NULL) {
 312         return 0;
 313     }
 314 
 315     ipc_proxy = pcmk__find_client_by_id(client->userdata);
 316 
 317     crm_trace("Connection %p", c);
 318 
 319     if (ipc_proxy) {
 320         xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
 321         crm_xml_add(msg, F_LRMD_IPC_OP, LRMD_IPC_OP_DESTROY);
 322         crm_xml_add(msg, F_LRMD_IPC_SESSION, client->id);
 323         lrmd_server_send_notify(ipc_proxy, msg);
 324         free_xml(msg);
 325     }
 326 
 327     g_hash_table_remove(ipc_clients, client->id);
 328 
 329     free(client->userdata);
 330     client->userdata = NULL;
 331     pcmk__free_client(client);
 332     return 0;
 333 }
 334 
 335 static void
 336 ipc_proxy_destroy(qb_ipcs_connection_t * c)
     /* [previous][next][first][last][top][bottom][index][help] */
 337 {
 338     crm_trace("Connection %p", c);
 339     ipc_proxy_closed(c);
 340 }
 341 
 342 static struct qb_ipcs_service_handlers crmd_proxy_callbacks = {
 343     .connection_accept = crmd_proxy_accept,
 344     .connection_created = NULL,
 345     .msg_process = ipc_proxy_dispatch,
 346     .connection_closed = ipc_proxy_closed,
 347     .connection_destroyed = ipc_proxy_destroy
 348 };
 349 
 350 static struct qb_ipcs_service_handlers attrd_proxy_callbacks = {
 351     .connection_accept = attrd_proxy_accept,
 352     .connection_created = NULL,
 353     .msg_process = ipc_proxy_dispatch,
 354     .connection_closed = ipc_proxy_closed,
 355     .connection_destroyed = ipc_proxy_destroy
 356 };
 357 
 358 static struct qb_ipcs_service_handlers stonith_proxy_callbacks = {
 359     .connection_accept = stonith_proxy_accept,
 360     .connection_created = NULL,
 361     .msg_process = ipc_proxy_dispatch,
 362     .connection_closed = ipc_proxy_closed,
 363     .connection_destroyed = ipc_proxy_destroy
 364 };
 365 
 366 static struct qb_ipcs_service_handlers pacemakerd_proxy_callbacks = {
 367     .connection_accept = pacemakerd_proxy_accept,
 368     .connection_created = NULL,
 369     .msg_process = NULL,
 370     .connection_closed = NULL,
 371     .connection_destroyed = NULL
 372 };
 373 
 374 static struct qb_ipcs_service_handlers cib_proxy_callbacks_ro = {
 375     .connection_accept = cib_proxy_accept_ro,
 376     .connection_created = NULL,
 377     .msg_process = ipc_proxy_dispatch,
 378     .connection_closed = ipc_proxy_closed,
 379     .connection_destroyed = ipc_proxy_destroy
 380 };
 381 
 382 static struct qb_ipcs_service_handlers cib_proxy_callbacks_rw = {
 383     .connection_accept = cib_proxy_accept_rw,
 384     .connection_created = NULL,
 385     .msg_process = ipc_proxy_dispatch,
 386     .connection_closed = ipc_proxy_closed,
 387     .connection_destroyed = ipc_proxy_destroy
 388 };
 389 
 390 void
 391 ipc_proxy_add_provider(pcmk__client_t *ipc_proxy)
     /* [previous][next][first][last][top][bottom][index][help] */
 392 {
 393     // Prepending ensures the most recent connection is always first
 394     ipc_providers = g_list_prepend(ipc_providers, ipc_proxy);
 395 }
 396 
 397 void
 398 ipc_proxy_remove_provider(pcmk__client_t *ipc_proxy)
     /* [previous][next][first][last][top][bottom][index][help] */
 399 {
 400     GHashTableIter iter;
 401     pcmk__client_t *ipc_client = NULL;
 402     char *key = NULL;
 403     GList *remove_these = NULL;
 404     GList *gIter = NULL;
 405 
 406     ipc_providers = g_list_remove(ipc_providers, ipc_proxy);
 407 
 408     g_hash_table_iter_init(&iter, ipc_clients);
 409     while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & ipc_client)) {
 410         const char *proxy_id = ipc_client->userdata;
 411         if (pcmk__str_eq(proxy_id, ipc_proxy->id, pcmk__str_casei)) {
 412             crm_info("ipc proxy connection for client %s pid %d destroyed because cluster node disconnected.",
 413                 ipc_client->id, ipc_client->pid);
 414             /* we can't remove during the iteration, so copy items
 415              * to a list we can destroy later */
 416             remove_these = g_list_append(remove_these, ipc_client);
 417         }
 418     }
 419 
 420     for (gIter = remove_these; gIter != NULL; gIter = gIter->next) {
 421         ipc_client = gIter->data;
 422 
 423         // Disconnection callback will free the client here
 424         qb_ipcs_disconnect(ipc_client->ipcs);
 425     }
 426 
 427     /* just frees the list, not the elements in the list */
 428     g_list_free(remove_these);
 429 }
 430 
 431 void
 432 ipc_proxy_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 433 {
 434     ipc_clients = pcmk__strkey_table(NULL, NULL);
 435 
 436     pcmk__serve_based_ipc(&cib_ro, &cib_rw, &cib_shm, &cib_proxy_callbacks_ro,
 437                           &cib_proxy_callbacks_rw);
 438     pcmk__serve_attrd_ipc(&attrd_ipcs, &attrd_proxy_callbacks);
 439     pcmk__serve_fenced_ipc(&stonith_ipcs, &stonith_proxy_callbacks);
 440     pcmk__serve_pacemakerd_ipc(&pacemakerd_ipcs, &pacemakerd_proxy_callbacks);
 441     crmd_ipcs = pcmk__serve_controld_ipc(&crmd_proxy_callbacks);
 442     if (crmd_ipcs == NULL) {
 443         crm_err("Failed to create controller: exiting and inhibiting respawn");
 444         crm_warn("Verify pacemaker and pacemaker_remote are not both enabled");
 445         crm_exit(CRM_EX_FATAL);
 446     }
 447 }
 448 
 449 void
 450 ipc_proxy_cleanup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 451 {
 452     if (ipc_providers) {
 453         g_list_free(ipc_providers);
 454         ipc_providers = NULL;
 455     }
 456     if (ipc_clients) {
 457         g_hash_table_destroy(ipc_clients);
 458         ipc_clients = NULL;
 459     }
 460     pcmk__stop_based_ipc(cib_ro, cib_rw, cib_shm);
 461     qb_ipcs_destroy(attrd_ipcs);
 462     qb_ipcs_destroy(stonith_ipcs);
 463     qb_ipcs_destroy(pacemakerd_ipcs);
 464     qb_ipcs_destroy(crmd_ipcs);
 465     cib_ro = NULL;
 466     cib_rw = NULL;
 467     cib_shm = NULL;
 468 }

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