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. controller_resource_op
  18. pcmk_controld_api_fail
  19. pcmk_controld_api_refresh
  20. pcmk_controld_api_replies_expected
  21. create_hello_message

   1 /*
   2  * Copyright 2020-2021 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <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 // \return Standard Pacemaker return code
 434 static int
 435 controller_resource_op(pcmk_ipc_api_t *api, const char *op,
     /* [previous][next][first][last][top][bottom][index][help] */
 436                        const char *target_node, const char *router_node,
 437                        bool cib_only, const char *rsc_id,
 438                        const char *rsc_long_id, const char *standard,
 439                        const char *provider, const char *type)
 440 {
 441     int rc = pcmk_rc_ok;
 442     char *key;
 443     xmlNode *request, *msg_data, *xml_rsc, *params;
 444 
 445     if (api == NULL) {
 446         return EINVAL;
 447     }
 448     if (router_node == NULL) {
 449         router_node = target_node;
 450     }
 451 
 452     msg_data = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP);
 453 
 454     /* The controller logs the transition key from resource op requests, so we
 455      * need to have *something* for it.
 456      * @TODO don't use "crm-resource"
 457      */
 458     key = pcmk__transition_key(0, getpid(), 0,
 459                                "xxxxxxxx-xrsc-opxx-xcrm-resourcexxxx");
 460     crm_xml_add(msg_data, XML_ATTR_TRANSITION_KEY, key);
 461     free(key);
 462 
 463     crm_xml_add(msg_data, XML_LRM_ATTR_TARGET, target_node);
 464     if (!pcmk__str_eq(router_node, target_node, pcmk__str_casei)) {
 465         crm_xml_add(msg_data, XML_LRM_ATTR_ROUTER_NODE, router_node);
 466     }
 467 
 468     if (cib_only) {
 469         // Indicate that only the CIB needs to be cleaned
 470         crm_xml_add(msg_data, PCMK__XA_MODE, XML_TAG_CIB);
 471     }
 472 
 473     xml_rsc = create_xml_node(msg_data, XML_CIB_TAG_RESOURCE);
 474     crm_xml_add(xml_rsc, XML_ATTR_ID, rsc_id);
 475     crm_xml_add(xml_rsc, XML_ATTR_ID_LONG, rsc_long_id);
 476     crm_xml_add(xml_rsc, XML_AGENT_ATTR_CLASS, standard);
 477     crm_xml_add(xml_rsc, XML_AGENT_ATTR_PROVIDER, provider);
 478     crm_xml_add(xml_rsc, XML_ATTR_TYPE, type);
 479 
 480     params = create_xml_node(msg_data, XML_TAG_ATTRS);
 481     crm_xml_add(params, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
 482 
 483     // The controller parses the timeout from the request
 484     key = crm_meta_name(XML_ATTR_TIMEOUT);
 485     crm_xml_add(params, key, "60000");  /* 1 minute */ //@TODO pass as arg
 486     free(key);
 487 
 488     request = create_controller_request(api, op, router_node, msg_data);
 489     rc = send_controller_request(api, request, true);
 490     free_xml(msg_data);
 491     free_xml(request);
 492     return rc;
 493 }
 494 
 495 /*!
 496  * \brief Ask the controller to fail a resource
 497  *
 498  * \param[in] api          Controller connection
 499  * \param[in] target_node  Name of node resource is on
 500  * \param[in] router_node  Router node for target
 501  * \param[in] rsc_id       ID of resource to fail
 502  * \param[in] rsc_long_id  Long ID of resource (if any)
 503  * \param[in] standard     Standard of resource
 504  * \param[in] provider     Provider of resource (if any)
 505  * \param[in] type         Type of resource to fail
 506  *
 507  * \return Standard Pacemaker return code
 508  * \note Event callback will get a reply of type pcmk_controld_reply_resource.
 509  */
 510 int
 511 pcmk_controld_api_fail(pcmk_ipc_api_t *api,
     /* [previous][next][first][last][top][bottom][index][help] */
 512                        const char *target_node, const char *router_node,
 513                        const char *rsc_id, const char *rsc_long_id,
 514                        const char *standard, const char *provider,
 515                        const char *type)
 516 {
 517     crm_debug("Sending %s IPC request to fail %s (a.k.a. %s) on %s via %s",
 518               pcmk_ipc_name(api, true), crm_str(rsc_id), crm_str(rsc_long_id),
 519               crm_str(target_node), crm_str(router_node));
 520     return controller_resource_op(api, CRM_OP_LRM_FAIL, target_node,
 521                                   router_node, false, rsc_id, rsc_long_id,
 522                                   standard, provider, type);
 523 }
 524 
 525 /*!
 526  * \brief Ask the controller to refresh a resource
 527  *
 528  * \param[in] api          Controller connection
 529  * \param[in] target_node  Name of node resource is on
 530  * \param[in] router_node  Router node for target
 531  * \param[in] rsc_id       ID of resource to refresh
 532  * \param[in] rsc_long_id  Long ID of resource (if any)
 533  * \param[in] standard     Standard of resource
 534  * \param[in] provider     Provider of resource (if any)
 535  * \param[in] type         Type of resource
 536  * \param[in] cib_only     If true, clean resource from CIB only
 537  *
 538  * \return Standard Pacemaker return code
 539  * \note Event callback will get a reply of type pcmk_controld_reply_resource.
 540  */
 541 int
 542 pcmk_controld_api_refresh(pcmk_ipc_api_t *api, const char *target_node,
     /* [previous][next][first][last][top][bottom][index][help] */
 543                           const char *router_node,
 544                           const char *rsc_id, const char *rsc_long_id,
 545                           const char *standard, const char *provider,
 546                           const char *type, bool cib_only)
 547 {
 548     crm_debug("Sending %s IPC request to refresh %s (a.k.a. %s) on %s via %s",
 549               pcmk_ipc_name(api, true), crm_str(rsc_id), crm_str(rsc_long_id),
 550               crm_str(target_node), crm_str(router_node));
 551     return controller_resource_op(api, CRM_OP_LRM_DELETE, target_node,
 552                                   router_node, cib_only, rsc_id, rsc_long_id,
 553                                   standard, provider, type);
 554 }
 555 
 556 /*!
 557  * \brief Get the number of IPC replies currently expected from the controller
 558  *
 559  * \param[in] api  Controller IPC API connection
 560  *
 561  * \return Number of replies expected
 562  */
 563 unsigned int
 564 pcmk_controld_api_replies_expected(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 565 {
 566     struct controld_api_private_s *private = api->api_data;
 567 
 568     return private->replies_expected;
 569 }
 570 
 571 /*!
 572  * \brief Create XML for a controller IPC "hello" message
 573  *
 574  * \deprecated This function is deprecated as part of the public C API.
 575  */
 576 // \todo make this static to this file when breaking API backward compatibility
 577 xmlNode *
 578 create_hello_message(const char *uuid, const char *client_name,
     /* [previous][next][first][last][top][bottom][index][help] */
 579                      const char *major_version, const char *minor_version)
 580 {
 581     xmlNode *hello_node = NULL;
 582     xmlNode *hello = NULL;
 583 
 584     if (pcmk__str_empty(uuid) || pcmk__str_empty(client_name)
 585         || pcmk__str_empty(major_version) || pcmk__str_empty(minor_version)) {
 586         crm_err("Could not create IPC hello message from %s (UUID %s): "
 587                 "missing information",
 588                 client_name? client_name : "unknown client",
 589                 uuid? uuid : "unknown");
 590         return NULL;
 591     }
 592 
 593     hello_node = create_xml_node(NULL, XML_TAG_OPTIONS);
 594     if (hello_node == NULL) {
 595         crm_err("Could not create IPC hello message from %s (UUID %s): "
 596                 "Message data creation failed", client_name, uuid);
 597         return NULL;
 598     }
 599 
 600     crm_xml_add(hello_node, "major_version", major_version);
 601     crm_xml_add(hello_node, "minor_version", minor_version);
 602     crm_xml_add(hello_node, "client_name", client_name);
 603     crm_xml_add(hello_node, "client_uuid", uuid);
 604 
 605     hello = create_request(CRM_OP_HELLO, hello_node, NULL, NULL, client_name, uuid);
 606     if (hello == NULL) {
 607         crm_err("Could not create IPC hello message from %s (UUID %s): "
 608                 "Request creation failed", client_name, uuid);
 609         return NULL;
 610     }
 611     free_xml(hello_node);
 612 
 613     crm_trace("Created hello message from %s (UUID %s)", client_name, uuid);
 614     return hello;
 615 }

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