pacemaker 2.1.5-a3f44794f94
Scalable High-Availability cluster resource manager
proxy_common.c
Go to the documentation of this file.
1/*
2 * Copyright 2015-2021 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
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 = 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
44void
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
59void
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
68void
70{
71 /* sending to the remote node an event msg. */
72 xmlNode *event = create_xml_node(NULL, T_LRMD_IPC_PROXY);
76 crm_log_xml_explicit(event, "EventForProxy");
77 lrmd_internal_proxy_send(proxy->lrm, event);
78 free_xml(event);
79}
80
81void
82remote_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
94static void
95remote_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
107void
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
118int
119remote_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
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);
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
147void
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
166remote_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
205void
206remote_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 CRM_ASSERT(node_name);
252 pcmk__update_acl_user(request, F_LRMD_IPC_USER, node_name);
253
255 const char *type = crm_element_value(request, F_TYPE);
256 int rc = 0;
257
258 if (pcmk__str_eq(type, T_ATTRD, pcmk__str_casei)
259 && crm_element_value(request,
265 pcmk__xe_add_node(request, proxy->node_name, 0);
266 }
267
268 rc = crm_ipc_send(proxy->ipc, request, flags, 5000, NULL);
269
270 if(rc < 0) {
271 xmlNode *op_reply = create_xml_node(NULL, "nack");
272
273 crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
274 op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
275
276 /* Send a n'ack so the caller doesn't block */
277 crm_xml_add(op_reply, "function", __func__);
278 crm_xml_add_int(op_reply, "line", __LINE__);
279 crm_xml_add_int(op_reply, "rc", rc);
280 remote_proxy_relay_response(proxy, op_reply, msg_id);
281 free_xml(op_reply);
282
283 } else {
284 crm_trace("Relayed %s request %d from %s to %s for %s",
285 op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
286 proxy->last_request_id = msg_id;
287 }
288
289 } else {
290 int rc = pcmk_ok;
291 xmlNode *op_reply = NULL;
292 // @COMPAT pacemaker_remoted <= 1.1.10
293
294 crm_trace("Relaying %s request %d from %s to %s for %s",
295 op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
296
297 rc = crm_ipc_send(proxy->ipc, request, flags, 10000, &op_reply);
298 if(rc < 0) {
299 crm_err("Could not relay %s request %d from %s to %s for %s: %s (%d)",
300 op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name, pcmk_strerror(rc), rc);
301 } else {
302 crm_trace("Relayed %s request %d from %s to %s for %s",
303 op, msg_id, proxy->node_name, crm_ipc_name(proxy->ipc), name);
304 }
305
306 if(op_reply) {
307 remote_proxy_relay_response(proxy, op_reply, msg_id);
308 free_xml(op_reply);
309 }
310 }
311 } else {
312 crm_err("Unknown proxy operation: %s", op);
313 }
314}
const char * pcmk__update_acl_user(xmlNode *request, const char *field, const char *peer_user)
Definition: acl.c:796
const char * name
Definition: cib.c:24
Cluster Configuration.
void pcmk__xe_add_node(xmlNode *xml, const char *node, int nodeid)
Definition: nodes.c:15
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:121
enum crm_ais_msg_types type
Definition: cpg.c:3
char data[0]
Definition: cpg.c:10
A dumping ground.
#define CRM_SYSTEM_CRMD
Definition: crm.h:105
char * crm_system_name
Definition: utils.c:51
#define PCMK__XA_ATTR_NODE_NAME
Definition: crm_internal.h:68
#define PCMK__ATTRD_CMD_UPDATE_BOTH
Definition: crm_internal.h:101
#define PCMK__ATTRD_CMD_UPDATE_DELAY
Definition: crm_internal.h:102
#define PCMK__XA_TASK
Definition: crm_internal.h:84
#define PCMK__ATTRD_CMD_UPDATE
Definition: crm_internal.h:100
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:1209
const char * crm_ipc_name(crm_ipc_t *client)
Definition: ipc_client.c:1136
@ crm_ipc_proxied_relay_response
Definition: ipc.h:156
@ crm_ipc_proxied
Definition: ipc.h:150
bool crm_ipc_connected(crm_ipc_t *client)
Definition: ipc_client.c:970
uint32_t crm_ipc_buffer_flags(crm_ipc_t *client)
Definition: ipc_client.c:1122
#define crm_warn(fmt, args...)
Definition: logging.h:360
#define crm_log_xml_explicit(xml, text)
Definition: logging.h:375
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
#define crm_err(fmt, args...)
Definition: logging.h:359
#define crm_trace(fmt, args...)
Definition: logging.h:365
Resource agent executor.
#define LRMD_IPC_OP_RESPONSE
Definition: lrmd.h:110
#define F_LRMD_IPC_MSG
Definition: lrmd.h:120
#define LRMD_IPC_OP_SHUTDOWN_ACK
Definition: lrmd.h:112
#define F_LRMD_IPC_MSG_FLAGS
Definition: lrmd.h:122
#define LRMD_IPC_OP_REQUEST
Definition: lrmd.h:109
#define LRMD_IPC_OP_SHUTDOWN_NACK
Definition: lrmd.h:113
#define LRMD_IPC_OP_EVENT
Definition: lrmd.h:108
#define LRMD_IPC_OP_DESTROY
Definition: lrmd.h:107
#define T_LRMD_IPC_PROXY
Definition: lrmd.h:127
#define F_LRMD_IPC_SESSION
Definition: lrmd.h:117
#define F_LRMD_IPC_USER
Definition: lrmd.h:119
#define F_LRMD_IPC_CLIENT
Definition: lrmd.h:118
#define F_LRMD_IPC_OP
Definition: lrmd.h:115
#define F_LRMD_IPC_MSG_ID
Definition: lrmd.h:121
Wrappers for and extensions to glib mainloop.
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:947
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:916
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition: mainloop.c:941
const char * pcmk__message_name(const char *name)
Get name to be used as identifier for cluster messages.
Definition: messages.c:180
#define XML_ACL_TAG_ROLE
Definition: msg_xml.h:425
#define T_ATTRD
Definition: msg_xml.h:85
#define F_TYPE
Definition: msg_xml.h:69
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:517
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:553
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:419
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:323
int lrmd_internal_proxy_send(lrmd_t *lrmd, xmlNode *msg)
Definition: lrmd_client.c:1894
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
void remote_proxy_cb(lrmd_t *lrmd, const char *node_name, xmlNode *msg)
Definition: proxy_common.c:206
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
void remote_proxy_free(gpointer data)
Definition: proxy_common.c:108
GHashTable * proxy_table
Definition: proxy_common.c:26
void remote_proxy_relay_response(remote_proxy_t *proxy, xmlNode *msg, int msg_id)
Definition: proxy_common.c:82
void remote_proxy_disconnected(gpointer userdata)
Definition: proxy_common.c:148
void remote_proxy_ack_shutdown(lrmd_t *lrmd)
Send an acknowledgment of a remote proxy shutdown request.
Definition: proxy_common.c:45
int remote_proxy_dispatch(const char *buffer, ssize_t length, gpointer userdata)
Definition: proxy_common.c:119
void remote_proxy_relay_event(remote_proxy_t *proxy, xmlNode *msg)
Definition: proxy_common.c:69
const char * pcmk_strerror(int rc)
Definition: results.c:148
#define CRM_ASSERT(expr)
Definition: results.h:42
#define pcmk_ok
Definition: results.h:68
Services API.
Cluster status and scheduling.
@ pcmk__str_casei
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:952
Definition: lrmd.h:597
mainloop_io_t * source
Definition: lrmd_internal.h:58
gboolean is_local
Definition: lrmd_internal.h:55
crm_ipc_t * ipc
Definition: lrmd_internal.h:57
uint32_t last_request_id
Definition: lrmd_internal.h:59
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition: messages.c:160
xmlNode * string2xml(const char *input)
Definition: xml.c:930
void free_xml(xmlNode *child)
Definition: xml.c:885
xmlNode * get_message_xml(const xmlNode *msg, const char *field)
Definition: messages.c:154
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:749