pacemaker  2.0.5-ba59be712
Scalable High-Availability cluster resource manager
proxy_common.c
Go to the documentation of this file.
1 /*
2  * Copyright 2015-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 <glib.h>
13 #include <unistd.h>
14 
15 #include <crm/crm.h>
16 #include <crm/msg_xml.h>
17 #include <crm/services.h>
18 #include <crm/common/mainloop.h>
19 
20 #include <crm/pengine/status.h>
21 #include <crm/cib.h>
22 #include <crm/lrmd.h>
23 #include <crm/lrmd_internal.h>
24 
25 int lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg);
26 GHashTable *proxy_table = NULL;
27 
28 static void
29 remote_proxy_notify_destroy(lrmd_t *lrmd, const char *session_id)
30 {
31  /* sending to the remote node that an ipc connection has been destroyed */
32  xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
34  crm_xml_add(msg, F_LRMD_IPC_SESSION, session_id);
35  lrmd_internal_proxy_send(lrmd, msg);
36  free_xml(msg);
37 }
38 
44 void
46 {
47  xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
49  lrmd_internal_proxy_send(lrmd, msg);
50  free_xml(msg);
51 }
52 
59 void
61 {
62  xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
64  lrmd_internal_proxy_send(lrmd, msg);
65  free_xml(msg);
66 }
67 
68 void
70 {
71  /* sending to the remote node an event msg. */
72  xmlNode *event = create_xml_node(NULL, T_LRMD_IPC_PROXY);
75  add_message_xml(event, F_LRMD_IPC_MSG, msg);
76  crm_log_xml_explicit(event, "EventForProxy");
77  lrmd_internal_proxy_send(proxy->lrm, event);
78  free_xml(event);
79 }
80 
81 void
82 remote_proxy_relay_response(remote_proxy_t *proxy, xmlNode *msg, int msg_id)
83 {
84  /* sending to the remote node a response msg. */
85  xmlNode *response = create_xml_node(NULL, T_LRMD_IPC_PROXY);
87  crm_xml_add(response, F_LRMD_IPC_SESSION, proxy->session_id);
88  crm_xml_add_int(response, F_LRMD_IPC_MSG_ID, msg_id);
89  add_message_xml(response, F_LRMD_IPC_MSG, msg);
90  lrmd_internal_proxy_send(proxy->lrm, response);
91  free_xml(response);
92 }
93 
94 static void
95 remote_proxy_end_session(remote_proxy_t *proxy)
96 {
97  if (proxy == NULL) {
98  return;
99  }
100  crm_trace("ending session ID %s", proxy->session_id);
101 
102  if (proxy->source) {
104  }
105 }
106 
107 void
109 {
110  remote_proxy_t *proxy = data;
111 
112  crm_trace("freed proxy session ID %s", proxy->session_id);
113  free(proxy->node_name);
114  free(proxy->session_id);
115  free(proxy);
116 }
117 
118 int
119 remote_proxy_dispatch(const char *buffer, ssize_t length, gpointer userdata)
120 {
121  // Async responses from cib and friends to clients via pacemaker-remoted
122  xmlNode *xml = NULL;
123  uint32_t flags = 0;
124  remote_proxy_t *proxy = userdata;
125 
126  xml = string2xml(buffer);
127  if (xml == NULL) {
128  crm_warn("Received a NULL msg from IPC service.");
129  return 1;
130  }
131 
132  flags = crm_ipc_buffer_flags(proxy->ipc);
134  crm_trace("Passing response back to %.8s on %s: %.200s - request id: %d", proxy->session_id, proxy->node_name, buffer, proxy->last_request_id);
135  remote_proxy_relay_response(proxy, xml, proxy->last_request_id);
136  proxy->last_request_id = 0;
137 
138  } else {
139  crm_trace("Passing event back to %.8s on %s: %.200s", proxy->session_id, proxy->node_name, buffer);
140  remote_proxy_relay_event(proxy, xml);
141  }
142  free_xml(xml);
143  return 1;
144 }
145 
146 
147 void
148 remote_proxy_disconnected(gpointer userdata)
149 {
150  remote_proxy_t *proxy = userdata;
151 
152  crm_trace("destroying %p", proxy);
153 
154  proxy->source = NULL;
155  proxy->ipc = NULL;
156 
157  if(proxy->lrm) {
158  remote_proxy_notify_destroy(proxy->lrm, proxy->session_id);
159  proxy->lrm = NULL;
160  }
161 
162  g_hash_table_remove(proxy_table, proxy->session_id);
163 }
164 
166 remote_proxy_new(lrmd_t *lrmd, struct ipc_client_callbacks *proxy_callbacks,
167  const char *node_name, const char *session_id, const char *channel)
168 {
169  remote_proxy_t *proxy = NULL;
170 
171  if(channel == NULL) {
172  crm_err("No channel specified to proxy");
173  remote_proxy_notify_destroy(lrmd, session_id);
174  return NULL;
175  }
176 
177  proxy = calloc(1, sizeof(remote_proxy_t));
178 
179  proxy->node_name = strdup(node_name);
180  proxy->session_id = strdup(session_id);
181  proxy->lrm = lrmd;
182 
184  && !strcmp(pcmk__message_name(channel), CRM_SYSTEM_CRMD)) {
185  // The controller doesn't need to connect to itself
186  proxy->is_local = TRUE;
187 
188  } else {
189  proxy->source = mainloop_add_ipc_client(channel, G_PRIORITY_LOW, 0, proxy, proxy_callbacks);
190  proxy->ipc = mainloop_get_ipc_client(proxy->source);
191  if (proxy->source == NULL) {
192  remote_proxy_free(proxy);
193  remote_proxy_notify_destroy(lrmd, session_id);
194  return NULL;
195  }
196  }
197 
198  crm_trace("new remote proxy client established to %s on %s, session id %s",
199  channel, node_name, session_id);
200  g_hash_table_insert(proxy_table, proxy->session_id, proxy);
201 
202  return proxy;
203 }
204 
205 void
206 remote_proxy_cb(lrmd_t *lrmd, const char *node_name, xmlNode *msg)
207 {
208  const char *op = crm_element_value(msg, F_LRMD_IPC_OP);
209  const char *session = crm_element_value(msg, F_LRMD_IPC_SESSION);
210  remote_proxy_t *proxy = g_hash_table_lookup(proxy_table, session);
211  int msg_id = 0;
212 
213  /* sessions are raw ipc connections to IPC,
214  * all we do is proxy requests/responses exactly
215  * like they are given to us at the ipc level. */
216 
217  CRM_CHECK(op != NULL, return);
218  CRM_CHECK(session != NULL, return);
219 
221  /* This is msg from remote ipc client going to real ipc server */
222 
223  if (pcmk__str_eq(op, LRMD_IPC_OP_DESTROY, pcmk__str_casei)) {
224  remote_proxy_end_session(proxy);
225 
226  } else if (pcmk__str_eq(op, LRMD_IPC_OP_REQUEST, pcmk__str_casei)) {
227  int flags = 0;
228  xmlNode *request = get_message_xml(msg, F_LRMD_IPC_MSG);
229  const char *name = crm_element_value(msg, F_LRMD_IPC_CLIENT);
230 
231  CRM_CHECK(request != NULL, return);
232 
233  if (proxy == NULL) {
234  /* proxy connection no longer exists */
235  remote_proxy_notify_destroy(lrmd, session);
236  return;
237  }
238 
239  // Controller requests MUST be handled by the controller, not us
240  CRM_CHECK(proxy->is_local == FALSE,
241  remote_proxy_end_session(proxy); return);
242 
243  if (crm_ipc_connected(proxy->ipc) == FALSE) {
244  remote_proxy_end_session(proxy);
245  return;
246  }
247  proxy->last_request_id = 0;
249  crm_xml_add(request, XML_ACL_TAG_ROLE, "pacemaker-remote");
250 
251 #if ENABLE_ACL
252  CRM_ASSERT(node_name);
253  pcmk__update_acl_user(request, F_LRMD_IPC_USER, node_name);
254 #endif
255 
257  const char *type = crm_element_value(request, F_TYPE);
258  int rc = 0;
259 
260  if (pcmk__str_eq(type, T_ATTRD, pcmk__str_casei)
261  && crm_element_value(request,
262  PCMK__XA_ATTR_NODE_NAME) == NULL) {
264  }
265 
266  rc = crm_ipc_send(proxy->ipc, request, flags, 5000, NULL);
267 
268  if(rc < 0) {
269  xmlNode *op_reply = create_xml_node(NULL, "nack");
270 
271  crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
272  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
273 
274  /* Send a n'ack so the caller doesn't block */
275  crm_xml_add(op_reply, "function", __func__);
276  crm_xml_add_int(op_reply, "line", __LINE__);
277  crm_xml_add_int(op_reply, "rc", rc);
278  remote_proxy_relay_response(proxy, op_reply, msg_id);
279  free_xml(op_reply);
280 
281  } else {
282  crm_trace("Relayed %s request %d from %s to %s for %s",
283  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
284  proxy->last_request_id = msg_id;
285  }
286 
287  } else {
288  int rc = pcmk_ok;
289  xmlNode *op_reply = NULL;
290  // @COMPAT pacemaker_remoted <= 1.1.10
291 
292  crm_trace("Relaying %s request %d from %s to %s for %s",
293  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
294 
295  rc = crm_ipc_send(proxy->ipc, request, flags, 10000, &op_reply);
296  if(rc < 0) {
297  crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
298  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
299  } else {
300  crm_trace("Relayed %s request %d from %s to %s for %s",
301  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
302  }
303 
304  if(op_reply) {
305  remote_proxy_relay_response(proxy, op_reply, msg_id);
306  free_xml(op_reply);
307  }
308  }
309  } else {
310  crm_err("Unknown proxy operation: %s", op);
311  }
312 }
Services API.
#define T_ATTRD
Definition: msg_xml.h:46
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:215
const char * pcmk__message_name(const char *name)
Get name to be used as identifier for cluster messages.
Definition: messages.c:182
void remote_proxy_disconnected(gpointer userdata)
Definition: proxy_common.c:148
A dumping ground.
#define F_TYPE
Definition: msg_xml.h:30
xmlNode * get_message_xml(xmlNode *msg, const char *field)
Definition: messages.c:154
const char * pcmk_strerror(int rc)
Definition: results.c:58
#define F_LRMD_IPC_CLIENT
Definition: lrmd.h:117
#define LRMD_IPC_OP_SHUTDOWN_NACK
Definition: lrmd.h:112
#define T_LRMD_IPC_PROXY
Definition: lrmd.h:126
#define F_LRMD_IPC_SESSION
Definition: lrmd.h:116
void remote_proxy_ack_shutdown(lrmd_t *lrmd)
Send an acknowledgment of a remote proxy shutdown request.
Definition: proxy_common.c:45
void remote_proxy_relay_response(remote_proxy_t *proxy, xmlNode *msg, int msg_id)
Definition: proxy_common.c:82
#define LRMD_IPC_OP_DESTROY
Definition: lrmd.h:106
#define LRMD_IPC_OP_RESPONSE
Definition: lrmd.h:109
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition: nvpair.c:425
uint32_t last_request_id
Definition: lrmd_internal.h:45
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:317
Resource agent executor.
char * crm_system_name
Definition: utils.c:54
void remote_proxy_nack_shutdown(lrmd_t *lrmd)
We're not going to shutdown as response to a remote proxy shutdown request.
Definition: proxy_common.c:60
uint32_t crm_ipc_buffer_flags(crm_ipc_t *client)
Definition: ipc_client.c:1053
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:559
Wrappers for and extensions to glib mainloop.
#define F_LRMD_IPC_OP
Definition: lrmd.h:114
xmlNode * string2xml(const char *input)
Definition: xml.c:835
#define F_LRMD_IPC_MSG_ID
Definition: lrmd.h:120
void remote_proxy_free(gpointer data)
Definition: proxy_common.c:108
remote_proxy_t * remote_proxy_new(lrmd_t *lrmd, struct ipc_client_callbacks *proxy_callbacks, const char *node_name, const char *session_id, const char *channel)
Definition: proxy_common.c:166
#define XML_ACL_TAG_ROLE
Definition: msg_xml.h:380
#define crm_warn(fmt, args...)
Definition: logging.h:348
void remote_proxy_relay_event(remote_proxy_t *proxy, xmlNode *msg)
Definition: proxy_common.c:69
int rc
Definition: pcmk_fence.c:35
#define LRMD_IPC_OP_REQUEST
Definition: lrmd.h:108
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:523
int remote_proxy_dispatch(const char *buffer, ssize_t length, gpointer userdata)
Definition: proxy_common.c:119
#define crm_trace(fmt, args...)
Definition: logging.h:353
#define crm_log_xml_explicit(xml, text)
Definition: logging.h:363
const char * pcmk__update_acl_user(xmlNode *request, const char *field, const char *peer_user)
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:196
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:663
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:900
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition: messages.c:162
void free_xml(xmlNode *child)
Definition: xml.c:790
#define CRM_SYSTEM_CRMD
Definition: crm.h:102
crm_ipc_t * ipc
Definition: lrmd_internal.h:43
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc_client.c:907
int lrmd_internal_proxy_send(lrmd_t *lrmd, xmlNode *msg)
Definition: lrmd_client.c:1719
#define LRMD_IPC_OP_SHUTDOWN_ACK
Definition: lrmd.h:111
#define F_LRMD_IPC_MSG_FLAGS
Definition: lrmd.h:121
#define PCMK__XA_ATTR_NODE_NAME
Definition: crm_internal.h:49
const char * crm_ipc_name(crm_ipc_t *client)
Definition: ipc_client.c:1067
Cluster status and scheduling.
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:906
#define crm_err(fmt, args...)
Definition: logging.h:347
#define CRM_ASSERT(expr)
Definition: results.h:42
Cluster Configuration.
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
Definition: ipc_client.c:1139
mainloop_io_t * source
Definition: lrmd_internal.h:44
char data[0]
Definition: internal.h:90
Definition: lrmd.h:532
#define pcmk_ok
Definition: results.h:67
#define F_LRMD_IPC_USER
Definition: lrmd.h:118
GHashTable * proxy_table
Definition: proxy_common.c:26
#define LRMD_IPC_OP_EVENT
Definition: lrmd.h:107
mainloop_io_t * mainloop_add_ipc_client(const char *name, int priority, size_t max_size, void *userdata, struct ipc_client_callbacks *callbacks)
Definition: mainloop.c:880
char * name
Definition: pcmk_fence.c:31
gboolean is_local
Definition: lrmd_internal.h:41
uint64_t flags
Definition: remote.c:149
enum crm_ais_msg_types type
Definition: internal.h:83
void remote_proxy_cb(lrmd_t *lrmd, const char *node_name, xmlNode *msg)
Definition: proxy_common.c:206
#define F_LRMD_IPC_MSG
Definition: lrmd.h:119