pacemaker  2.0.3-4b1f869f0f
Scalable High-Availability cluster resource manager
proxy_common.c
Go to the documentation of this file.
1 /*
2  * Copyright 2015-2018 David Vossel <davidvossel@gmail.com>
3  *
4  * This source code is licensed under the GNU Lesser General Public License
5  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
6  */
7 
8 #include <crm_internal.h>
9 
10 #include <glib.h>
11 #include <unistd.h>
12 
13 #include <crm/crm.h>
14 #include <crm/msg_xml.h>
15 #include <crm/services.h>
16 #include <crm/common/mainloop.h>
17 
18 #include <crm/pengine/status.h>
19 #include <crm/cib.h>
20 #include <crm/lrmd.h>
21 
22 int lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg);
23 GHashTable *proxy_table = NULL;
24 
25 static void
26 remote_proxy_notify_destroy(lrmd_t *lrmd, const char *session_id)
27 {
28  /* sending to the remote node that an ipc connection has been destroyed */
29  xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
31  crm_xml_add(msg, F_LRMD_IPC_SESSION, session_id);
32  lrmd_internal_proxy_send(lrmd, msg);
33  free_xml(msg);
34 }
35 
41 void
43 {
44  xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
46  lrmd_internal_proxy_send(lrmd, msg);
47  free_xml(msg);
48 }
49 
56 void
58 {
59  xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
61  lrmd_internal_proxy_send(lrmd, msg);
62  free_xml(msg);
63 }
64 
65 void
67 {
68  /* sending to the remote node an event msg. */
69  xmlNode *event = create_xml_node(NULL, T_LRMD_IPC_PROXY);
72  add_message_xml(event, F_LRMD_IPC_MSG, msg);
73  crm_log_xml_explicit(event, "EventForProxy");
74  lrmd_internal_proxy_send(proxy->lrm, event);
75  free_xml(event);
76 }
77 
78 void
79 remote_proxy_relay_response(remote_proxy_t *proxy, xmlNode *msg, int msg_id)
80 {
81  /* sending to the remote node a response msg. */
82  xmlNode *response = create_xml_node(NULL, T_LRMD_IPC_PROXY);
84  crm_xml_add(response, F_LRMD_IPC_SESSION, proxy->session_id);
85  crm_xml_add_int(response, F_LRMD_IPC_MSG_ID, msg_id);
86  add_message_xml(response, F_LRMD_IPC_MSG, msg);
87  lrmd_internal_proxy_send(proxy->lrm, response);
88  free_xml(response);
89 }
90 
91 static void
92 remote_proxy_end_session(remote_proxy_t *proxy)
93 {
94  if (proxy == NULL) {
95  return;
96  }
97  crm_trace("ending session ID %s", proxy->session_id);
98 
99  if (proxy->source) {
101  }
102 }
103 
104 void
106 {
107  remote_proxy_t *proxy = data;
108 
109  crm_trace("freed proxy session ID %s", proxy->session_id);
110  free(proxy->node_name);
111  free(proxy->session_id);
112  free(proxy);
113 }
114 
115 int
116 remote_proxy_dispatch(const char *buffer, ssize_t length, gpointer userdata)
117 {
118  // Async responses from cib and friends to clients via pacemaker-remoted
119  xmlNode *xml = NULL;
120  uint32_t flags = 0;
121  remote_proxy_t *proxy = userdata;
122 
123  xml = string2xml(buffer);
124  if (xml == NULL) {
125  crm_warn("Received a NULL msg from IPC service.");
126  return 1;
127  }
128 
129  flags = crm_ipc_buffer_flags(proxy->ipc);
131  crm_trace("Passing response back to %.8s on %s: %.200s - request id: %d", proxy->session_id, proxy->node_name, buffer, proxy->last_request_id);
132  remote_proxy_relay_response(proxy, xml, proxy->last_request_id);
133  proxy->last_request_id = 0;
134 
135  } else {
136  crm_trace("Passing event back to %.8s on %s: %.200s", proxy->session_id, proxy->node_name, buffer);
137  remote_proxy_relay_event(proxy, xml);
138  }
139  free_xml(xml);
140  return 1;
141 }
142 
143 
144 void
145 remote_proxy_disconnected(gpointer userdata)
146 {
147  remote_proxy_t *proxy = userdata;
148 
149  crm_trace("destroying %p", proxy);
150 
151  proxy->source = NULL;
152  proxy->ipc = NULL;
153 
154  if(proxy->lrm) {
155  remote_proxy_notify_destroy(proxy->lrm, proxy->session_id);
156  proxy->lrm = NULL;
157  }
158 
159  g_hash_table_remove(proxy_table, proxy->session_id);
160 }
161 
163 remote_proxy_new(lrmd_t *lrmd, struct ipc_client_callbacks *proxy_callbacks,
164  const char *node_name, const char *session_id, const char *channel)
165 {
166  remote_proxy_t *proxy = NULL;
167 
168  if(channel == NULL) {
169  crm_err("No channel specified to proxy");
170  remote_proxy_notify_destroy(lrmd, session_id);
171  return NULL;
172  }
173 
174  proxy = calloc(1, sizeof(remote_proxy_t));
175 
176  proxy->node_name = strdup(node_name);
177  proxy->session_id = strdup(session_id);
178  proxy->lrm = lrmd;
179 
181  && !strcmp(pcmk_message_name(channel), CRM_SYSTEM_CRMD)) {
182  // The controller doesn't need to connect to itself
183  proxy->is_local = TRUE;
184 
185  } else {
186  proxy->source = mainloop_add_ipc_client(channel, G_PRIORITY_LOW, 0, proxy, proxy_callbacks);
187  proxy->ipc = mainloop_get_ipc_client(proxy->source);
188  if (proxy->source == NULL) {
189  remote_proxy_free(proxy);
190  remote_proxy_notify_destroy(lrmd, session_id);
191  return NULL;
192  }
193  }
194 
195  crm_trace("new remote proxy client established to %s on %s, session id %s",
196  channel, node_name, session_id);
197  g_hash_table_insert(proxy_table, proxy->session_id, proxy);
198 
199  return proxy;
200 }
201 
202 void
203 remote_proxy_cb(lrmd_t *lrmd, const char *node_name, xmlNode *msg)
204 {
205  const char *op = crm_element_value(msg, F_LRMD_IPC_OP);
206  const char *session = crm_element_value(msg, F_LRMD_IPC_SESSION);
207  remote_proxy_t *proxy = g_hash_table_lookup(proxy_table, session);
208  int msg_id = 0;
209 
210  /* sessions are raw ipc connections to IPC,
211  * all we do is proxy requests/responses exactly
212  * like they are given to us at the ipc level. */
213 
214  CRM_CHECK(op != NULL, return);
215  CRM_CHECK(session != NULL, return);
216 
218  /* This is msg from remote ipc client going to real ipc server */
219 
220  if (safe_str_eq(op, LRMD_IPC_OP_DESTROY)) {
221  remote_proxy_end_session(proxy);
222 
223  } else if (safe_str_eq(op, LRMD_IPC_OP_REQUEST)) {
224  int flags = 0;
225  xmlNode *request = get_message_xml(msg, F_LRMD_IPC_MSG);
226  const char *name = crm_element_value(msg, F_LRMD_IPC_CLIENT);
227 
228  CRM_CHECK(request != NULL, return);
229 
230  if (proxy == NULL) {
231  /* proxy connection no longer exists */
232  remote_proxy_notify_destroy(lrmd, session);
233  return;
234  }
235 
236  // Controller requests MUST be handled by the controller, not us
237  CRM_CHECK(proxy->is_local == FALSE,
238  remote_proxy_end_session(proxy); return);
239 
240  if (crm_ipc_connected(proxy->ipc) == FALSE) {
241  remote_proxy_end_session(proxy);
242  return;
243  }
244  proxy->last_request_id = 0;
246  crm_xml_add(request, XML_ACL_TAG_ROLE, "pacemaker-remote");
247 
248 #if ENABLE_ACL
249  CRM_ASSERT(node_name);
250  crm_acl_get_set_user(request, F_LRMD_IPC_USER, node_name);
251 #endif
252 
253  if(is_set(flags, crm_ipc_proxied)) {
254  const char *type = crm_element_value(request, F_TYPE);
255  int rc = 0;
256 
257  if (safe_str_eq(type, T_ATTRD)
258  && crm_element_value(request, F_ATTRD_HOST) == NULL) {
259  crm_xml_add(request, F_ATTRD_HOST, proxy->node_name);
260  }
261 
262  rc = crm_ipc_send(proxy->ipc, request, flags, 5000, NULL);
263 
264  if(rc < 0) {
265  xmlNode *op_reply = create_xml_node(NULL, "nack");
266 
267  crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
268  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
269 
270  /* Send a n'ack so the caller doesn't block */
271  crm_xml_add(op_reply, "function", __FUNCTION__);
272  crm_xml_add_int(op_reply, "line", __LINE__);
273  crm_xml_add_int(op_reply, "rc", rc);
274  remote_proxy_relay_response(proxy, op_reply, msg_id);
275  free_xml(op_reply);
276 
277  } else {
278  crm_trace("Relayed %s request %d from %s to %s for %s",
279  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
280  proxy->last_request_id = msg_id;
281  }
282 
283  } else {
284  int rc = pcmk_ok;
285  xmlNode *op_reply = NULL;
286  // @COMPAT pacemaker_remoted <= 1.1.10
287 
288  crm_trace("Relaying %s request %d from %s to %s for %s",
289  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
290 
291  rc = crm_ipc_send(proxy->ipc, request, flags, 10000, &op_reply);
292  if(rc < 0) {
293  crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
294  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
295  } else {
296  crm_trace("Relayed %s request %d from %s to %s for %s",
297  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
298  }
299 
300  if(op_reply) {
301  remote_proxy_relay_response(proxy, op_reply, msg_id);
302  free_xml(op_reply);
303  }
304  }
305  } else {
306  crm_err("Unknown proxy operation: %s", op);
307  }
308 }
crm_acl_get_set_user
const char * crm_acl_get_set_user(xmlNode *request, const char *field, const char *peer_user)
remote_proxy_ack_shutdown
void remote_proxy_ack_shutdown(lrmd_t *lrmd)
Send an acknowledgment of a remote proxy shutdown request.
Definition: proxy_common.c:42
F_LRMD_IPC_MSG_FLAGS
#define F_LRMD_IPC_MSG_FLAGS
Definition: lrmd.h:121
flags
uint64_t flags
Definition: remote.c:5
msg_xml.h
remote_proxy_relay_response
void remote_proxy_relay_response(remote_proxy_t *proxy, xmlNode *msg, int msg_id)
Definition: proxy_common.c:79
data
char data[0]
Definition: internal.h:12
remote_proxy_s
Definition: crm_internal.h:276
crm_ipc_proxied
@ crm_ipc_proxied
Definition: ipc.h:45
crm_element_value_int
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:555
mainloop_get_ipc_client
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:932
create_xml_node
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:1970
CRM_SYSTEM_CRMD
#define CRM_SYSTEM_CRMD
Definition: crm.h:103
lrmd_s
Definition: lrmd.h:533
pcmk_strerror
const char * pcmk_strerror(int rc)
Definition: results.c:188
CRM_CHECK
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:157
remote_proxy_nack_shutdown
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:57
type
enum crm_ais_msg_types type
Definition: internal.h:5
crm_err
#define crm_err(fmt, args...)
Definition: logging.h:241
F_LRMD_IPC_USER
#define F_LRMD_IPC_USER
Definition: lrmd.h:118
T_LRMD_IPC_PROXY
#define T_LRMD_IPC_PROXY
Definition: lrmd.h:126
crm_ipc_send
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Definition: ipc.c:1321
crm_ipc_buffer_flags
uint32_t crm_ipc_buffer_flags(crm_ipc_t *client)
Definition: ipc.c:1225
crm_trace
#define crm_trace(fmt, args...)
Definition: logging.h:247
safe_str_eq
#define safe_str_eq(a, b)
Definition: util.h:61
crm_warn
#define crm_warn(fmt, args...)
Definition: logging.h:242
free_xml
void free_xml(xmlNode *child)
Definition: xml.c:2130
LRMD_IPC_OP_DESTROY
#define LRMD_IPC_OP_DESTROY
Definition: lrmd.h:106
remote_proxy_dispatch
int remote_proxy_dispatch(const char *buffer, ssize_t length, gpointer userdata)
Definition: proxy_common.c:116
remote_proxy_s::last_request_id
uint32_t last_request_id
Definition: crm_internal.h:284
mainloop.h
Wrappers for and extensions to glib mainloop.
add_message_xml
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition: xml.c:2618
remote_proxy_free
void remote_proxy_free(gpointer data)
Definition: proxy_common.c:105
XML_ACL_TAG_ROLE
#define XML_ACL_TAG_ROLE
Definition: msg_xml.h:370
crm_log_xml_explicit
#define crm_log_xml_explicit(xml, text)
Definition: logging.h:257
F_LRMD_IPC_OP
#define F_LRMD_IPC_OP
Definition: lrmd.h:114
LRMD_IPC_OP_EVENT
#define LRMD_IPC_OP_EVENT
Definition: lrmd.h:107
crm_ipc_connected
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc.c:1076
remote_proxy_new
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:163
string2xml
xmlNode * string2xml(const char *input)
Definition: xml.c:2174
remote_proxy_relay_event
void remote_proxy_relay_event(remote_proxy_t *proxy, xmlNode *msg)
Definition: proxy_common.c:66
crm_system_name
char * crm_system_name
Definition: utils.c:61
LRMD_IPC_OP_RESPONSE
#define LRMD_IPC_OP_RESPONSE
Definition: lrmd.h:109
T_ATTRD
#define T_ATTRD
Definition: msg_xml.h:46
ipc_client_callbacks
Definition: mainloop.h:74
get_message_xml
xmlNode * get_message_xml(xmlNode *msg, const char *field)
Definition: xml.c:2610
remote_proxy_s::lrm
lrmd_t * lrm
Definition: crm_internal.h:285
crm_xml_add
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:313
lrmd.h
Resource agent executor.
crm_element_value
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:519
crm_ipc_name
const char * crm_ipc_name(crm_ipc_t *client)
Definition: ipc.c:1239
cib.h
Cluster Configuration.
lrmd_internal_proxy_send
int lrmd_internal_proxy_send(lrmd_t *lrmd, xmlNode *msg)
Definition: lrmd_client.c:1656
crm_ipc_proxied_relay_response
@ crm_ipc_proxied_relay_response
Definition: ipc.h:51
pcmk_message_name
const char * pcmk_message_name(const char *name)
Get name to be used as identifier for cluster messages.
Definition: utils.c:1109
mainloop_del_ipc_client
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:926
remote_proxy_s::node_name
char * node_name
Definition: crm_internal.h:277
crm_xml_add_int
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:421
LRMD_IPC_OP_REQUEST
#define LRMD_IPC_OP_REQUEST
Definition: lrmd.h:108
F_TYPE
#define F_TYPE
Definition: msg_xml.h:30
services.h
Services API.
F_LRMD_IPC_MSG
#define F_LRMD_IPC_MSG
Definition: lrmd.h:119
CRM_ASSERT
#define CRM_ASSERT(expr)
Definition: results.h:42
F_LRMD_IPC_CLIENT
#define F_LRMD_IPC_CLIENT
Definition: lrmd.h:117
F_LRMD_IPC_SESSION
#define F_LRMD_IPC_SESSION
Definition: lrmd.h:116
LRMD_IPC_OP_SHUTDOWN_NACK
#define LRMD_IPC_OP_SHUTDOWN_NACK
Definition: lrmd.h:112
LRMD_IPC_OP_SHUTDOWN_ACK
#define LRMD_IPC_OP_SHUTDOWN_ACK
Definition: lrmd.h:111
remote_proxy_s::ipc
crm_ipc_t * ipc
Definition: crm_internal.h:282
remote_proxy_s::session_id
char * session_id
Definition: crm_internal.h:278
proxy_table
GHashTable * proxy_table
Definition: proxy_common.c:23
remote_proxy_s::is_local
gboolean is_local
Definition: crm_internal.h:280
remote_proxy_s::source
mainloop_io_t * source
Definition: crm_internal.h:283
F_LRMD_IPC_MSG_ID
#define F_LRMD_IPC_MSG_ID
Definition: lrmd.h:120
mainloop_add_ipc_client
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:898
crm_internal.h
remote_proxy_cb
void remote_proxy_cb(lrmd_t *lrmd, const char *node_name, xmlNode *msg)
Definition: proxy_common.c:203
status.h
Cluster status and scheduling.
crm.h
A dumping ground.
pcmk_ok
#define pcmk_ok
Definition: results.h:57
F_ATTRD_HOST
#define F_ATTRD_HOST
Definition: crm_internal.h:192
remote_proxy_disconnected
void remote_proxy_disconnected(gpointer userdata)
Definition: proxy_common.c:145