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

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