LCOV - code coverage report
Current view: top level - common - ipc_controld.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 246 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 22 0.0 %

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

Generated by: LCOV version 1.14