LCOV - code coverage report
Current view: top level - common - ipc_pacemakerd.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 141 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 14 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 <stdlib.h>
      13             : #include <time.h>
      14             : 
      15             : #include <crm/crm.h>
      16             : #include <crm/common/xml.h>
      17             : #include <crm/common/ipc.h>
      18             : #include <crm/common/ipc_internal.h>
      19             : #include <crm/common/ipc_pacemakerd.h>
      20             : #include "crmcommon_private.h"
      21             : 
      22             : typedef struct pacemakerd_api_private_s {
      23             :     enum pcmk_pacemakerd_state state;
      24             :     char *client_uuid;
      25             : } pacemakerd_api_private_t;
      26             : 
      27             : static const char *pacemakerd_state_str[] = {
      28             :     PCMK__VALUE_INIT,
      29             :     PCMK__VALUE_STARTING_DAEMONS,
      30             :     PCMK__VALUE_WAIT_FOR_PING,
      31             :     PCMK__VALUE_RUNNING,
      32             :     PCMK__VALUE_SHUTTING_DOWN,
      33             :     PCMK__VALUE_SHUTDOWN_COMPLETE,
      34             :     PCMK_VALUE_REMOTE,
      35             : };
      36             : 
      37             : enum pcmk_pacemakerd_state
      38           0 : pcmk_pacemakerd_api_daemon_state_text2enum(const char *state)
      39             : {
      40             :     int i;
      41             : 
      42           0 :     if (state == NULL) {
      43           0 :         return pcmk_pacemakerd_state_invalid;
      44             :     }
      45           0 :     for (i=pcmk_pacemakerd_state_init; i <= pcmk_pacemakerd_state_max;
      46           0 :          i++) {
      47           0 :         if (pcmk__str_eq(state, pacemakerd_state_str[i], pcmk__str_none)) {
      48           0 :             return i;
      49             :         }
      50             :     }
      51           0 :     return pcmk_pacemakerd_state_invalid;
      52             : }
      53             : 
      54             : const char *
      55           0 : pcmk_pacemakerd_api_daemon_state_enum2text(
      56             :     enum pcmk_pacemakerd_state state)
      57             : {
      58           0 :     if ((state >= pcmk_pacemakerd_state_init) &&
      59             :         (state <= pcmk_pacemakerd_state_max)) {
      60           0 :         return pacemakerd_state_str[state];
      61             :     }
      62           0 :     return "invalid";
      63             : }
      64             : 
      65             : /*!
      66             :  * \internal
      67             :  * \brief Return a friendly string representation of a \p pacemakerd state
      68             :  *
      69             :  * \param[in] state  \p pacemakerd state
      70             :  *
      71             :  * \return A user-friendly string representation of \p state, or
      72             :  *         <tt>"Invalid pacemakerd state"</tt>
      73             :  */
      74             : const char *
      75           0 : pcmk__pcmkd_state_enum2friendly(enum pcmk_pacemakerd_state state)
      76             : {
      77           0 :     switch (state) {
      78           0 :         case pcmk_pacemakerd_state_init:
      79           0 :             return "Initializing pacemaker";
      80           0 :         case pcmk_pacemakerd_state_starting_daemons:
      81           0 :             return "Pacemaker daemons are starting";
      82           0 :         case pcmk_pacemakerd_state_wait_for_ping:
      83           0 :             return "Waiting for startup trigger from SBD";
      84           0 :         case pcmk_pacemakerd_state_running:
      85           0 :             return "Pacemaker is running";
      86           0 :         case pcmk_pacemakerd_state_shutting_down:
      87           0 :             return "Pacemaker daemons are shutting down";
      88           0 :         case pcmk_pacemakerd_state_shutdown_complete:
      89             :             /* Assuming pacemakerd won't process messages while in
      90             :              * shutdown_complete state unless reporting to SBD
      91             :              */
      92           0 :             return "Pacemaker daemons are shut down (reporting to SBD)";
      93           0 :         case pcmk_pacemakerd_state_remote:
      94           0 :             return "pacemaker-remoted is running (on a Pacemaker Remote node)";
      95           0 :         default:
      96           0 :             return "Invalid pacemakerd state";
      97             :     }
      98             : }
      99             : 
     100             : /*!
     101             :  * \internal
     102             :  * \brief Get a string representation of a \p pacemakerd API reply type
     103             :  *
     104             :  * \param[in] reply  \p pacemakerd API reply type
     105             :  *
     106             :  * \return String representation of a \p pacemakerd API reply type
     107             :  */
     108             : const char *
     109           0 : pcmk__pcmkd_api_reply2str(enum pcmk_pacemakerd_api_reply reply)
     110             : {
     111           0 :     switch (reply) {
     112           0 :         case pcmk_pacemakerd_reply_ping:
     113           0 :             return "ping";
     114           0 :         case pcmk_pacemakerd_reply_shutdown:
     115           0 :             return "shutdown";
     116           0 :         default:
     117           0 :             return "unknown";
     118             :     }
     119             : }
     120             : 
     121             : // \return Standard Pacemaker return code
     122             : static int
     123           0 : new_data(pcmk_ipc_api_t *api)
     124             : {
     125           0 :     struct pacemakerd_api_private_s *private = NULL;
     126             : 
     127           0 :     api->api_data = calloc(1, sizeof(struct pacemakerd_api_private_s));
     128             : 
     129           0 :     if (api->api_data == NULL) {
     130           0 :         return errno;
     131             :     }
     132             : 
     133           0 :     private = api->api_data;
     134           0 :     private->state = pcmk_pacemakerd_state_invalid;
     135             :     /* other as with cib, controld, ... we are addressing pacemakerd just
     136             :        from the local node -> pid is unique and thus sufficient as an ID
     137             :      */
     138           0 :     private->client_uuid = pcmk__getpid_s();
     139             : 
     140           0 :     return pcmk_rc_ok;
     141             : }
     142             : 
     143             : static void
     144           0 : free_data(void *data)
     145             : {
     146           0 :     free(((struct pacemakerd_api_private_s *) data)->client_uuid);
     147           0 :     free(data);
     148           0 : }
     149             : 
     150             : // \return Standard Pacemaker return code
     151             : static int
     152           0 : post_connect(pcmk_ipc_api_t *api)
     153             : {
     154           0 :     struct pacemakerd_api_private_s *private = NULL;
     155             : 
     156           0 :     if (api->api_data == NULL) {
     157           0 :         return EINVAL;
     158             :     }
     159           0 :     private = api->api_data;
     160           0 :     private->state = pcmk_pacemakerd_state_invalid;
     161             : 
     162           0 :     return pcmk_rc_ok;
     163             : }
     164             : 
     165             : static void
     166           0 : post_disconnect(pcmk_ipc_api_t *api)
     167             : {
     168           0 :     struct pacemakerd_api_private_s *private = NULL;
     169             : 
     170           0 :     if (api->api_data == NULL) {
     171           0 :         return;
     172             :     }
     173           0 :     private = api->api_data;
     174           0 :     private->state = pcmk_pacemakerd_state_invalid;
     175             : 
     176           0 :     return;
     177             : }
     178             : 
     179             : static bool
     180           0 : reply_expected(pcmk_ipc_api_t *api, const xmlNode *request)
     181             : {
     182           0 :     const char *command = crm_element_value(request, PCMK__XA_CRM_TASK);
     183             : 
     184           0 :     if (command == NULL) {
     185           0 :         return false;
     186             :     }
     187             : 
     188             :     // We only need to handle commands that functions in this file can send
     189           0 :     return pcmk__str_any_of(command, CRM_OP_PING, CRM_OP_QUIT, NULL);
     190             : }
     191             : 
     192             : static bool
     193           0 : dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
     194             : {
     195           0 :     crm_exit_t status = CRM_EX_OK;
     196           0 :     xmlNode *wrapper = NULL;
     197           0 :     xmlNode *msg_data = NULL;
     198           0 :     pcmk_pacemakerd_api_reply_t reply_data = {
     199             :         pcmk_pacemakerd_reply_unknown
     200             :     };
     201           0 :     const char *value = NULL;
     202           0 :     long long value_ll = 0;
     203             : 
     204           0 :     if (pcmk__xe_is(reply, PCMK__XE_ACK)) {
     205           0 :         long long int ack_status = 0;
     206           0 :         pcmk__scan_ll(crm_element_value(reply, PCMK_XA_STATUS), &ack_status,
     207             :                       CRM_EX_OK);
     208           0 :         return ack_status == CRM_EX_INDETERMINATE;
     209             :     }
     210             : 
     211           0 :     value = crm_element_value(reply, PCMK__XA_SUBT);
     212           0 :     if (!pcmk__str_eq(value, PCMK__VALUE_RESPONSE, pcmk__str_none)) {
     213           0 :         crm_info("Unrecognizable message from %s: "
     214             :                  "message type '%s' not '" PCMK__VALUE_RESPONSE "'",
     215             :                  pcmk_ipc_name(api, true), pcmk__s(value, ""));
     216           0 :         status = CRM_EX_PROTOCOL;
     217           0 :         goto done;
     218             :     }
     219             : 
     220           0 :     if (pcmk__str_empty(crm_element_value(reply, PCMK_XA_REFERENCE))) {
     221           0 :         crm_info("Unrecognizable message from %s: no reference",
     222             :                  pcmk_ipc_name(api, true));
     223           0 :         status = CRM_EX_PROTOCOL;
     224           0 :         goto done;
     225             :     }
     226             : 
     227           0 :     value = crm_element_value(reply, PCMK__XA_CRM_TASK);
     228             : 
     229             :     // Parse useful info from reply
     230           0 :     wrapper = pcmk__xe_first_child(reply, PCMK__XE_CRM_XML, NULL, NULL);
     231           0 :     msg_data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
     232             : 
     233           0 :     crm_element_value_ll(msg_data, PCMK_XA_CRM_TIMESTAMP, &value_ll);
     234             : 
     235           0 :     if (pcmk__str_eq(value, CRM_OP_PING, pcmk__str_none)) {
     236           0 :         reply_data.reply_type = pcmk_pacemakerd_reply_ping;
     237           0 :         reply_data.data.ping.state =
     238           0 :             pcmk_pacemakerd_api_daemon_state_text2enum(
     239             :                 crm_element_value(msg_data, PCMK__XA_PACEMAKERD_STATE));
     240           0 :         reply_data.data.ping.status =
     241           0 :             pcmk__str_eq(crm_element_value(msg_data, PCMK_XA_RESULT), "ok",
     242           0 :                          pcmk__str_casei)?pcmk_rc_ok:pcmk_rc_error;
     243           0 :         reply_data.data.ping.last_good = (value_ll < 0)? 0 : (time_t) value_ll;
     244           0 :         reply_data.data.ping.sys_from =
     245           0 :             crm_element_value(msg_data, PCMK__XA_CRM_SUBSYSTEM);
     246           0 :     } else if (pcmk__str_eq(value, CRM_OP_QUIT, pcmk__str_none)) {
     247           0 :         const char *op_status = crm_element_value(msg_data, PCMK__XA_OP_STATUS);
     248             : 
     249           0 :         reply_data.reply_type = pcmk_pacemakerd_reply_shutdown;
     250           0 :         reply_data.data.shutdown.status = atoi(op_status);
     251             :     } else {
     252           0 :         crm_info("Unrecognizable message from %s: unknown command '%s'",
     253             :                  pcmk_ipc_name(api, true), pcmk__s(value, ""));
     254           0 :         status = CRM_EX_PROTOCOL;
     255           0 :         goto done;
     256             :     }
     257             : 
     258           0 : done:
     259           0 :     pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
     260           0 :     return false;
     261             : }
     262             : 
     263             : pcmk__ipc_methods_t *
     264           0 : pcmk__pacemakerd_api_methods(void)
     265             : {
     266           0 :     pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
     267             : 
     268           0 :     if (cmds != NULL) {
     269           0 :         cmds->new_data = new_data;
     270           0 :         cmds->free_data = free_data;
     271           0 :         cmds->post_connect = post_connect;
     272           0 :         cmds->reply_expected = reply_expected;
     273           0 :         cmds->dispatch = dispatch;
     274           0 :         cmds->post_disconnect = post_disconnect;
     275             :     }
     276           0 :     return cmds;
     277             : }
     278             : 
     279             : static int
     280           0 : do_pacemakerd_api_call(pcmk_ipc_api_t *api, const char *ipc_name, const char *task)
     281             : {
     282             :     pacemakerd_api_private_t *private;
     283             :     xmlNode *cmd;
     284             :     int rc;
     285             : 
     286           0 :     if (api == NULL) {
     287           0 :         return EINVAL;
     288             :     }
     289             : 
     290           0 :     private = api->api_data;
     291           0 :     CRM_ASSERT(private != NULL);
     292             : 
     293           0 :     cmd = create_request(task, NULL, NULL, CRM_SYSTEM_MCP,
     294             :                          pcmk__ipc_sys_name(ipc_name, "client"),
     295             :                          private->client_uuid);
     296             : 
     297           0 :     if (cmd) {
     298           0 :         rc = pcmk__send_ipc_request(api, cmd);
     299           0 :         if (rc != pcmk_rc_ok) {
     300           0 :             crm_debug("Couldn't send request to %s: %s rc=%d",
     301             :                       pcmk_ipc_name(api, true), pcmk_rc_str(rc), rc);
     302             :         }
     303           0 :         free_xml(cmd);
     304             :     } else {
     305           0 :         rc = ENOMSG;
     306             :     }
     307             : 
     308           0 :     return rc;
     309             : }
     310             : 
     311             : int
     312           0 : pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
     313             : {
     314           0 :     return do_pacemakerd_api_call(api, ipc_name, CRM_OP_PING);
     315             : }
     316             : 
     317             : int
     318           0 : pcmk_pacemakerd_api_shutdown(pcmk_ipc_api_t *api, const char *ipc_name)
     319             : {
     320           0 :     return do_pacemakerd_api_call(api, ipc_name, CRM_OP_QUIT);
     321             : }

Generated by: LCOV version 1.14