pacemaker  2.1.2-ada5c3b36
Scalable High-Availability cluster resource manager
ipc_pacemakerd.c
Go to the documentation of this file.
1 /*
2  * Copyright 2020 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>
21 #include "crmcommon_private.h"
22 
23 typedef struct pacemakerd_api_private_s {
24  enum pcmk_pacemakerd_state state;
25  char *client_uuid;
27 
28 static const char *pacemakerd_state_str[] = {
35 };
36 
39 {
40  int i;
41 
42  if (state == NULL) {
44  }
46  i++) {
47  if (pcmk__str_eq(state, pacemakerd_state_str[i], pcmk__str_none)) {
48  return i;
49  }
50  }
52 }
53 
54 const char *
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)
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)
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)
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)
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)
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 void
137 dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
138 {
139  crm_exit_t status = CRM_EX_OK;
140  xmlNode *msg_data = NULL;
141  pcmk_pacemakerd_api_reply_t reply_data = {
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  return;
149  }
150 
151  value = crm_element_value(reply, F_CRM_MSG_TYPE);
152  if ((value == NULL) || (strcmp(value, XML_ATTR_RESPONSE))) {
153  crm_debug("Unrecognizable pacemakerd message: invalid message type '%s'",
154  crm_str(value));
155  status = CRM_EX_PROTOCOL;
156  goto done;
157  }
158 
159  if (crm_element_value(reply, XML_ATTR_REFERENCE) == NULL) {
160  crm_debug("Unrecognizable pacemakerd message: no reference");
161  status = CRM_EX_PROTOCOL;
162  goto done;
163  }
164 
165  value = crm_element_value(reply, F_CRM_TASK);
166 
167  // Parse useful info from reply
168  msg_data = get_message_xml(reply, F_CRM_DATA);
169  crm_element_value_ll(msg_data, XML_ATTR_TSTAMP, &value_ll);
170 
171  if (pcmk__str_eq(value, CRM_OP_PING, pcmk__str_none)) {
173  reply_data.data.ping.state =
176  reply_data.data.ping.status =
177  pcmk__str_eq(crm_element_value(msg_data, XML_PING_ATTR_STATUS), "ok",
179  reply_data.data.ping.last_good = (time_t) value_ll;
180  reply_data.data.ping.sys_from = crm_element_value(msg_data,
182  } else if (pcmk__str_eq(value, CRM_OP_QUIT, pcmk__str_none)) {
184  reply_data.data.shutdown.status = atoi(crm_element_value(msg_data, XML_LRM_ATTR_OPSTATUS));
185  } else {
186  crm_debug("Unrecognizable pacemakerd message: '%s'", crm_str(value));
187  status = CRM_EX_PROTOCOL;
188  goto done;
189  }
190 
191 done:
192  pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
193 }
194 
197 {
198  pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
199 
200  if (cmds != NULL) {
201  cmds->new_data = new_data;
202  cmds->free_data = free_data;
203  cmds->post_connect = post_connect;
204  cmds->reply_expected = reply_expected;
205  cmds->dispatch = dispatch;
206  cmds->post_disconnect = post_disconnect;
207  }
208  return cmds;
209 }
210 
211 static int
212 do_pacemakerd_api_call(pcmk_ipc_api_t *api, const char *ipc_name, const char *task)
213 {
214  pacemakerd_api_private_t *private;
215  xmlNode *cmd;
216  int rc;
217 
218  CRM_CHECK(api != NULL, return -EINVAL);
219  private = api->api_data;
220  CRM_ASSERT(private != NULL);
221 
222  cmd = create_request(task, NULL, NULL, CRM_SYSTEM_MCP,
223  ipc_name?ipc_name:((crm_system_name? crm_system_name : "client")),
224  private->client_uuid);
225 
226  if (cmd) {
227  rc = pcmk__send_ipc_request(api, cmd);
228  if (rc != pcmk_rc_ok) {
229  crm_debug("Couldn't ping pacemakerd: %s rc=%d",
230  pcmk_rc_str(rc), rc);
231  rc = ECOMM;
232  }
233  free_xml(cmd);
234  } else {
235  rc = ENOMSG;
236  }
237 
238  return rc;
239 }
240 
241 int
242 pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
243 {
244  return do_pacemakerd_api_call(api, ipc_name, CRM_OP_PING);
245 }
246 
247 int
248 pcmk_pacemakerd_api_shutdown(pcmk_ipc_api_t *api, const char *ipc_name)
249 {
250  return do_pacemakerd_api_call(api, ipc_name, CRM_OP_QUIT);
251 }
#define F_CRM_TASK
Definition: msg_xml.h:85
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:225
A dumping ground.
xmlNode * get_message_xml(xmlNode *msg, const char *field)
Definition: messages.c:154
int pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
char data[0]
Definition: cpg.c:55
void(* dispatch)(pcmk_ipc_api_t *api, xmlNode *msg)
#define F_CRM_MSG_TYPE
Definition: msg_xml.h:87
struct pcmk_pacemakerd_api_reply_t::@4::@5 ping
#define XML_PING_ATTR_PACEMAKERDSTATE_INIT
Definition: msg_xml.h:160
#define XML_PING_ATTR_PACEMAKERDSTATE_WAITPING
Definition: msg_xml.h:162
#define CRM_OP_QUIT
Definition: crm.h:141
#define XML_PING_ATTR_PACEMAKERDSTATE_STARTINGDAEMONS
Definition: msg_xml.h:161
char * crm_system_name
Definition: utils.c:54
enum crm_exit_e crm_exit_t
struct pcmk_pacemakerd_api_reply_t::@4::@6 shutdown
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:432
int crm_element_value_ll(const xmlNode *data, const char *name, long long *dest)
Retrieve the long long integer value of an XML attribute.
Definition: nvpair.c:597
G_GNUC_INTERNAL void pcmk__call_ipc_callback(pcmk_ipc_api_t *api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data)
Definition: ipc_client.c:144
#define CRM_SYSTEM_MCP
Definition: crm.h:111
struct pacemakerd_api_private_s pacemakerd_api_private_t
enum pcmk_pacemakerd_api_reply reply_type
union pcmk_pacemakerd_api_reply_t::@4 data
int rc
Definition: pcmk_fence.c:35
Protocol violated.
Definition: results.h:263
#define XML_PING_ATTR_PACEMAKERDSTATE_SHUTDOWNCOMPLETE
Definition: msg_xml.h:165
#define crm_debug(fmt, args...)
Definition: logging.h:362
#define XML_PING_ATTR_STATUS
Definition: msg_xml.h:156
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:529
#define XML_ATTR_TSTAMP
Definition: msg_xml.h:125
Wrappers for and extensions to libxml2.
#define XML_PING_ATTR_PACEMAKERDSTATE_RUNNING
Definition: msg_xml.h:163
#define XML_PING_ATTR_PACEMAKERDSTATE_SHUTTINGDOWN
Definition: msg_xml.h:164
#define ECOMM
Definition: portability.h:123
G_GNUC_INTERNAL int pcmk__send_ipc_request(pcmk_ipc_api_t *api, xmlNode *request)
Definition: ipc_client.c:584
Success.
Definition: results.h:239
IPC commands for Pacemakerd.
void free_xml(xmlNode *child)
Definition: xml.c:824
int(* post_connect)(pcmk_ipc_api_t *api)
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:955
#define XML_PING_ATTR_SYSFROM
Definition: msg_xml.h:157
pcmk__ipc_methods_t * pcmk__pacemakerd_api_methods()
#define F_CRM_DATA
Definition: msg_xml.h:84
pcmk_pacemakerd_state
int(* new_data)(pcmk_ipc_api_t *api)
int pcmk_pacemakerd_api_shutdown(pcmk_ipc_api_t *api, const char *ipc_name)
enum pcmk_pacemakerd_state pcmk_pacemakerd_api_daemon_state_text2enum(const char *state)
const char * pcmk_pacemakerd_api_daemon_state_enum2text(enum pcmk_pacemakerd_state state)
#define CRM_ASSERT(expr)
Definition: results.h:42
#define XML_ATTR_REFERENCE
Definition: msg_xml.h:153
void(* free_data)(void *api_data)
#define XML_ATTR_RESPONSE
Definition: msg_xml.h:149
#define crm_str(x)
Definition: logging.h:383
#define XML_LRM_ATTR_OPSTATUS
Definition: msg_xml.h:307
bool(* reply_expected)(pcmk_ipc_api_t *api, xmlNode *request)
IPC interface to Pacemaker daemons.
#define CRM_OP_PING
Definition: crm.h:134
void(* post_disconnect)(pcmk_ipc_api_t *api)
Daemon&#39;s reply to client IPC request.
Definition: ipc.h:82
#define create_request(task, xml_data, host_to, sys_to, sys_from, uuid_from)
Definition: ipc.h:42
#define XML_PING_ATTR_PACEMAKERDSTATE
Definition: msg_xml.h:159