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. new_data
  4. free_data
  5. post_connect
  6. post_disconnect
  7. reply_expected
  8. dispatch
  9. pcmk__pacemakerd_api_methods
  10. do_pacemakerd_api_call
  11. pcmk_pacemakerd_api_ping
  12. 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 // \return Standard Pacemaker return code
  66 static int
  67 new_data(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
  68 {
  69     struct pacemakerd_api_private_s *private = NULL;
  70 
  71     api->api_data = calloc(1, sizeof(struct pacemakerd_api_private_s));
  72 
  73     if (api->api_data == NULL) {
  74         return errno;
  75     }
  76 
  77     private = api->api_data;
  78     private->state = pcmk_pacemakerd_state_invalid;
  79     /* other as with cib, controld, ... we are addressing pacemakerd just
  80        from the local node -> pid is unique and thus sufficient as an ID
  81      */
  82     private->client_uuid = pcmk__getpid_s();
  83 
  84     return pcmk_rc_ok;
  85 }
  86 
  87 static void
  88 free_data(void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90     free(((struct pacemakerd_api_private_s *) data)->client_uuid);
  91     free(data);
  92 }
  93 
  94 // \return Standard Pacemaker return code
  95 static int
  96 post_connect(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
  97 {
  98     struct pacemakerd_api_private_s *private = NULL;
  99 
 100     if (api->api_data == NULL) {
 101         return EINVAL;
 102     }
 103     private = api->api_data;
 104     private->state = pcmk_pacemakerd_state_invalid;
 105 
 106     return pcmk_rc_ok;
 107 }
 108 
 109 static void
 110 post_disconnect(pcmk_ipc_api_t *api)
     /* [previous][next][first][last][top][bottom][index][help] */
 111 {
 112     struct pacemakerd_api_private_s *private = NULL;
 113 
 114     if (api->api_data == NULL) {
 115         return;
 116     }
 117     private = api->api_data;
 118     private->state = pcmk_pacemakerd_state_invalid;
 119 
 120     return;
 121 }
 122 
 123 static bool
 124 reply_expected(pcmk_ipc_api_t *api, xmlNode *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 125 {
 126     const char *command = crm_element_value(request, F_CRM_TASK);
 127 
 128     if (command == NULL) {
 129         return false;
 130     }
 131 
 132     // We only need to handle commands that functions in this file can send
 133     return pcmk__str_any_of(command, CRM_OP_PING, CRM_OP_QUIT, NULL);
 134 }
 135 
 136 static bool
 137 dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
     /* [previous][next][first][last][top][bottom][index][help] */
 138 {
 139     crm_exit_t status = CRM_EX_OK;
 140     xmlNode *msg_data = NULL;
 141     pcmk_pacemakerd_api_reply_t reply_data = {
 142         pcmk_pacemakerd_reply_unknown
 143     };
 144     const char *value = NULL;
 145     long long value_ll = 0;
 146 
 147     if (pcmk__str_eq((const char *) reply->name, "ack", pcmk__str_casei)) {
 148         long long int ack_status = 0;
 149         pcmk__scan_ll(crm_element_value(reply, "status"), &ack_status, CRM_EX_OK);
 150         return ack_status == CRM_EX_INDETERMINATE;
 151     }
 152 
 153     value = crm_element_value(reply, F_CRM_MSG_TYPE);
 154     if ((value == NULL) || (strcmp(value, XML_ATTR_RESPONSE))) {
 155         crm_debug("Unrecognizable pacemakerd message: invalid message type '%s'",
 156                   crm_str(value));
 157         status = CRM_EX_PROTOCOL;
 158         goto done;
 159     }
 160 
 161     if (crm_element_value(reply, XML_ATTR_REFERENCE) == NULL) {
 162         crm_debug("Unrecognizable pacemakerd message: no reference");
 163         status = CRM_EX_PROTOCOL;
 164         goto done;
 165     }
 166 
 167     value = crm_element_value(reply, F_CRM_TASK);
 168 
 169     // Parse useful info from reply
 170     msg_data = get_message_xml(reply, F_CRM_DATA);
 171     crm_element_value_ll(msg_data, XML_ATTR_TSTAMP, &value_ll);
 172 
 173     if (pcmk__str_eq(value, CRM_OP_PING, pcmk__str_none)) {
 174         reply_data.reply_type = pcmk_pacemakerd_reply_ping;
 175         reply_data.data.ping.state =
 176             pcmk_pacemakerd_api_daemon_state_text2enum(
 177                 crm_element_value(msg_data, XML_PING_ATTR_PACEMAKERDSTATE));
 178         reply_data.data.ping.status =
 179             pcmk__str_eq(crm_element_value(msg_data, XML_PING_ATTR_STATUS), "ok",
 180                          pcmk__str_casei)?pcmk_rc_ok:pcmk_rc_error;
 181         reply_data.data.ping.last_good = (time_t) value_ll;
 182         reply_data.data.ping.sys_from = crm_element_value(msg_data,
 183                                             XML_PING_ATTR_SYSFROM);
 184     } else if (pcmk__str_eq(value, CRM_OP_QUIT, pcmk__str_none)) {
 185         reply_data.reply_type = pcmk_pacemakerd_reply_shutdown;
 186         reply_data.data.shutdown.status = atoi(crm_element_value(msg_data, XML_LRM_ATTR_OPSTATUS));
 187     } else {
 188         crm_debug("Unrecognizable pacemakerd message: '%s'", crm_str(value));
 189         status = CRM_EX_PROTOCOL;
 190         goto done;
 191     }
 192 
 193 done:
 194     pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
 195     return false;
 196 }
 197 
 198 pcmk__ipc_methods_t *
 199 pcmk__pacemakerd_api_methods()
     /* [previous][next][first][last][top][bottom][index][help] */
 200 {
 201     pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
 202 
 203     if (cmds != NULL) {
 204         cmds->new_data = new_data;
 205         cmds->free_data = free_data;
 206         cmds->post_connect = post_connect;
 207         cmds->reply_expected = reply_expected;
 208         cmds->dispatch = dispatch;
 209         cmds->post_disconnect = post_disconnect;
 210     }
 211     return cmds;
 212 }
 213 
 214 static int
 215 do_pacemakerd_api_call(pcmk_ipc_api_t *api, const char *ipc_name, const char *task)
     /* [previous][next][first][last][top][bottom][index][help] */
 216 {
 217     pacemakerd_api_private_t *private;
 218     xmlNode *cmd;
 219     int rc;
 220 
 221     if (api == NULL) {
 222         return EINVAL;
 223     }
 224 
 225     private = api->api_data;
 226     CRM_ASSERT(private != NULL);
 227 
 228     cmd = create_request(task, NULL, NULL, CRM_SYSTEM_MCP,
 229                          pcmk__ipc_sys_name(ipc_name, "client"),
 230                          private->client_uuid);
 231 
 232     if (cmd) {
 233         rc = pcmk__send_ipc_request(api, cmd);
 234         if (rc != pcmk_rc_ok) {
 235             crm_debug("Couldn't send request to pacemakerd: %s rc=%d",
 236                       pcmk_rc_str(rc), rc);
 237         }
 238         free_xml(cmd);
 239     } else {
 240         rc = ENOMSG;
 241     }
 242 
 243     return rc;
 244 }
 245 
 246 int
 247 pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
     /* [previous][next][first][last][top][bottom][index][help] */
 248 {
 249     return do_pacemakerd_api_call(api, ipc_name, CRM_OP_PING);
 250 }
 251 
 252 int
 253 pcmk_pacemakerd_api_shutdown(pcmk_ipc_api_t *api, const char *ipc_name)
     /* [previous][next][first][last][top][bottom][index][help] */
 254 {
 255     return do_pacemakerd_api_call(api, ipc_name, CRM_OP_QUIT);
 256 }

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