root/lib/common/ipc_controld.c

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

DEFINITIONS

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

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

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