pacemaker 3.0.1-16e74fc4da
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
proxy_common.c
Go to the documentation of this file.
1/*
2 * Copyright 2015-2025 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
25int lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg);
26GHashTable *proxy_table = NULL;
27
28static void
29remote_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 pcmk__xml_free(msg);
37}
38
45void
53
60void
68
69void
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 pcmk__xml_free(event);
85}
86
87void
88remote_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
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 pcmk__xml_free(response);
103}
104
105static void
106remote_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
118void
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
129int
130remote_proxy_dispatch(const char *buffer, ssize_t length, gpointer userdata)
131{
132 // Async responses from servers to clients via the remote executor
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
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);
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 pcmk__xml_free(xml);
154 return 1;
155}
156
157
158void
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
177remote_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 && (pcmk__parse_server(channel) == pcmk_ipc_controld)) {
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
216void
217remote_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 uint32_t flags = 0U;
239 int rc = pcmk_rc_ok;
241
242 xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_LRMD_IPC_MSG,
243 NULL, NULL);
244 xmlNode *request = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
245
246 CRM_CHECK(request != NULL, return);
247
248 if (proxy == NULL) {
249 /* proxy connection no longer exists */
250 remote_proxy_notify_destroy(lrmd, session);
251 return;
252 }
253
254 // Controller requests MUST be handled by the controller, not us
255 CRM_CHECK(proxy->is_local == FALSE,
256 remote_proxy_end_session(proxy); return);
257
258 if (!crm_ipc_connected(proxy->ipc)) {
259 remote_proxy_end_session(proxy);
260 return;
261 }
262 proxy->last_request_id = 0;
263 crm_xml_add(request, PCMK_XE_ACL_ROLE, "pacemaker-remote");
264
266 if (rc != pcmk_rc_ok) {
267 crm_warn("Couldn't parse controller flags from remote request: %s",
268 pcmk_rc_str(rc));
269 }
270
271 pcmk__assert(node_name != NULL);
273
275 const char *type = crm_element_value(request, PCMK__XA_T);
276 int rc = 0;
277
278 if (pcmk__str_eq(type, PCMK__VALUE_ATTRD, pcmk__str_none)
279 && (crm_element_value(request, PCMK__XA_ATTR_HOST) == NULL)
284
285 crm_xml_add(request, PCMK__XA_ATTR_HOST, proxy->node_name);
286 }
287
288 rc = crm_ipc_send(proxy->ipc, request, flags, 5000, NULL);
289
290 if(rc < 0) {
291 xmlNode *op_reply = pcmk__xe_create(NULL, PCMK__XE_NACK);
292
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
296 /* Send a n'ack so the caller doesn't block */
297 crm_xml_add(op_reply, PCMK_XA_FUNCTION, __func__);
298 crm_xml_add_int(op_reply, PCMK__XA_LINE, __LINE__);
299 crm_xml_add_int(op_reply, PCMK_XA_RC, rc);
300 remote_proxy_relay_response(proxy, op_reply, msg_id);
301 pcmk__xml_free(op_reply);
302
303 } else {
304 crm_trace("Relayed %s request %d from %s to %s for %s",
305 op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
306 proxy->last_request_id = msg_id;
307 }
308
309 } else {
310 int rc = pcmk_ok;
311 xmlNode *op_reply = NULL;
312 // @COMPAT pacemaker_remoted <= 1.1.10
313
314 crm_trace("Relaying %s request %d from %s to %s for %s",
315 op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
316
317 rc = crm_ipc_send(proxy->ipc, request, flags, 10000, &op_reply);
318 if(rc < 0) {
319 crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
320 op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
321 } else {
322 crm_trace("Relayed %s request %d from %s to %s for %s",
323 op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
324 }
325
326 if(op_reply) {
327 remote_proxy_relay_response(proxy, op_reply, msg_id);
328 pcmk__xml_free(op_reply);
329 }
330 }
331 } else {
332 crm_err("Unknown proxy operation: %s", op);
333 }
334}
const char * pcmk__update_acl_user(xmlNode *request, const char *field, const char *peer_user)
Definition acl.c:853
const char * name
Definition cib.c:26
Cluster Configuration.
#define pcmk__assert_alloc(nmemb, size)
Definition internal.h:246
uint64_t flags
Definition remote.c:3
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:80
char data[0]
Definition cpg.c:10
enum pcmk_ipc_server type
Definition cpg.c:3
A dumping ground.
char * crm_system_name
Definition utils.c:45
#define PCMK__ATTRD_CMD_UPDATE_BOTH
#define PCMK__ATTRD_CMD_UPDATE_DELAY
#define PCMK__ATTRD_CMD_UPDATE
const char * crm_ipc_name(crm_ipc_t *client)
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.
@ crm_ipc_proxied_relay_response
Definition ipc.h:152
@ crm_ipc_proxied
ALL replies to proxied connections need to be sent as events
Definition ipc.h:140
bool crm_ipc_connected(crm_ipc_t *client)
@ pcmk_ipc_controld
Controller.
Definition ipc.h:52
uint32_t crm_ipc_buffer_flags(crm_ipc_t *client)
#define crm_warn(fmt, args...)
Definition logging.h:360
#define crm_log_xml_explicit(xml, text)
Definition logging.h:380
#define CRM_CHECK(expr, failure_action)
Definition logging.h:213
#define crm_err(fmt, args...)
Definition logging.h:357
#define crm_trace(fmt, args...)
Definition logging.h:370
Resource agent executor.
#define LRMD_IPC_OP_RESPONSE
Definition lrmd.h:75
#define LRMD_IPC_OP_SHUTDOWN_ACK
Definition lrmd.h:77
#define LRMD_IPC_OP_REQUEST
Definition lrmd.h:74
#define LRMD_IPC_OP_SHUTDOWN_NACK
Definition lrmd.h:78
#define LRMD_IPC_OP_EVENT
Definition lrmd.h:73
#define LRMD_IPC_OP_DESTROY
Definition lrmd.h:72
Wrappers for and extensions to glib mainloop.
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition mainloop.c:953
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:922
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition mainloop.c:947
#define PCMK__VALUE_ATTRD
int lrmd_internal_proxy_send(lrmd_t *lrmd, xmlNode *msg)
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)
void remote_proxy_cb(lrmd_t *lrmd, const char *node_name, xmlNode *msg)
void remote_proxy_nack_shutdown(lrmd_t *lrmd)
void remote_proxy_free(gpointer data)
GHashTable * proxy_table
void remote_proxy_relay_response(remote_proxy_t *proxy, xmlNode *msg, int msg_id)
void remote_proxy_disconnected(gpointer userdata)
void remote_proxy_ack_shutdown(lrmd_t *lrmd)
int remote_proxy_dispatch(const char *buffer, ssize_t length, gpointer userdata)
void remote_proxy_relay_event(remote_proxy_t *proxy, xmlNode *msg)
const char * pcmk_strerror(int rc)
Definition results.c:257
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition results.c:617
@ pcmk_rc_ok
Definition results.h:159
#define pcmk_ok
Definition results.h:65
#define pcmk__assert(expr)
enum pcmk_ipc_server pcmk__parse_server(const char *text)
Definition servers.c:178
Services API.
Cluster status and scheduling.
@ pcmk__str_none
@ pcmk__str_casei
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1053
Definition lrmd.h:473
mainloop_io_t * source
gboolean is_local
crm_ipc_t * ipc
uint32_t last_request_id
Wrappers for and extensions to libxml2.
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml_element.c:43
int pcmk__xe_get_flags(const xmlNode *xml, const char *name, uint32_t *dest, uint32_t default_value)
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition xml.c:832
void pcmk__xml_free(xmlNode *xml)
Definition xml.c:816
xmlNode * pcmk__xml_parse(const char *input)
Definition xml_io.c:167
#define PCMK_XA_RC
Definition xml_names.h:369
#define PCMK_XE_ACL_ROLE
Definition xml_names.h:57
#define PCMK_XA_FUNCTION
Definition xml_names.h:292
#define PCMK_XA_TASK
Definition xml_names.h:424
#define PCMK__XA_LINE
#define PCMK__XA_LRMD_IPC_SESSION
#define PCMK__XA_LRMD_IPC_USER
#define PCMK__XE_LRMD_IPC_MSG
#define PCMK__XA_T
#define PCMK__XA_LRMD_IPC_CLIENT
#define PCMK__XA_LRMD_IPC_OP
#define PCMK__XA_LRMD_IPC_MSG_FLAGS
#define PCMK__XE_LRMD_IPC_PROXY
#define PCMK__XA_ATTR_HOST
#define PCMK__XE_NACK
#define PCMK__XA_LRMD_IPC_MSG_ID