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. pcmk__pcmkd_api_reply2str
  5. new_data
  6. free_data
  7. post_connect
  8. post_disconnect
  9. reply_expected
  10. dispatch
  11. pcmk__pacemakerd_api_methods
  12. do_pacemakerd_api_call
  13. pcmk_pacemakerd_api_ping
  14. pcmk_pacemakerd_api_shutdown

   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 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         case pcmk_pacemakerd_state_remote:
  94             return "pacemaker-remoted is running (on a Pacemaker Remote node)";
  95         default:
  96             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 pcmk__pcmkd_api_reply2str(enum pcmk_pacemakerd_api_reply reply)
     /* [previous][next][first][last][top][bottom][index][help] */
 110 {
 111     switch (reply) {
 112         case pcmk_pacemakerd_reply_ping:
 113             return "ping";
 114         case pcmk_pacemakerd_reply_shutdown:
 115             return "shutdown";
 116         default:
 117             return "unknown";
 118     }
 119 }
 120 
 121 // \return Standard Pacemaker return code
 122 static int
 123 new_data(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125     struct pacemakerd_api_private_s *private = NULL;
 126 
 127     api->api_data = calloc(1, sizeof(struct pacemakerd_api_private_s));
 128 
 129     if (api->api_data == NULL) {
 130         return errno;
 131     }
 132 
 133     private = api->api_data;
 134     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     private->client_uuid = pcmk__getpid_s();
 139 
 140     return pcmk_rc_ok;
 141 }
 142 
 143 static void
 144 free_data(void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 145 {
 146     free(((struct pacemakerd_api_private_s *) data)->client_uuid);
 147     free(data);
 148 }
 149 
 150 // \return Standard Pacemaker return code
 151 static int
 152 post_connect(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 153 {
 154     struct pacemakerd_api_private_s *private = NULL;
 155 
 156     if (api->api_data == NULL) {
 157         return EINVAL;
 158     }
 159     private = api->api_data;
 160     private->state = pcmk_pacemakerd_state_invalid;
 161 
 162     return pcmk_rc_ok;
 163 }
 164 
 165 static void
 166 post_disconnect(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 167 {
 168     struct pacemakerd_api_private_s *private = NULL;
 169 
 170     if (api->api_data == NULL) {
 171         return;
 172     }
 173     private = api->api_data;
 174     private->state = pcmk_pacemakerd_state_invalid;
 175 
 176     return;
 177 }
 178 
 179 static bool
 180 reply_expected(pcmk_ipc_api_t *api, const xmlNode *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 181 {
 182     const char *command = crm_element_value(request, PCMK__XA_CRM_TASK);
 183 
 184     if (command == NULL) {
 185         return false;
 186     }
 187 
 188     // We only need to handle commands that functions in this file can send
 189     return pcmk__str_any_of(command, CRM_OP_PING, CRM_OP_QUIT, NULL);
 190 }
 191 
 192 static bool
 193 dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
     /* [previous][next][first][last][top][bottom][index][help] */
 194 {
 195     crm_exit_t status = CRM_EX_OK;
 196     xmlNode *wrapper = NULL;
 197     xmlNode *msg_data = NULL;
 198     pcmk_pacemakerd_api_reply_t reply_data = {
 199         pcmk_pacemakerd_reply_unknown
 200     };
 201     const char *value = NULL;
 202     long long value_ll = 0;
 203 
 204     if (pcmk__xe_is(reply, PCMK__XE_ACK)) {
 205         long long int ack_status = 0;
 206         const char *status = crm_element_value(reply, PCMK_XA_STATUS);
 207         int rc = pcmk__scan_ll(status, &ack_status, CRM_EX_OK);
 208 
 209         if (rc != pcmk_rc_ok) {
 210             crm_warn("Ack reply from %s has invalid " PCMK_XA_STATUS
 211                      " '%s' (bug?)",
 212                      pcmk_ipc_name(api, true), pcmk__s(status, ""));
 213         }
 214         return ack_status == CRM_EX_INDETERMINATE;
 215     }
 216 
 217     value = crm_element_value(reply, PCMK__XA_SUBT);
 218     if (!pcmk__str_eq(value, PCMK__VALUE_RESPONSE, pcmk__str_none)) {
 219         crm_info("Unrecognizable message from %s: "
 220                  "message type '%s' not '" PCMK__VALUE_RESPONSE "'",
 221                  pcmk_ipc_name(api, true), pcmk__s(value, ""));
 222         status = CRM_EX_PROTOCOL;
 223         goto done;
 224     }
 225 
 226     if (pcmk__str_empty(crm_element_value(reply, PCMK_XA_REFERENCE))) {
 227         crm_info("Unrecognizable message from %s: no reference",
 228                  pcmk_ipc_name(api, true));
 229         status = CRM_EX_PROTOCOL;
 230         goto done;
 231     }
 232 
 233     value = crm_element_value(reply, PCMK__XA_CRM_TASK);
 234 
 235     // Parse useful info from reply
 236     wrapper = pcmk__xe_first_child(reply, PCMK__XE_CRM_XML, NULL, NULL);
 237     msg_data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
 238 
 239     crm_element_value_ll(msg_data, PCMK_XA_CRM_TIMESTAMP, &value_ll);
 240 
 241     if (pcmk__str_eq(value, CRM_OP_PING, pcmk__str_none)) {
 242         reply_data.reply_type = pcmk_pacemakerd_reply_ping;
 243         reply_data.data.ping.state =
 244             pcmk_pacemakerd_api_daemon_state_text2enum(
 245                 crm_element_value(msg_data, PCMK__XA_PACEMAKERD_STATE));
 246         reply_data.data.ping.status =
 247             pcmk__str_eq(crm_element_value(msg_data, PCMK_XA_RESULT), "ok",
 248                          pcmk__str_casei)?pcmk_rc_ok:pcmk_rc_error;
 249         reply_data.data.ping.last_good = (value_ll < 0)? 0 : (time_t) value_ll;
 250         reply_data.data.ping.sys_from =
 251             crm_element_value(msg_data, PCMK__XA_CRM_SUBSYSTEM);
 252     } else if (pcmk__str_eq(value, CRM_OP_QUIT, pcmk__str_none)) {
 253         const char *op_status = crm_element_value(msg_data, PCMK__XA_OP_STATUS);
 254 
 255         reply_data.reply_type = pcmk_pacemakerd_reply_shutdown;
 256         reply_data.data.shutdown.status = atoi(op_status);
 257     } else {
 258         crm_info("Unrecognizable message from %s: unknown command '%s'",
 259                  pcmk_ipc_name(api, true), pcmk__s(value, ""));
 260         status = CRM_EX_PROTOCOL;
 261         goto done;
 262     }
 263 
 264 done:
 265     pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
 266     return false;
 267 }
 268 
 269 pcmk__ipc_methods_t *
 270 pcmk__pacemakerd_api_methods(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 271 {
 272     pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
 273 
 274     if (cmds != NULL) {
 275         cmds->new_data = new_data;
 276         cmds->free_data = free_data;
 277         cmds->post_connect = post_connect;
 278         cmds->reply_expected = reply_expected;
 279         cmds->dispatch = dispatch;
 280         cmds->post_disconnect = post_disconnect;
 281     }
 282     return cmds;
 283 }
 284 
 285 static int
 286 do_pacemakerd_api_call(pcmk_ipc_api_t *api, const char *ipc_name, const char *task)
     /* [previous][next][first][last][top][bottom][index][help] */
 287 {
 288     pacemakerd_api_private_t *private;
 289     xmlNode *cmd;
 290     int rc;
 291 
 292     if (api == NULL) {
 293         return EINVAL;
 294     }
 295 
 296     private = api->api_data;
 297     pcmk__assert(private != NULL);
 298 
 299     cmd = create_request(task, NULL, NULL, CRM_SYSTEM_MCP,
 300                          pcmk__ipc_sys_name(ipc_name, "client"),
 301                          private->client_uuid);
 302 
 303     if (cmd) {
 304         rc = pcmk__send_ipc_request(api, cmd);
 305         if (rc != pcmk_rc_ok) {
 306             crm_debug("Couldn't send request to %s: %s rc=%d",
 307                       pcmk_ipc_name(api, true), pcmk_rc_str(rc), rc);
 308         }
 309         free_xml(cmd);
 310     } else {
 311         rc = ENOMSG;
 312     }
 313 
 314     return rc;
 315 }
 316 
 317 int
 318 pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
     /* [previous][next][first][last][top][bottom][index][help] */
 319 {
 320     return do_pacemakerd_api_call(api, ipc_name, CRM_OP_PING);
 321 }
 322 
 323 int
 324 pcmk_pacemakerd_api_shutdown(pcmk_ipc_api_t *api, const char *ipc_name)
     /* [previous][next][first][last][top][bottom][index][help] */
 325 {
 326     return do_pacemakerd_api_call(api, ipc_name, CRM_OP_QUIT);
 327 }

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