pacemaker  2.1.8-3980678f03
Scalable High-Availability cluster resource manager
proxy_common.c
Go to the documentation of this file.
1 /*
2  * Copyright 2015-2024 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/common/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 = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
34  crm_xml_add(msg, PCMK__XA_LRMD_IPC_SESSION, session_id);
35  lrmd_internal_proxy_send(lrmd, msg);
36  free_xml(msg);
37 }
38 
45 void
47 {
48  xmlNode *msg = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
50  lrmd_internal_proxy_send(lrmd, msg);
51  free_xml(msg);
52 }
53 
60 void
62 {
63  xmlNode *msg = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
65  lrmd_internal_proxy_send(lrmd, msg);
66  free_xml(msg);
67 }
68 
69 void
71 {
72  /* sending to the remote node an event msg. */
73  xmlNode *event = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
74  xmlNode *wrapper = NULL;
75 
78 
79  wrapper = pcmk__xe_create(event, PCMK__XE_LRMD_IPC_MSG);
80  pcmk__xml_copy(wrapper, msg);
81 
82  crm_log_xml_explicit(event, "EventForProxy");
83  lrmd_internal_proxy_send(proxy->lrm, event);
84  free_xml(event);
85 }
86 
87 void
88 remote_proxy_relay_response(remote_proxy_t *proxy, xmlNode *msg, int msg_id)
89 {
90  /* sending to the remote node a response msg. */
91  xmlNode *response = pcmk__xe_create(NULL, PCMK__XE_LRMD_IPC_PROXY);
92  xmlNode *wrapper = NULL;
93 
96  crm_xml_add_int(response, PCMK__XA_LRMD_IPC_MSG_ID, msg_id);
97 
98  wrapper = pcmk__xe_create(response, PCMK__XE_LRMD_IPC_MSG);
99  pcmk__xml_copy(wrapper, msg);
100 
101  lrmd_internal_proxy_send(proxy->lrm, response);
102  free_xml(response);
103 }
104 
105 static void
106 remote_proxy_end_session(remote_proxy_t *proxy)
107 {
108  if (proxy == NULL) {
109  return;
110  }
111  crm_trace("ending session ID %s", proxy->session_id);
112 
113  if (proxy->source) {
115  }
116 }
117 
118 void
120 {
121  remote_proxy_t *proxy = data;
122 
123  crm_trace("freed proxy session ID %s", proxy->session_id);
124  free(proxy->node_name);
125  free(proxy->session_id);
126  free(proxy);
127 }
128 
129 int
130 remote_proxy_dispatch(const char *buffer, ssize_t length, gpointer userdata)
131 {
132  // Async responses from cib and friends to clients via pacemaker-remoted
133  xmlNode *xml = NULL;
134  uint32_t flags = 0;
135  remote_proxy_t *proxy = userdata;
136 
137  xml = pcmk__xml_parse(buffer);
138  if (xml == NULL) {
139  crm_warn("Received a NULL msg from IPC service.");
140  return 1;
141  }
142 
143  flags = crm_ipc_buffer_flags(proxy->ipc);
145  crm_trace("Passing response back to %.8s on %s: %.200s - request id: %d", proxy->session_id, proxy->node_name, buffer, proxy->last_request_id);
146  remote_proxy_relay_response(proxy, xml, proxy->last_request_id);
147  proxy->last_request_id = 0;
148 
149  } else {
150  crm_trace("Passing event back to %.8s on %s: %.200s", proxy->session_id, proxy->node_name, buffer);
151  remote_proxy_relay_event(proxy, xml);
152  }
153  free_xml(xml);
154  return 1;
155 }
156 
157 
158 void
159 remote_proxy_disconnected(gpointer userdata)
160 {
161  remote_proxy_t *proxy = userdata;
162 
163  crm_trace("destroying %p", proxy);
164 
165  proxy->source = NULL;
166  proxy->ipc = NULL;
167 
168  if(proxy->lrm) {
169  remote_proxy_notify_destroy(proxy->lrm, proxy->session_id);
170  proxy->lrm = NULL;
171  }
172 
173  g_hash_table_remove(proxy_table, proxy->session_id);
174 }
175 
177 remote_proxy_new(lrmd_t *lrmd, struct ipc_client_callbacks *proxy_callbacks,
178  const char *node_name, const char *session_id, const char *channel)
179 {
180  remote_proxy_t *proxy = NULL;
181 
182  if(channel == NULL) {
183  crm_err("No channel specified to proxy");
184  remote_proxy_notify_destroy(lrmd, session_id);
185  return NULL;
186  }
187 
188  proxy = pcmk__assert_alloc(1, sizeof(remote_proxy_t));
189 
190  proxy->node_name = strdup(node_name);
191  proxy->session_id = strdup(session_id);
192  proxy->lrm = lrmd;
193 
195  && !strcmp(pcmk__message_name(channel), CRM_SYSTEM_CRMD)) {
196  // The controller doesn't need to connect to itself
197  proxy->is_local = TRUE;
198 
199  } else {
200  proxy->source = mainloop_add_ipc_client(channel, G_PRIORITY_LOW, 0, proxy, proxy_callbacks);
201  proxy->ipc = mainloop_get_ipc_client(proxy->source);
202  if (proxy->source == NULL) {
203  remote_proxy_free(proxy);
204  remote_proxy_notify_destroy(lrmd, session_id);
205  return NULL;
206  }
207  }
208 
209  crm_trace("new remote proxy client established to %s on %s, session id %s",
210  channel, node_name, session_id);
211  g_hash_table_insert(proxy_table, proxy->session_id, proxy);
212 
213  return proxy;
214 }
215 
216 void
217 remote_proxy_cb(lrmd_t *lrmd, const char *node_name, xmlNode *msg)
218 {
219  const char *op = crm_element_value(msg, PCMK__XA_LRMD_IPC_OP);
220  const char *session = crm_element_value(msg, PCMK__XA_LRMD_IPC_SESSION);
221  remote_proxy_t *proxy = g_hash_table_lookup(proxy_table, session);
222  int msg_id = 0;
223 
224  /* sessions are raw ipc connections to IPC,
225  * all we do is proxy requests/responses exactly
226  * like they are given to us at the ipc level. */
227 
228  CRM_CHECK(op != NULL, return);
229  CRM_CHECK(session != NULL, return);
230 
232  /* This is msg from remote ipc client going to real ipc server */
233 
234  if (pcmk__str_eq(op, LRMD_IPC_OP_DESTROY, pcmk__str_casei)) {
235  remote_proxy_end_session(proxy);
236 
237  } else if (pcmk__str_eq(op, LRMD_IPC_OP_REQUEST, pcmk__str_casei)) {
238  int flags = 0;
239  const char *name = crm_element_value(msg, PCMK__XA_LRMD_IPC_CLIENT);
240 
241  xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_LRMD_IPC_MSG,
242  NULL, NULL);
243  xmlNode *request = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
244 
245  CRM_CHECK(request != NULL, return);
246 
247  if (proxy == NULL) {
248  /* proxy connection no longer exists */
249  remote_proxy_notify_destroy(lrmd, session);
250  return;
251  }
252 
253  // Controller requests MUST be handled by the controller, not us
254  CRM_CHECK(proxy->is_local == FALSE,
255  remote_proxy_end_session(proxy); return);
256 
257  if (!crm_ipc_connected(proxy->ipc)) {
258  remote_proxy_end_session(proxy);
259  return;
260  }
261  proxy->last_request_id = 0;
263  crm_xml_add(request, PCMK_XE_ACL_ROLE, "pacemaker-remote");
264 
265  CRM_ASSERT(node_name);
266  pcmk__update_acl_user(request, PCMK__XA_LRMD_IPC_USER, node_name);
267 
269  const char *type = crm_element_value(request, PCMK__XA_T);
270  int rc = 0;
271 
272  if (pcmk__str_eq(type, PCMK__VALUE_ATTRD, pcmk__str_none)
273  && (crm_element_value(request, PCMK__XA_ATTR_HOST) == NULL)
278  pcmk__xe_add_node(request, proxy->node_name, 0);
279  }
280 
281  rc = crm_ipc_send(proxy->ipc, request, flags, 5000, NULL);
282 
283  if(rc < 0) {
284  xmlNode *op_reply = pcmk__xe_create(NULL, PCMK__XE_NACK);
285 
286  crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
287  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
288 
289  /* Send a n'ack so the caller doesn't block */
290  crm_xml_add(op_reply, PCMK_XA_FUNCTION, __func__);
291  crm_xml_add_int(op_reply, PCMK__XA_LINE, __LINE__);
292  crm_xml_add_int(op_reply, PCMK_XA_RC, rc);
293  remote_proxy_relay_response(proxy, op_reply, msg_id);
294  free_xml(op_reply);
295 
296  } else {
297  crm_trace("Relayed %s request %d from %s to %s for %s",
298  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
299  proxy->last_request_id = msg_id;
300  }
301 
302  } else {
303  int rc = pcmk_ok;
304  xmlNode *op_reply = NULL;
305  // @COMPAT pacemaker_remoted <= 1.1.10
306 
307  crm_trace("Relaying %s request %d from %s to %s for %s",
308  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
309 
310  rc = crm_ipc_send(proxy->ipc, request, flags, 10000, &op_reply);
311  if(rc < 0) {
312  crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
313  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
314  } else {
315  crm_trace("Relayed %s request %d from %s to %s for %s",
316  op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
317  }
318 
319  if(op_reply) {
320  remote_proxy_relay_response(proxy, op_reply, msg_id);
321  free_xml(op_reply);
322  }
323  }
324  } else {
325  crm_err("Unknown proxy operation: %s", op);
326  }
327 }
Services API.
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:245
#define PCMK__ATTRD_CMD_UPDATE_DELAY
Definition: crm_internal.h:77
void remote_proxy_disconnected(gpointer userdata)
Definition: proxy_common.c:159
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition: xml.c:883
A dumping ground.
const char * pcmk_strerror(int rc)
Definition: results.c:149
#define PCMK__XA_LRMD_IPC_SESSION
#define PCMK__ATTRD_CMD_UPDATE_BOTH
Definition: crm_internal.h:76
#define LRMD_IPC_OP_SHUTDOWN_NACK
Definition: lrmd.h:89
char data[0]
Definition: cpg.c:58
#define PCMK__VALUE_ATTRD
const char * name
Definition: cib.c:26
void remote_proxy_ack_shutdown(lrmd_t *lrmd)
Definition: proxy_common.c:46
void remote_proxy_relay_response(remote_proxy_t *proxy, xmlNode *msg, int msg_id)
Definition: proxy_common.c:88
#define LRMD_IPC_OP_DESTROY
Definition: lrmd.h:83
#define LRMD_IPC_OP_RESPONSE
Definition: lrmd.h:86
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:348
uint32_t last_request_id
Definition: lrmd_internal.h:62
const char * pcmk__update_acl_user(xmlNode *request, const char *field, const char *peer_user)
Definition: acl.c:799
#define PCMK__XA_LRMD_IPC_OP
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:301
Resource agent executor.
char * crm_system_name
Definition: utils.c:50
#define PCMK_XE_ACL_ROLE
Definition: xml_names.h:57
enum crm_ais_msg_types type
Definition: cpg.c:51
void remote_proxy_nack_shutdown(lrmd_t *lrmd)
Definition: proxy_common.c:61
uint32_t crm_ipc_buffer_flags(crm_ipc_t *client)
Definition: ipc_client.c:1221
#define PCMK__XA_LINE
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:482
Wrappers for and extensions to glib mainloop.
void remote_proxy_free(gpointer data)
Definition: proxy_common.c:119
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:177
#define crm_warn(fmt, args...)
Definition: logging.h:394
void remote_proxy_relay_event(remote_proxy_t *proxy, xmlNode *msg)
Definition: proxy_common.c:70
#define PCMK__XA_LRMD_IPC_MSG_ID
#define LRMD_IPC_OP_REQUEST
Definition: lrmd.h:85
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:446
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml.c:440
int remote_proxy_dispatch(const char *buffer, ssize_t length, gpointer userdata)
Definition: proxy_common.c:130
#define crm_trace(fmt, args...)
Definition: logging.h:404
#define crm_log_xml_explicit(xml, text)
Definition: logging.h:414
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:98
#define PCMK_XA_TASK
Definition: xml_names.h:419
#define PCMK__XA_LRMD_IPC_USER
Wrappers for and extensions to libxml2.
#define PCMK__XE_LRMD_IPC_MSG
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:943
#define PCMK__ATTRD_CMD_UPDATE
Definition: crm_internal.h:75
void free_xml(xmlNode *child)
Definition: xml.c:867
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1050
xmlNode * pcmk__xml_parse(const char *input)
Definition: xml_io.c:244
const char * pcmk__message_name(const char *name)
Get name to be used as identifier for cluster messages.
Definition: messages.c:171
#define CRM_SYSTEM_CRMD
Definition: crm.h:90
crm_ipc_t * ipc
Definition: lrmd_internal.h:60
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc_client.c:1068
int lrmd_internal_proxy_send(lrmd_t *lrmd, xmlNode *msg)
Definition: lrmd_client.c:1983
#define LRMD_IPC_OP_SHUTDOWN_ACK
Definition: lrmd.h:88
#define PCMK_XA_FUNCTION
Definition: xml_names.h:287
#define PCMK__XA_ATTR_HOST
const char * crm_ipc_name(crm_ipc_t *client)
Definition: ipc_client.c:1235
Cluster status and scheduling.
#define PCMK_XA_RC
Definition: xml_names.h:364
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:949
#define crm_err(fmt, args...)
Definition: logging.h:391
#define CRM_ASSERT(expr)
Definition: results.h:42
Cluster Configuration.
#define PCMK__XE_LRMD_IPC_PROXY
mainloop_io_t * source
Definition: lrmd_internal.h:61
#define PCMK__XE_NACK
Definition: lrmd.h:490
#define pcmk_ok
Definition: results.h:69
#define PCMK__XA_LRMD_IPC_MSG_FLAGS
GHashTable * proxy_table
Definition: proxy_common.c:26
#define LRMD_IPC_OP_EVENT
Definition: lrmd.h:84
#define PCMK__XA_T
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:918
void pcmk__xe_add_node(xmlNode *xml, const char *node, int nodeid)
Definition: nodes.c:127
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml.c:720
#define PCMK__XA_LRMD_IPC_CLIENT
#define pcmk__assert_alloc(nmemb, size)
Definition: internal.h:297
int crm_ipc_send(crm_ipc_t *client, const xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
Definition: ipc_client.c:1308
gboolean is_local
Definition: lrmd_internal.h:58
uint64_t flags
Definition: remote.c:215
void remote_proxy_cb(lrmd_t *lrmd, const char *node_name, xmlNode *msg)
Definition: proxy_common.c:217