root/lib/common/ipc_pacemakerd.c

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

DEFINITIONS

This source file includes following definitions.
  1. pcmk_pacemakerd_api_daemon_state_text2enum
  2. pcmk_pacemakerd_api_daemon_state_enum2text
  3. pcmk__pcmkd_state_enum2friendly
  4. new_data
  5. free_data
  6. post_connect
  7. post_disconnect
  8. reply_expected
  9. dispatch
  10. pcmk__pacemakerd_api_methods
  11. do_pacemakerd_api_call
  12. pcmk_pacemakerd_api_ping
  13. pcmk_pacemakerd_api_shutdown

   1 /*
   2  * Copyright 2020-2022 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/msg_xml.h>
  17 #include <crm/common/xml.h>
  18 #include <crm/common/ipc.h>
  19 #include <crm/common/ipc_internal.h>
  20 #include <crm/common/ipc_pacemakerd.h>
  21 #include "crmcommon_private.h"
  22 
  23 typedef struct pacemakerd_api_private_s {
  24     enum pcmk_pacemakerd_state state;
  25     char *client_uuid;
  26 } pacemakerd_api_private_t;
  27 
  28 static const char *pacemakerd_state_str[] = {
  29     XML_PING_ATTR_PACEMAKERDSTATE_INIT,
  30     XML_PING_ATTR_PACEMAKERDSTATE_STARTINGDAEMONS,
  31     XML_PING_ATTR_PACEMAKERDSTATE_WAITPING,
  32     XML_PING_ATTR_PACEMAKERDSTATE_RUNNING,
  33     XML_PING_ATTR_PACEMAKERDSTATE_SHUTTINGDOWN,
  34     XML_PING_ATTR_PACEMAKERDSTATE_SHUTDOWNCOMPLETE
  35 };
  36 
  37 enum pcmk_pacemakerd_state
  38 pcmk_pacemakerd_api_daemon_state_text2enum(const char *state)
     /* [previous][next][first][last][top][bottom][index][help] */
  39 {
  40     int i;
  41 
  42     if (state == NULL) {
  43         return pcmk_pacemakerd_state_invalid;
  44     }
  45     for (i=pcmk_pacemakerd_state_init; i <= pcmk_pacemakerd_state_max;
  46          i++) {
  47         if (pcmk__str_eq(state, pacemakerd_state_str[i], pcmk__str_none)) {
  48             return i;
  49         }
  50     }
  51     return pcmk_pacemakerd_state_invalid;
  52 }
  53 
  54 const char *
  55 pcmk_pacemakerd_api_daemon_state_enum2text(
     /* [previous][next][first][last][top][bottom][index][help] */
  56     enum pcmk_pacemakerd_state state)
  57 {
  58     if ((state >= pcmk_pacemakerd_state_init) &&
  59         (state <= pcmk_pacemakerd_state_max)) {
  60         return pacemakerd_state_str[state];
  61     }
  62     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 pcmk__pcmkd_state_enum2friendly(enum pcmk_pacemakerd_state state)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77     switch (state) {
  78         case pcmk_pacemakerd_state_init:
  79             return "Initializing pacemaker";
  80         case pcmk_pacemakerd_state_starting_daemons:
  81             return "Pacemaker daemons are starting";
  82         case pcmk_pacemakerd_state_wait_for_ping:
  83             return "Waiting for startup trigger from SBD";
  84         case pcmk_pacemakerd_state_running:
  85             return "Pacemaker is running";
  86         case pcmk_pacemakerd_state_shutting_down:
  87             return "Pacemaker daemons are shutting down";
  88         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             return "Pacemaker daemons are shut down (reporting to SBD)";
  93         default:
  94             return "Invalid pacemakerd state";
  95     }
  96 }
  97 
  98 // \return Standard Pacemaker return code
  99 static int
 100 new_data(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 101 {
 102     struct pacemakerd_api_private_s *private = NULL;
 103 
 104     api->api_data = calloc(1, sizeof(struct pacemakerd_api_private_s));
 105 
 106     if (api->api_data == NULL) {
 107         return errno;
 108     }
 109 
 110     private = api->api_data;
 111     private->state = pcmk_pacemakerd_state_invalid;
 112     /* other as with cib, controld, ... we are addressing pacemakerd just
 113        from the local node -> pid is unique and thus sufficient as an ID
 114      */
 115     private->client_uuid = pcmk__getpid_s();
 116 
 117     return pcmk_rc_ok;
 118 }
 119 
 120 static void
 121 free_data(void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 122 {
 123     free(((struct pacemakerd_api_private_s *) data)->client_uuid);
 124     free(data);
 125 }
 126 
 127 // \return Standard Pacemaker return code
 128 static int
 129 post_connect(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 130 {
 131     struct pacemakerd_api_private_s *private = NULL;
 132 
 133     if (api->api_data == NULL) {
 134         return EINVAL;
 135     }
 136     private = api->api_data;
 137     private->state = pcmk_pacemakerd_state_invalid;
 138 
 139     return pcmk_rc_ok;
 140 }
 141 
 142 static void
 143 post_disconnect(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 144 {
 145     struct pacemakerd_api_private_s *private = NULL;
 146 
 147     if (api->api_data == NULL) {
 148         return;
 149     }
 150     private = api->api_data;
 151     private->state = pcmk_pacemakerd_state_invalid;
 152 
 153     return;
 154 }
 155 
 156 static bool
 157 reply_expected(pcmk_ipc_api_t *api, xmlNode *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 158 {
 159     const char *command = crm_element_value(request, F_CRM_TASK);
 160 
 161     if (command == NULL) {
 162         return false;
 163     }
 164 
 165     // We only need to handle commands that functions in this file can send
 166     return pcmk__str_any_of(command, CRM_OP_PING, CRM_OP_QUIT, NULL);
 167 }
 168 
 169 static bool
 170 dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
     /* [previous][next][first][last][top][bottom][index][help] */
 171 {
 172     crm_exit_t status = CRM_EX_OK;
 173     xmlNode *msg_data = NULL;
 174     pcmk_pacemakerd_api_reply_t reply_data = {
 175         pcmk_pacemakerd_reply_unknown
 176     };
 177     const char *value = NULL;
 178     long long value_ll = 0;
 179 
 180     if (pcmk__str_eq((const char *) reply->name, "ack", pcmk__str_none)) {
 181         long long int ack_status = 0;
 182         pcmk__scan_ll(crm_element_value(reply, "status"), &ack_status, CRM_EX_OK);
 183         return ack_status == CRM_EX_INDETERMINATE;
 184     }
 185 
 186     value = crm_element_value(reply, F_CRM_MSG_TYPE);
 187     if (pcmk__str_empty(value)
 188         || !pcmk__str_eq(value, XML_ATTR_RESPONSE, pcmk__str_none)) {
 189         crm_info("Unrecognizable message from pacemakerd: "
 190                  "message type '%s' not '" XML_ATTR_RESPONSE "'",
 191                  pcmk__s(value, ""));
 192         status = CRM_EX_PROTOCOL;
 193         goto done;
 194     }
 195 
 196     if (pcmk__str_empty(crm_element_value(reply, XML_ATTR_REFERENCE))) {
 197         crm_info("Unrecognizable message from pacemakerd: no reference");
 198         status = CRM_EX_PROTOCOL;
 199         goto done;
 200     }
 201 
 202     value = crm_element_value(reply, F_CRM_TASK);
 203 
 204     // Parse useful info from reply
 205     msg_data = get_message_xml(reply, F_CRM_DATA);
 206     crm_element_value_ll(msg_data, XML_ATTR_TSTAMP, &value_ll);
 207 
 208     if (pcmk__str_eq(value, CRM_OP_PING, pcmk__str_none)) {
 209         reply_data.reply_type = pcmk_pacemakerd_reply_ping;
 210         reply_data.data.ping.state =
 211             pcmk_pacemakerd_api_daemon_state_text2enum(
 212                 crm_element_value(msg_data, XML_PING_ATTR_PACEMAKERDSTATE));
 213         reply_data.data.ping.status =
 214             pcmk__str_eq(crm_element_value(msg_data, XML_PING_ATTR_STATUS), "ok",
 215                          pcmk__str_casei)?pcmk_rc_ok:pcmk_rc_error;
 216         reply_data.data.ping.last_good = (value_ll < 0)? 0 : (time_t) value_ll;
 217         reply_data.data.ping.sys_from = crm_element_value(msg_data,
 218                                             XML_PING_ATTR_SYSFROM);
 219     } else if (pcmk__str_eq(value, CRM_OP_QUIT, pcmk__str_none)) {
 220         reply_data.reply_type = pcmk_pacemakerd_reply_shutdown;
 221         reply_data.data.shutdown.status = atoi(crm_element_value(msg_data, XML_LRM_ATTR_OPSTATUS));
 222     } else {
 223         crm_info("Unrecognizable message from pacemakerd: "
 224                  "unknown command '%s'", pcmk__s(value, ""));
 225         status = CRM_EX_PROTOCOL;
 226         goto done;
 227     }
 228 
 229 done:
 230     pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
 231     return false;
 232 }
 233 
 234 pcmk__ipc_methods_t *
 235 pcmk__pacemakerd_api_methods(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 236 {
 237     pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
 238 
 239     if (cmds != NULL) {
 240         cmds->new_data = new_data;
 241         cmds->free_data = free_data;
 242         cmds->post_connect = post_connect;
 243         cmds->reply_expected = reply_expected;
 244         cmds->dispatch = dispatch;
 245         cmds->post_disconnect = post_disconnect;
 246     }
 247     return cmds;
 248 }
 249 
 250 static int
 251 do_pacemakerd_api_call(pcmk_ipc_api_t *api, const char *ipc_name, const char *task)
     /* [previous][next][first][last][top][bottom][index][help] */
 252 {
 253     pacemakerd_api_private_t *private;
 254     xmlNode *cmd;
 255     int rc;
 256 
 257     if (api == NULL) {
 258         return EINVAL;
 259     }
 260 
 261     private = api->api_data;
 262     CRM_ASSERT(private != NULL);
 263 
 264     cmd = create_request(task, NULL, NULL, CRM_SYSTEM_MCP,
 265                          pcmk__ipc_sys_name(ipc_name, "client"),
 266                          private->client_uuid);
 267 
 268     if (cmd) {
 269         rc = pcmk__send_ipc_request(api, cmd);
 270         if (rc != pcmk_rc_ok) {
 271             crm_debug("Couldn't send request to pacemakerd: %s rc=%d",
 272                       pcmk_rc_str(rc), rc);
 273         }
 274         free_xml(cmd);
 275     } else {
 276         rc = ENOMSG;
 277     }
 278 
 279     return rc;
 280 }
 281 
 282 int
 283 pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
     /* [previous][next][first][last][top][bottom][index][help] */
 284 {
 285     return do_pacemakerd_api_call(api, ipc_name, CRM_OP_PING);
 286 }
 287 
 288 int
 289 pcmk_pacemakerd_api_shutdown(pcmk_ipc_api_t *api, const char *ipc_name)
     /* [previous][next][first][last][top][bottom][index][help] */
 290 {
 291     return do_pacemakerd_api_call(api, ipc_name, CRM_OP_QUIT);
 292 }

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