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-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 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(void)
     /* [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  * \param[in,out] ipc_proxy  IPC client connection to proxy provider
 286  *
 287  * \return 0 on success, -1 on error
 288  */
 289 int
 290 ipc_proxy_shutdown_req(pcmk__client_t *ipc_proxy)
     /* [previous][next][first][last][top][bottom][index][help] */
 291 {
 292     xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
 293     int rc;
 294 
 295     crm_xml_add(msg, F_LRMD_IPC_OP, LRMD_IPC_OP_SHUTDOWN_REQ);
 296 
 297     /* We don't really have a session, but the controller needs this attribute
 298      * to recognize this as proxy communication.
 299      */
 300     crm_xml_add(msg, F_LRMD_IPC_SESSION, "0");
 301 
 302     rc = (lrmd_server_send_notify(ipc_proxy, msg) != pcmk_rc_ok)? -1 : 0;
 303     free_xml(msg);
 304     return rc;
 305 }
 306 
 307 static int32_t
 308 ipc_proxy_closed(qb_ipcs_connection_t * c)
     /* [previous][next][first][last][top][bottom][index][help] */
 309 {
 310     pcmk__client_t *client = pcmk__find_client(c);
 311     pcmk__client_t *ipc_proxy;
 312 
 313     if (client == NULL) {
 314         return 0;
 315     }
 316 
 317     ipc_proxy = pcmk__find_client_by_id(client->userdata);
 318 
 319     crm_trace("Connection %p", c);
 320 
 321     if (ipc_proxy) {
 322         xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
 323         crm_xml_add(msg, F_LRMD_IPC_OP, LRMD_IPC_OP_DESTROY);
 324         crm_xml_add(msg, F_LRMD_IPC_SESSION, client->id);
 325         lrmd_server_send_notify(ipc_proxy, msg);
 326         free_xml(msg);
 327     }
 328 
 329     g_hash_table_remove(ipc_clients, client->id);
 330 
 331     free(client->userdata);
 332     client->userdata = NULL;
 333     pcmk__free_client(client);
 334     return 0;
 335 }
 336 
 337 static void
 338 ipc_proxy_destroy(qb_ipcs_connection_t * c)
     /* [previous][next][first][last][top][bottom][index][help] */
 339 {
 340     crm_trace("Connection %p", c);
 341     ipc_proxy_closed(c);
 342 }
 343 
 344 static struct qb_ipcs_service_handlers crmd_proxy_callbacks = {
 345     .connection_accept = crmd_proxy_accept,
 346     .connection_created = NULL,
 347     .msg_process = ipc_proxy_dispatch,
 348     .connection_closed = ipc_proxy_closed,
 349     .connection_destroyed = ipc_proxy_destroy
 350 };
 351 
 352 static struct qb_ipcs_service_handlers attrd_proxy_callbacks = {
 353     .connection_accept = attrd_proxy_accept,
 354     .connection_created = NULL,
 355     .msg_process = ipc_proxy_dispatch,
 356     .connection_closed = ipc_proxy_closed,
 357     .connection_destroyed = ipc_proxy_destroy
 358 };
 359 
 360 static struct qb_ipcs_service_handlers stonith_proxy_callbacks = {
 361     .connection_accept = stonith_proxy_accept,
 362     .connection_created = NULL,
 363     .msg_process = ipc_proxy_dispatch,
 364     .connection_closed = ipc_proxy_closed,
 365     .connection_destroyed = ipc_proxy_destroy
 366 };
 367 
 368 static struct qb_ipcs_service_handlers pacemakerd_proxy_callbacks = {
 369     .connection_accept = pacemakerd_proxy_accept,
 370     .connection_created = NULL,
 371     .msg_process = NULL,
 372     .connection_closed = NULL,
 373     .connection_destroyed = NULL
 374 };
 375 
 376 static struct qb_ipcs_service_handlers cib_proxy_callbacks_ro = {
 377     .connection_accept = cib_proxy_accept_ro,
 378     .connection_created = NULL,
 379     .msg_process = ipc_proxy_dispatch,
 380     .connection_closed = ipc_proxy_closed,
 381     .connection_destroyed = ipc_proxy_destroy
 382 };
 383 
 384 static struct qb_ipcs_service_handlers cib_proxy_callbacks_rw = {
 385     .connection_accept = cib_proxy_accept_rw,
 386     .connection_created = NULL,
 387     .msg_process = ipc_proxy_dispatch,
 388     .connection_closed = ipc_proxy_closed,
 389     .connection_destroyed = ipc_proxy_destroy
 390 };
 391 
 392 void
 393 ipc_proxy_add_provider(pcmk__client_t *ipc_proxy)
     /* [previous][next][first][last][top][bottom][index][help] */
 394 {
 395     // Prepending ensures the most recent connection is always first
 396     ipc_providers = g_list_prepend(ipc_providers, ipc_proxy);
 397 }
 398 
 399 void
 400 ipc_proxy_remove_provider(pcmk__client_t *ipc_proxy)
     /* [previous][next][first][last][top][bottom][index][help] */
 401 {
 402     GHashTableIter iter;
 403     pcmk__client_t *ipc_client = NULL;
 404     char *key = NULL;
 405     GList *remove_these = NULL;
 406     GList *gIter = NULL;
 407 
 408     ipc_providers = g_list_remove(ipc_providers, ipc_proxy);
 409 
 410     g_hash_table_iter_init(&iter, ipc_clients);
 411     while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & ipc_client)) {
 412         const char *proxy_id = ipc_client->userdata;
 413         if (pcmk__str_eq(proxy_id, ipc_proxy->id, pcmk__str_casei)) {
 414             crm_info("ipc proxy connection for client %s pid %d destroyed because cluster node disconnected.",
 415                 ipc_client->id, ipc_client->pid);
 416             /* we can't remove during the iteration, so copy items
 417              * to a list we can destroy later */
 418             remove_these = g_list_append(remove_these, ipc_client);
 419         }
 420     }
 421 
 422     for (gIter = remove_these; gIter != NULL; gIter = gIter->next) {
 423         ipc_client = gIter->data;
 424 
 425         // Disconnection callback will free the client here
 426         qb_ipcs_disconnect(ipc_client->ipcs);
 427     }
 428 
 429     /* just frees the list, not the elements in the list */
 430     g_list_free(remove_these);
 431 }
 432 
 433 void
 434 ipc_proxy_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 435 {
 436     ipc_clients = pcmk__strkey_table(NULL, NULL);
 437 
 438     pcmk__serve_based_ipc(&cib_ro, &cib_rw, &cib_shm, &cib_proxy_callbacks_ro,
 439                           &cib_proxy_callbacks_rw);
 440     pcmk__serve_attrd_ipc(&attrd_ipcs, &attrd_proxy_callbacks);
 441     pcmk__serve_fenced_ipc(&stonith_ipcs, &stonith_proxy_callbacks);
 442     pcmk__serve_pacemakerd_ipc(&pacemakerd_ipcs, &pacemakerd_proxy_callbacks);
 443     crmd_ipcs = pcmk__serve_controld_ipc(&crmd_proxy_callbacks);
 444     if (crmd_ipcs == NULL) {
 445         crm_err("Failed to create controller: exiting and inhibiting respawn");
 446         crm_warn("Verify pacemaker and pacemaker_remote are not both enabled");
 447         crm_exit(CRM_EX_FATAL);
 448     }
 449 }
 450 
 451 void
 452 ipc_proxy_cleanup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 453 {
 454     if (ipc_providers) {
 455         g_list_free(ipc_providers);
 456         ipc_providers = NULL;
 457     }
 458     if (ipc_clients) {
 459         g_hash_table_destroy(ipc_clients);
 460         ipc_clients = NULL;
 461     }
 462     pcmk__stop_based_ipc(cib_ro, cib_rw, cib_shm);
 463     qb_ipcs_destroy(attrd_ipcs);
 464     qb_ipcs_destroy(stonith_ipcs);
 465     qb_ipcs_destroy(pacemakerd_ipcs);
 466     qb_ipcs_destroy(crmd_ipcs);
 467     cib_ro = NULL;
 468     cib_rw = NULL;
 469     cib_shm = NULL;
 470 }

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