pacemaker  1.1.18-7fdfbbe
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
proxy_common.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 David Vossel <davidvossel@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  */
19 
20 #include <crm_internal.h>
21 
22 #include <glib.h>
23 #include <unistd.h>
24 
25 #include <crm/crm.h>
26 #include <crm/msg_xml.h>
27 #include <crm/services.h>
28 #include <crm/common/mainloop.h>
29 
30 #include <crm/pengine/status.h>
31 #include <crm/cib.h>
32 #include <crm/lrmd.h>
33 
34 int lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg);
35 GHashTable *proxy_table = NULL;
36 
37 static void
38 remote_proxy_notify_destroy(lrmd_t *lrmd, const char *session_id)
39 {
40  /* sending to the remote node that an ipc connection has been destroyed */
41  xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
43  crm_xml_add(msg, F_LRMD_IPC_SESSION, session_id);
44  lrmd_internal_proxy_send(lrmd, msg);
45  free_xml(msg);
46 }
47 
53 void
55 {
56  xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
58  lrmd_internal_proxy_send(lrmd, msg);
59  free_xml(msg);
60 }
61 
68 void
70 {
71  xmlNode *msg = create_xml_node(NULL, T_LRMD_IPC_PROXY);
73  lrmd_internal_proxy_send(lrmd, msg);
74  free_xml(msg);
75 }
76 
77 void
79 {
80  /* sending to the remote node an event msg. */
81  xmlNode *event = create_xml_node(NULL, T_LRMD_IPC_PROXY);
84  add_message_xml(event, F_LRMD_IPC_MSG, msg);
85  crm_log_xml_explicit(event, "EventForProxy");
86  lrmd_internal_proxy_send(proxy->lrm, event);
87  free_xml(event);
88 }
89 
90 void
91 remote_proxy_relay_response(remote_proxy_t *proxy, xmlNode *msg, int msg_id)
92 {
93  /* sending to the remote node a response msg. */
94  xmlNode *response = create_xml_node(NULL, T_LRMD_IPC_PROXY);
96  crm_xml_add(response, F_LRMD_IPC_SESSION, proxy->session_id);
97  crm_xml_add_int(response, F_LRMD_IPC_MSG_ID, msg_id);
98  add_message_xml(response, F_LRMD_IPC_MSG, msg);
99  lrmd_internal_proxy_send(proxy->lrm, response);
100  free_xml(response);
101 }
102 
103 static void
104 remote_proxy_end_session(remote_proxy_t *proxy)
105 {
106  if (proxy == NULL) {
107  return;
108  }
109  crm_trace("ending session ID %s", proxy->session_id);
110 
111  if (proxy->source) {
113  }
114 }
115 
116 void
118 {
119  remote_proxy_t *proxy = data;
120 
121  crm_trace("freed proxy session ID %s", proxy->session_id);
122  free(proxy->node_name);
123  free(proxy->session_id);
124  free(proxy);
125 }
126 
127 int
128 remote_proxy_dispatch(const char *buffer, ssize_t length, gpointer userdata)
129 {
130  /* Async responses from cib and friends back to clients via pacemaker_remoted */
131  xmlNode *xml = NULL;
132  uint32_t flags = 0;
133  remote_proxy_t *proxy = userdata;
134 
135  xml = string2xml(buffer);
136  if (xml == NULL) {
137  crm_warn("Received a NULL msg from IPC service.");
138  return 1;
139  }
140 
141  flags = crm_ipc_buffer_flags(proxy->ipc);
142  if (flags & crm_ipc_proxied_relay_response) {
143  crm_trace("Passing response back to %.8s on %s: %.200s - request id: %d", proxy->session_id, proxy->node_name, buffer, proxy->last_request_id);
144  remote_proxy_relay_response(proxy, xml, proxy->last_request_id);
145  proxy->last_request_id = 0;
146 
147  } else {
148  crm_trace("Passing event back to %.8s on %s: %.200s", proxy->session_id, proxy->node_name, buffer);
149  remote_proxy_relay_event(proxy, xml);
150  }
151  free_xml(xml);
152  return 1;
153 }
154 
155 
156 void
157 remote_proxy_disconnected(gpointer userdata)
158 {
159  remote_proxy_t *proxy = userdata;
160 
161  crm_trace("destroying %p", proxy);
162 
163  proxy->source = NULL;
164  proxy->ipc = NULL;
165 
166  if(proxy->lrm) {
167  remote_proxy_notify_destroy(proxy->lrm, proxy->session_id);
168  proxy->lrm = NULL;
169  }
170 
171  g_hash_table_remove(proxy_table, proxy->session_id);
172 }
173 
175 remote_proxy_new(lrmd_t *lrmd, struct ipc_client_callbacks *proxy_callbacks,
176  const char *node_name, const char *session_id, const char *channel)
177 {
178  remote_proxy_t *proxy = NULL;
179 
180  if(channel == NULL) {
181  crm_err("No channel specified to proxy");
182  remote_proxy_notify_destroy(lrmd, session_id);
183  return NULL;
184  }
185 
186  proxy = calloc(1, sizeof(remote_proxy_t));
187 
188  proxy->node_name = strdup(node_name);
189  proxy->session_id = strdup(session_id);
190  proxy->lrm = lrmd;
191 
193  && safe_str_eq(channel, CRM_SYSTEM_CRMD)) {
194  /* The crmd doesn't need to connect to itself */
195  proxy->is_local = TRUE;
196 
197  } else {
198  proxy->source = mainloop_add_ipc_client(channel, G_PRIORITY_LOW, 0, proxy, proxy_callbacks);
199  proxy->ipc = mainloop_get_ipc_client(proxy->source);
200  if (proxy->source == NULL) {
201  remote_proxy_free(proxy);
202  remote_proxy_notify_destroy(lrmd, session_id);
203  return NULL;
204  }
205  }
206 
207  crm_trace("new remote proxy client established to %s on %s, session id %s",
208  channel, node_name, session_id);
209  g_hash_table_insert(proxy_table, proxy->session_id, proxy);
210 
211  return proxy;
212 }
213 
214 void
215 remote_proxy_cb(lrmd_t *lrmd, const char *node_name, xmlNode *msg)
216 {
217  const char *op = crm_element_value(msg, F_LRMD_IPC_OP);
218  const char *session = crm_element_value(msg, F_LRMD_IPC_SESSION);
219  remote_proxy_t *proxy = g_hash_table_lookup(proxy_table, session);
220  int msg_id = 0;
221 
222  /* sessions are raw ipc connections to IPC,
223  * all we do is proxy requests/responses exactly
224  * like they are given to us at the ipc level. */
225 
226  CRM_CHECK(op != NULL, return);
227  CRM_CHECK(session != NULL, return);
228 
230  /* This is msg from remote ipc client going to real ipc server */
231 
232  if (safe_str_eq(op, LRMD_IPC_OP_DESTROY)) {
233  remote_proxy_end_session(proxy);
234 
235  } else if (safe_str_eq(op, LRMD_IPC_OP_REQUEST)) {
236  int flags = 0;
237  xmlNode *request = get_message_xml(msg, F_LRMD_IPC_MSG);
238  const char *name = crm_element_value(msg, F_LRMD_IPC_CLIENT);
239 
240  CRM_CHECK(request != NULL, return);
241 
242  if (proxy == NULL) {
243  /* proxy connection no longer exists */
244  remote_proxy_notify_destroy(lrmd, session);
245  return;
246  }
247 
248  /* crmd requests MUST be handled by the crmd, not us */
249  CRM_CHECK(proxy->is_local == FALSE,
250  remote_proxy_end_session(proxy); return);
251 
252  if (crm_ipc_connected(proxy->ipc) == FALSE) {
253  remote_proxy_end_session(proxy);
254  return;
255  }
256  proxy->last_request_id = 0;
258  crm_xml_add(request, XML_ACL_TAG_ROLE, "pacemaker-remote");
259 
260 #if ENABLE_ACL
261  CRM_ASSERT(node_name);
262  crm_acl_get_set_user(request, F_LRMD_IPC_USER, node_name);
263 #endif
264 
265  if(is_set(flags, crm_ipc_proxied)) {
266  const char *type = crm_element_value(request, F_TYPE);
267  int rc = 0;
268 
269  if (safe_str_eq(type, T_ATTRD)
270  && crm_element_value(request, F_ATTRD_HOST) == NULL) {
271  crm_xml_add(request, F_ATTRD_HOST, proxy->node_name);
272  }
273 
274  rc = crm_ipc_send(proxy->ipc, request, flags, 5000, NULL);
275 
276  if(rc < 0) {
277  xmlNode *op_reply = create_xml_node(NULL, "nack");
278 
279  crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
280  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
281 
282  /* Send a n'ack so the caller doesn't block */
283  crm_xml_add(op_reply, "function", __FUNCTION__);
284  crm_xml_add_int(op_reply, "line", __LINE__);
285  crm_xml_add_int(op_reply, "rc", rc);
286  remote_proxy_relay_response(proxy, op_reply, msg_id);
287  free_xml(op_reply);
288 
289  } else {
290  crm_trace("Relayed %s request %d from %s to %s for %s",
291  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
292  proxy->last_request_id = msg_id;
293  }
294 
295  } else {
296  int rc = pcmk_ok;
297  xmlNode *op_reply = NULL;
298  /* For backwards compatibility with pacemaker_remoted <= 1.1.10 */
299 
300  crm_trace("Relaying %s request %d from %s to %s for %s",
301  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
302 
303  rc = crm_ipc_send(proxy->ipc, request, flags, 10000, &op_reply);
304  if(rc < 0) {
305  crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
306  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
307  } else {
308  crm_trace("Relayed %s request %d from %s to %s for %s",
309  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
310  }
311 
312  if(op_reply) {
313  remote_proxy_relay_response(proxy, op_reply, msg_id);
314  free_xml(op_reply);
315  }
316  }
317  } else {
318  crm_err("Unknown proxy operation: %s", op);
319  }
320 }
void remote_proxy_relay_response(remote_proxy_t *proxy, xmlNode *msg, int msg_id)
Definition: proxy_common.c:91
Services API.
#define T_ATTRD
Definition: msg_xml.h:50
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:164
int remote_proxy_dispatch(const char *buffer, ssize_t length, gpointer userdata)
Definition: proxy_common.c:128
A dumping ground.
#define F_TYPE
Definition: msg_xml.h:34
xmlNode * get_message_xml(xmlNode *msg, const char *field)
Definition: xml.c:3163
#define F_LRMD_IPC_CLIENT
Definition: lrmd.h:123
#define LRMD_IPC_OP_SHUTDOWN_NACK
Definition: lrmd.h:118
#define T_LRMD_IPC_PROXY
Definition: lrmd.h:133
#define F_LRMD_IPC_SESSION
Definition: lrmd.h:122
const char * pcmk_strerror(int rc)
Definition: logging.c:1135
#define F_ATTRD_HOST
Definition: crm_internal.h:271
#define LRMD_IPC_OP_DESTROY
Definition: lrmd.h:112
#define LRMD_IPC_OP_RESPONSE
Definition: lrmd.h:115
#define pcmk_ok
Definition: error.h:42
uint32_t last_request_id
Definition: crm_internal.h:370
void remote_proxy_relay_event(remote_proxy_t *proxy, xmlNode *msg)
Definition: proxy_common.c:78
void remote_proxy_ack_shutdown(lrmd_t *lrmd)
Send an acknowledgment of a remote proxy shutdown request.
Definition: proxy_common.c:54
Local Resource Manager.
char * crm_system_name
Definition: utils.c:70
int lrmd_internal_proxy_send(lrmd_t *lrmd, xmlNode *msg)
Definition: lrmd_client.c:1559
uint32_t crm_ipc_buffer_flags(crm_ipc_t *client)
Definition: ipc.c:1103
Wrappers for and extensions to glib mainloop.
#define F_LRMD_IPC_OP
Definition: lrmd.h:120
xmlNode * string2xml(const char *input)
Definition: xml.c:2750
#define F_LRMD_IPC_MSG_ID
Definition: lrmd.h:127
#define XML_ACL_TAG_ROLE
Definition: msg_xml.h:398
#define crm_warn(fmt, args...)
Definition: logging.h:249
#define LRMD_IPC_OP_REQUEST
Definition: lrmd.h:114
void remote_proxy_cb(lrmd_t *lrmd, const char *node_name, xmlNode *msg)
Definition: proxy_common.c:215
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:175
#define crm_trace(fmt, args...)
Definition: logging.h:254
#define crm_log_xml_explicit(xml, text)
Definition: logging.h:264
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:2588
int crm_element_value_int(xmlNode *data, const char *name, int *dest)
Definition: xml.c:3844
const char * crm_element_value(xmlNode *data, const char *name)
Definition: xml.c:5165
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:795
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition: xml.c:3171
void free_xml(xmlNode *child)
Definition: xml.c:2706
void remote_proxy_disconnected(gpointer data)
Definition: proxy_common.c:157
#define CRM_SYSTEM_CRMD
Definition: crm.h:90
crm_ipc_t * ipc
Definition: crm_internal.h:368
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc.c:956
#define LRMD_IPC_OP_SHUTDOWN_ACK
Definition: lrmd.h:117
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Definition: xml.c:2490
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Definition: xml.c:2578
void remote_proxy_nack_shutdown(lrmd_t *lrmd)
We&#39;re not going to shutdown as response to a remote proxy shutdown request.
Definition: proxy_common.c:69
#define F_LRMD_IPC_MSG_FLAGS
Definition: lrmd.h:128
const char * crm_ipc_name(crm_ipc_t *client)
Definition: ipc.c:1117
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:801
#define crm_err(fmt, args...)
Definition: logging.h:248
Cluster Configuration.
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Definition: ipc.c:1199
void remote_proxy_free(gpointer data)
Definition: proxy_common.c:117
mainloop_io_t * source
Definition: crm_internal.h:369
#define uint32_t
Definition: stdint.in.h:158
#define CRM_ASSERT(expr)
Definition: error.h:35
char data[0]
Definition: internal.h:58
Definition: lrmd.h:498
const char * crm_acl_get_set_user(xmlNode *request, const char *field, const char *peer_user)
#define F_LRMD_IPC_USER
Definition: lrmd.h:125
GHashTable * proxy_table
Definition: proxy_common.c:35
#define LRMD_IPC_OP_EVENT
Definition: lrmd.h:113
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:767
#define safe_str_eq(a, b)
Definition: util.h:72
gboolean is_local
Definition: crm_internal.h:366
uint64_t flags
Definition: remote.c:156
enum crm_ais_msg_types type
Definition: internal.h:51
#define F_LRMD_IPC_MSG
Definition: lrmd.h:126