root/lib/common/ipc_controld.c

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

DEFINITIONS

This source file includes following definitions.
  1. pcmk__controld_api_reply2str
  2. new_data
  3. free_data
  4. post_connect
  5. set_node_info_data
  6. set_ping_data
  7. set_nodes_data
  8. reply_expected
  9. dispatch
  10. pcmk__controld_api_methods
  11. create_controller_request
  12. send_controller_request
  13. create_reprobe_message_data
  14. pcmk_controld_api_reprobe
  15. pcmk_controld_api_node_info
  16. pcmk_controld_api_ping
  17. pcmk_controld_api_list_nodes
  18. controller_resource_op
  19. pcmk_controld_api_fail
  20. pcmk_controld_api_refresh
  21. pcmk_controld_api_replies_expected
  22. create_hello_message

   1 /*
   2  * Copyright 2020-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 <errno.h>
  13 #include <inttypes.h>                   // PRIu32
  14 #include <stdbool.h>
  15 #include <stdint.h>                     // uint32_t
  16 #include <stdio.h>
  17 
  18 #include <libxml/tree.h>
  19 
  20 #include <crm/crm.h>
  21 #include <crm/common/xml.h>
  22 #include <crm/common/ipc.h>
  23 #include <crm/common/ipc_internal.h>
  24 #include <crm/common/ipc_controld.h>
  25 #include "crmcommon_private.h"
  26 
  27 struct controld_api_private_s {
  28     char *client_uuid;
  29     unsigned int replies_expected;
  30 };
  31 
  32 /*!
  33  * \internal
  34  * \brief Get a string representation of a controller API reply type
  35  *
  36  * \param[in] reply  Controller API reply type
  37  *
  38  * \return String representation of a controller API reply type
  39  */
  40 const char *
  41 pcmk__controld_api_reply2str(enum pcmk_controld_api_reply reply)
     /* [previous][next][first][last][top][bottom][index][help] */
  42 {
  43     switch (reply) {
  44         case pcmk_controld_reply_reprobe:
  45             return "reprobe";
  46         case pcmk_controld_reply_info:
  47             return "info";
  48         case pcmk_controld_reply_resource:
  49             return "resource";
  50         case pcmk_controld_reply_ping:
  51             return "ping";
  52         case pcmk_controld_reply_nodes:
  53             return "nodes";
  54         default:
  55             return "unknown";
  56     }
  57 }
  58 
  59 // \return Standard Pacemaker return code
  60 static int
  61 new_data(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
  62 {
  63     struct controld_api_private_s *private = NULL;
  64 
  65     api->api_data = calloc(1, sizeof(struct controld_api_private_s));
  66 
  67     if (api->api_data == NULL) {
  68         return errno;
  69     }
  70 
  71     private = api->api_data;
  72 
  73     /* This is set to the PID because that's how it was always done, but PIDs
  74      * are not unique because clients can be remote. The value appears to be
  75      * unused other than as part of PCMK__XA_CRM_SYS_FROM in IPC requests, which
  76      * is only compared against the internal system names (CRM_SYSTEM_TENGINE,
  77      * etc.), so it shouldn't be a problem.
  78      */
  79     private->client_uuid = pcmk__getpid_s();
  80 
  81     /* @TODO Implement a call ID model similar to the CIB, executor, and fencer
  82      *       IPC APIs, so that requests and replies can be matched, and
  83      *       duplicate replies can be discarded.
  84      */
  85     return pcmk_rc_ok;
  86 }
  87 
  88 static void
  89 free_data(void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91     free(((struct controld_api_private_s *) data)->client_uuid);
  92     free(data);
  93 }
  94 
  95 // \return Standard Pacemaker return code
  96 static int
  97 post_connect(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
  98 {
  99     /* The controller currently requires clients to register via a hello
 100      * request, but does not reply back.
 101      */
 102     struct controld_api_private_s *private = api->api_data;
 103     const char *client_name = crm_system_name? crm_system_name : "client";
 104     xmlNode *hello;
 105     int rc;
 106 
 107     hello = create_hello_message(private->client_uuid, client_name,
 108                                  PCMK__CONTROLD_API_MAJOR,
 109                                  PCMK__CONTROLD_API_MINOR);
 110     rc = pcmk__send_ipc_request(api, hello);
 111     free_xml(hello);
 112     if (rc != pcmk_rc_ok) {
 113         crm_info("Could not send IPC hello to %s: %s " CRM_XS " rc=%s",
 114                  pcmk_ipc_name(api, true), pcmk_rc_str(rc), rc);
 115     } else {
 116         crm_debug("Sent IPC hello to %s", pcmk_ipc_name(api, true));
 117     }
 118     return rc;
 119 }
 120 
 121 static void
 122 set_node_info_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 123 {
 124     data->reply_type = pcmk_controld_reply_info;
 125     if (msg_data == NULL) {
 126         return;
 127     }
 128     data->data.node_info.have_quorum =
 129         pcmk__xe_attr_is_true(msg_data, PCMK_XA_HAVE_QUORUM);
 130     data->data.node_info.is_remote =
 131         pcmk__xe_attr_is_true(msg_data, PCMK_XA_REMOTE_NODE);
 132 
 133     /* Integer node_info.id is currently valid only for Corosync nodes.
 134      *
 135      * @TODO: Improve handling after crm_node_t is refactored to handle layer-
 136      * specific data better.
 137      */
 138     crm_element_value_int(msg_data, PCMK_XA_ID, &(data->data.node_info.id));
 139 
 140     data->data.node_info.uuid = crm_element_value(msg_data, PCMK_XA_ID);
 141     data->data.node_info.uname = crm_element_value(msg_data, PCMK_XA_UNAME);
 142     data->data.node_info.state = crm_element_value(msg_data, PCMK_XA_CRMD);
 143 }
 144 
 145 static void
 146 set_ping_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 147 {
 148     data->reply_type = pcmk_controld_reply_ping;
 149     if (msg_data == NULL) {
 150         return;
 151     }
 152     data->data.ping.sys_from = crm_element_value(msg_data,
 153                                                  PCMK__XA_CRM_SUBSYSTEM);
 154     data->data.ping.fsa_state = crm_element_value(msg_data,
 155                                                   PCMK__XA_CRMD_STATE);
 156     data->data.ping.result = crm_element_value(msg_data, PCMK_XA_RESULT);
 157 }
 158 
 159 static void
 160 set_nodes_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 161 {
 162     pcmk_controld_api_node_t *node_info;
 163 
 164     data->reply_type = pcmk_controld_reply_nodes;
 165     for (xmlNode *node = pcmk__xe_first_child(msg_data, PCMK_XE_NODE, NULL,
 166                                               NULL);
 167          node != NULL; node = pcmk__xe_next_same(node)) {
 168 
 169         long long id_ll = 0;
 170 
 171         node_info = pcmk__assert_alloc(1, sizeof(pcmk_controld_api_node_t));
 172         crm_element_value_ll(node, PCMK_XA_ID, &id_ll);
 173         if (id_ll > 0) {
 174             node_info->id = id_ll;
 175         }
 176         node_info->uname = crm_element_value(node, PCMK_XA_UNAME);
 177         node_info->state = crm_element_value(node, PCMK__XA_IN_CCM);
 178         data->data.nodes = g_list_prepend(data->data.nodes, node_info);
 179     }
 180 }
 181 
 182 static bool
 183 reply_expected(pcmk_ipc_api_t *api, const xmlNode *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 184 {
 185     // We only need to handle commands that API functions can send
 186     return pcmk__str_any_of(crm_element_value(request, PCMK__XA_CRM_TASK),
 187                             PCMK__CONTROLD_CMD_NODES,
 188                             CRM_OP_LRM_DELETE,
 189                             CRM_OP_LRM_FAIL,
 190                             CRM_OP_NODE_INFO,
 191                             CRM_OP_PING,
 192                             CRM_OP_REPROBE,
 193                             CRM_OP_RM_NODE_CACHE,
 194                             NULL);
 195 }
 196 
 197 static bool
 198 dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
     /* [previous][next][first][last][top][bottom][index][help] */
 199 {
 200     struct controld_api_private_s *private = api->api_data;
 201     crm_exit_t status = CRM_EX_OK;
 202     xmlNode *wrapper = NULL;
 203     xmlNode *msg_data = NULL;
 204     const char *value = NULL;
 205     pcmk_controld_api_reply_t reply_data = {
 206         pcmk_controld_reply_unknown, NULL, NULL,
 207     };
 208 
 209     if (pcmk__xe_is(reply, PCMK__XE_ACK)) {
 210         /* ACKs are trivial responses that do not count toward expected replies,
 211          * and do not have all the fields that validation requires, so skip that
 212          * processing.
 213          */
 214         return private->replies_expected > 0;
 215     }
 216 
 217     if (private->replies_expected > 0) {
 218         private->replies_expected--;
 219     }
 220 
 221     // Do some basic validation of the reply
 222 
 223     /* @TODO We should be able to verify that value is always a response, but
 224      *       currently the controller doesn't always properly set the type. Even
 225      *       if we fix the controller, we'll still need to handle replies from
 226      *       old versions (feature set could be used to differentiate).
 227      */
 228     value = crm_element_value(reply, PCMK__XA_SUBT);
 229     if (!pcmk__str_any_of(value, PCMK__VALUE_REQUEST, PCMK__VALUE_RESPONSE,
 230                           NULL)) {
 231         crm_info("Unrecognizable message from controller: "
 232                  "invalid message type '%s'", pcmk__s(value, ""));
 233         status = CRM_EX_PROTOCOL;
 234         goto done;
 235     }
 236 
 237     if (pcmk__str_empty(crm_element_value(reply, PCMK_XA_REFERENCE))) {
 238         crm_info("Unrecognizable message from controller: no reference");
 239         status = CRM_EX_PROTOCOL;
 240         goto done;
 241     }
 242 
 243     value = crm_element_value(reply, PCMK__XA_CRM_TASK);
 244     if (pcmk__str_empty(value)) {
 245         crm_info("Unrecognizable message from controller: no command name");
 246         status = CRM_EX_PROTOCOL;
 247         goto done;
 248     }
 249 
 250     // Parse useful info from reply
 251 
 252     reply_data.feature_set = crm_element_value(reply, PCMK_XA_VERSION);
 253     reply_data.host_from = crm_element_value(reply, PCMK__XA_SRC);
 254 
 255     wrapper = pcmk__xe_first_child(reply, PCMK__XE_CRM_XML, NULL, NULL);
 256     msg_data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
 257 
 258     if (!strcmp(value, CRM_OP_REPROBE)) {
 259         reply_data.reply_type = pcmk_controld_reply_reprobe;
 260 
 261     } else if (!strcmp(value, CRM_OP_NODE_INFO)) {
 262         set_node_info_data(&reply_data, msg_data);
 263 
 264     } else if (!strcmp(value, CRM_OP_INVOKE_LRM)) {
 265         reply_data.reply_type = pcmk_controld_reply_resource;
 266         reply_data.data.resource.node_state = msg_data;
 267 
 268     } else if (!strcmp(value, CRM_OP_PING)) {
 269         set_ping_data(&reply_data, msg_data);
 270 
 271     } else if (!strcmp(value, PCMK__CONTROLD_CMD_NODES)) {
 272         set_nodes_data(&reply_data, msg_data);
 273 
 274     } else {
 275         crm_info("Unrecognizable message from controller: unknown command '%s'",
 276                  value);
 277         status = CRM_EX_PROTOCOL;
 278     }
 279 
 280 done:
 281     pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
 282 
 283     // Free any reply data that was allocated
 284     if (pcmk__str_eq(value, PCMK__CONTROLD_CMD_NODES, pcmk__str_casei)) {
 285         g_list_free_full(reply_data.data.nodes, free);
 286     }
 287 
 288     return false; // No further replies needed
 289 }
 290 
 291 pcmk__ipc_methods_t *
 292 pcmk__controld_api_methods(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 293 {
 294     pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
 295 
 296     if (cmds != NULL) {
 297         cmds->new_data = new_data;
 298         cmds->free_data = free_data;
 299         cmds->post_connect = post_connect;
 300         cmds->reply_expected = reply_expected;
 301         cmds->dispatch = dispatch;
 302     }
 303     return cmds;
 304 }
 305 
 306 /*!
 307  * \internal
 308  * \brief Create XML for a controller IPC request
 309  *
 310  * \param[in] api       Controller connection
 311  * \param[in] op        Controller IPC command name
 312  * \param[in] node      Node name to set as destination host
 313  * \param[in] msg_data  XML to attach to request as message data
 314  *
 315  * \return Newly allocated XML for request
 316  */
 317 static xmlNode *
 318 create_controller_request(const pcmk_ipc_api_t *api, const char *op,
     /* [previous][next][first][last][top][bottom][index][help] */
 319                           const char *node, xmlNode *msg_data)
 320 {
 321     struct controld_api_private_s *private = NULL;
 322     const char *sys_to = NULL;
 323 
 324     if (api == NULL) {
 325         return NULL;
 326     }
 327     private = api->api_data;
 328     if ((node == NULL) && !strcmp(op, CRM_OP_PING)) {
 329         sys_to = CRM_SYSTEM_DC;
 330     } else {
 331         sys_to = CRM_SYSTEM_CRMD;
 332     }
 333     return create_request(op, msg_data, node, sys_to,
 334                           (crm_system_name? crm_system_name : "client"),
 335                           private->client_uuid);
 336 }
 337 
 338 // \return Standard Pacemaker return code
 339 static int
 340 send_controller_request(pcmk_ipc_api_t *api, const xmlNode *request,
     /* [previous][next][first][last][top][bottom][index][help] */
 341                         bool reply_is_expected)
 342 {
 343     if (crm_element_value(request, PCMK_XA_REFERENCE) == NULL) {
 344         return EINVAL;
 345     }
 346     if (reply_is_expected) {
 347         struct controld_api_private_s *private = api->api_data;
 348 
 349         private->replies_expected++;
 350     }
 351     return pcmk__send_ipc_request(api, request);
 352 }
 353 
 354 static xmlNode *
 355 create_reprobe_message_data(const char *target_node, const char *router_node)
     /* [previous][next][first][last][top][bottom][index][help] */
 356 {
 357     xmlNode *msg_data;
 358 
 359     msg_data = pcmk__xe_create(NULL, "data_for_" CRM_OP_REPROBE);
 360     crm_xml_add(msg_data, PCMK__META_ON_NODE, target_node);
 361     if ((router_node != NULL) && !pcmk__str_eq(router_node, target_node, pcmk__str_casei)) {
 362         crm_xml_add(msg_data, PCMK__XA_ROUTER_NODE, router_node);
 363     }
 364     return msg_data;
 365 }
 366 
 367 /*!
 368  * \brief Send a reprobe controller operation
 369  *
 370  * \param[in,out] api          Controller connection
 371  * \param[in]     target_node  Name of node to reprobe
 372  * \param[in]     router_node  Router node for host
 373  *
 374  * \return Standard Pacemaker return code
 375  * \note Event callback will get a reply of type pcmk_controld_reply_reprobe.
 376  */
 377 int
 378 pcmk_controld_api_reprobe(pcmk_ipc_api_t *api, const char *target_node,
     /* [previous][next][first][last][top][bottom][index][help] */
 379                           const char *router_node)
 380 {
 381     xmlNode *request;
 382     xmlNode *msg_data;
 383     int rc = pcmk_rc_ok;
 384 
 385     if (api == NULL) {
 386         return EINVAL;
 387     }
 388     if (router_node == NULL) {
 389         router_node = target_node;
 390     }
 391     crm_debug("Sending %s IPC request to reprobe %s via %s",
 392               pcmk_ipc_name(api, true), pcmk__s(target_node, "local node"),
 393               pcmk__s(router_node, "local node"));
 394     msg_data = create_reprobe_message_data(target_node, router_node);
 395     request = create_controller_request(api, CRM_OP_REPROBE, router_node,
 396                                         msg_data);
 397     rc = send_controller_request(api, request, true);
 398     free_xml(msg_data);
 399     free_xml(request);
 400     return rc;
 401 }
 402 
 403 /*!
 404  * \brief Send a "node info" controller operation
 405  *
 406  * \param[in,out] api     Controller connection
 407  * \param[in]     nodeid  ID of node to get info for (or 0 for local node)
 408  *
 409  * \return Standard Pacemaker return code
 410  * \note Event callback will get a reply of type pcmk_controld_reply_info.
 411  */
 412 int
 413 pcmk_controld_api_node_info(pcmk_ipc_api_t *api, uint32_t nodeid)
     /* [previous][next][first][last][top][bottom][index][help] */
 414 {
 415     xmlNode *request;
 416     int rc = pcmk_rc_ok;
 417 
 418     request = create_controller_request(api, CRM_OP_NODE_INFO, NULL, NULL);
 419     if (request == NULL) {
 420         return EINVAL;
 421     }
 422     if (nodeid > 0) {
 423         crm_xml_add_ll(request, PCMK_XA_ID, nodeid);
 424     }
 425 
 426     rc = send_controller_request(api, request, true);
 427     free_xml(request);
 428     return rc;
 429 }
 430 
 431 /*!
 432  * \brief Ask the controller for status
 433  *
 434  * \param[in,out] api        Controller connection
 435  * \param[in]     node_name  Name of node whose status is desired (NULL for DC)
 436  *
 437  * \return Standard Pacemaker return code
 438  * \note Event callback will get a reply of type pcmk_controld_reply_ping.
 439  */
 440 int
 441 pcmk_controld_api_ping(pcmk_ipc_api_t *api, const char *node_name)
     /* [previous][next][first][last][top][bottom][index][help] */
 442 {
 443     xmlNode *request;
 444     int rc = pcmk_rc_ok;
 445 
 446     request = create_controller_request(api, CRM_OP_PING, node_name, NULL);
 447     if (request == NULL) {
 448         return EINVAL;
 449     }
 450     rc = send_controller_request(api, request, true);
 451     free_xml(request);
 452     return rc;
 453 }
 454 
 455 /*!
 456  * \brief Ask the controller for cluster information
 457  *
 458  * \param[in,out] api  Controller connection
 459  *
 460  * \return Standard Pacemaker return code
 461  * \note Event callback will get a reply of type pcmk_controld_reply_nodes.
 462  */
 463 int
 464 pcmk_controld_api_list_nodes(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 465 {
 466     xmlNode *request;
 467     int rc = EINVAL;
 468 
 469     request = create_controller_request(api, PCMK__CONTROLD_CMD_NODES, NULL,
 470                                         NULL);
 471     if (request != NULL) {
 472         rc = send_controller_request(api, request, true);
 473         free_xml(request);
 474     }
 475     return rc;
 476 }
 477 
 478 // \return Standard Pacemaker return code
 479 static int
 480 controller_resource_op(pcmk_ipc_api_t *api, const char *op,
     /* [previous][next][first][last][top][bottom][index][help] */
 481                        const char *target_node, const char *router_node,
 482                        bool cib_only, const char *rsc_id,
 483                        const char *rsc_long_id, const char *standard,
 484                        const char *provider, const char *type)
 485 {
 486     int rc = pcmk_rc_ok;
 487     char *key;
 488     xmlNode *request, *msg_data, *xml_rsc, *params;
 489 
 490     if (api == NULL) {
 491         return EINVAL;
 492     }
 493     if (router_node == NULL) {
 494         router_node = target_node;
 495     }
 496 
 497     msg_data = pcmk__xe_create(NULL, PCMK__XE_RSC_OP);
 498 
 499     /* The controller logs the transition key from resource op requests, so we
 500      * need to have *something* for it.
 501      * @TODO don't use "crm-resource"
 502      */
 503     key = pcmk__transition_key(0, getpid(), 0,
 504                                "xxxxxxxx-xrsc-opxx-xcrm-resourcexxxx");
 505     crm_xml_add(msg_data, PCMK__XA_TRANSITION_KEY, key);
 506     free(key);
 507 
 508     crm_xml_add(msg_data, PCMK__META_ON_NODE, target_node);
 509     if (!pcmk__str_eq(router_node, target_node, pcmk__str_casei)) {
 510         crm_xml_add(msg_data, PCMK__XA_ROUTER_NODE, router_node);
 511     }
 512 
 513     if (cib_only) {
 514         // Indicate that only the CIB needs to be cleaned
 515         crm_xml_add(msg_data, PCMK__XA_MODE, PCMK__VALUE_CIB);
 516     }
 517 
 518     xml_rsc = pcmk__xe_create(msg_data, PCMK_XE_PRIMITIVE);
 519     crm_xml_add(xml_rsc, PCMK_XA_ID, rsc_id);
 520     crm_xml_add(xml_rsc, PCMK__XA_LONG_ID, rsc_long_id);
 521     crm_xml_add(xml_rsc, PCMK_XA_CLASS, standard);
 522     crm_xml_add(xml_rsc, PCMK_XA_PROVIDER, provider);
 523     crm_xml_add(xml_rsc, PCMK_XA_TYPE, type);
 524 
 525     params = pcmk__xe_create(msg_data, PCMK__XE_ATTRIBUTES);
 526     crm_xml_add(params, PCMK_XA_CRM_FEATURE_SET, CRM_FEATURE_SET);
 527 
 528     // The controller parses the timeout from the request
 529     key = crm_meta_name(PCMK_META_TIMEOUT);
 530     crm_xml_add(params, key, "60000");  /* 1 minute */ //@TODO pass as arg
 531     free(key);
 532 
 533     request = create_controller_request(api, op, router_node, msg_data);
 534     rc = send_controller_request(api, request, true);
 535     free_xml(msg_data);
 536     free_xml(request);
 537     return rc;
 538 }
 539 
 540 /*!
 541  * \brief Ask the controller to fail a resource
 542  *
 543  * \param[in,out] api          Controller connection
 544  * \param[in]     target_node  Name of node resource is on
 545  * \param[in]     router_node  Router node for target
 546  * \param[in]     rsc_id       ID of resource to fail
 547  * \param[in]     rsc_long_id  Long ID of resource (if any)
 548  * \param[in]     standard     Standard of resource
 549  * \param[in]     provider     Provider of resource (if any)
 550  * \param[in]     type         Type of resource to fail
 551  *
 552  * \return Standard Pacemaker return code
 553  * \note Event callback will get a reply of type pcmk_controld_reply_resource.
 554  */
 555 int
 556 pcmk_controld_api_fail(pcmk_ipc_api_t *api,
     /* [previous][next][first][last][top][bottom][index][help] */
 557                        const char *target_node, const char *router_node,
 558                        const char *rsc_id, const char *rsc_long_id,
 559                        const char *standard, const char *provider,
 560                        const char *type)
 561 {
 562     crm_debug("Sending %s IPC request to fail %s (a.k.a. %s) on %s via %s",
 563               pcmk_ipc_name(api, true), pcmk__s(rsc_id, "unknown resource"),
 564               pcmk__s(rsc_long_id, "no other names"),
 565               pcmk__s(target_node, "unspecified node"),
 566               pcmk__s(router_node, "unspecified node"));
 567     return controller_resource_op(api, CRM_OP_LRM_FAIL, target_node,
 568                                   router_node, false, rsc_id, rsc_long_id,
 569                                   standard, provider, type);
 570 }
 571 
 572 /*!
 573  * \brief Ask the controller to refresh a resource
 574  *
 575  * \param[in,out] api          Controller connection
 576  * \param[in]     target_node  Name of node resource is on
 577  * \param[in]     router_node  Router node for target
 578  * \param[in]     rsc_id       ID of resource to refresh
 579  * \param[in]     rsc_long_id  Long ID of resource (if any)
 580  * \param[in]     standard     Standard of resource
 581  * \param[in]     provider     Provider of resource (if any)
 582  * \param[in]     type         Type of resource
 583  * \param[in]     cib_only     If true, clean resource from CIB only
 584  *
 585  * \return Standard Pacemaker return code
 586  * \note Event callback will get a reply of type pcmk_controld_reply_resource.
 587  */
 588 int
 589 pcmk_controld_api_refresh(pcmk_ipc_api_t *api, const char *target_node,
     /* [previous][next][first][last][top][bottom][index][help] */
 590                           const char *router_node,
 591                           const char *rsc_id, const char *rsc_long_id,
 592                           const char *standard, const char *provider,
 593                           const char *type, bool cib_only)
 594 {
 595     crm_debug("Sending %s IPC request to refresh %s (a.k.a. %s) on %s via %s",
 596               pcmk_ipc_name(api, true), pcmk__s(rsc_id, "unknown resource"),
 597               pcmk__s(rsc_long_id, "no other names"),
 598               pcmk__s(target_node, "unspecified node"),
 599               pcmk__s(router_node, "unspecified node"));
 600     return controller_resource_op(api, CRM_OP_LRM_DELETE, target_node,
 601                                   router_node, cib_only, rsc_id, rsc_long_id,
 602                                   standard, provider, type);
 603 }
 604 
 605 /*!
 606  * \brief Get the number of IPC replies currently expected from the controller
 607  *
 608  * \param[in] api  Controller IPC API connection
 609  *
 610  * \return Number of replies expected
 611  */
 612 unsigned int
 613 pcmk_controld_api_replies_expected(const pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 614 {
 615     struct controld_api_private_s *private = api->api_data;
 616 
 617     return private->replies_expected;
 618 }
 619 
 620 /*!
 621  * \brief Create XML for a controller IPC "hello" message
 622  *
 623  * \deprecated This function is deprecated as part of the public C API.
 624  */
 625 // \todo make this static to this file when breaking API backward compatibility
 626 xmlNode *
 627 create_hello_message(const char *uuid, const char *client_name,
     /* [previous][next][first][last][top][bottom][index][help] */
 628                      const char *major_version, const char *minor_version)
 629 {
 630     xmlNode *hello_node = NULL;
 631     xmlNode *hello = NULL;
 632 
 633     if (pcmk__str_empty(uuid) || pcmk__str_empty(client_name)
 634         || pcmk__str_empty(major_version) || pcmk__str_empty(minor_version)) {
 635         crm_err("Could not create IPC hello message from %s (UUID %s): "
 636                 "missing information",
 637                 client_name? client_name : "unknown client",
 638                 uuid? uuid : "unknown");
 639         return NULL;
 640     }
 641 
 642     hello_node = pcmk__xe_create(NULL, PCMK__XE_OPTIONS);
 643     crm_xml_add(hello_node, PCMK__XA_MAJOR_VERSION, major_version);
 644     crm_xml_add(hello_node, PCMK__XA_MINOR_VERSION, minor_version);
 645     crm_xml_add(hello_node, PCMK__XA_CLIENT_NAME, client_name);
 646 
 647     // @TODO Nothing uses this. Drop, or keep for debugging?
 648     crm_xml_add(hello_node, PCMK__XA_CLIENT_UUID, uuid);
 649 
 650     hello = create_request(CRM_OP_HELLO, hello_node, NULL, NULL, client_name, uuid);
 651     if (hello == NULL) {
 652         crm_err("Could not create IPC hello message from %s (UUID %s): "
 653                 "Request creation failed", client_name, uuid);
 654         return NULL;
 655     }
 656     free_xml(hello_node);
 657 
 658     crm_trace("Created hello message from %s (UUID %s)", client_name, uuid);
 659     return hello;
 660 }

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