pacemaker  2.1.8-3980678f03
Scalable High-Availability cluster resource manager
messages.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-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 <stdio.h>
13 #include <sys/types.h>
14 
15 #include <glib.h>
16 #include <libxml/tree.h>
17 
18 #include <crm/common/xml.h>
20 
39 xmlNode *
40 create_request_adv(const char *task, xmlNode *msg_data,
41  const char *host_to, const char *sys_to,
42  const char *sys_from, const char *uuid_from,
43  const char *origin)
44 {
45  static uint ref_counter = 0;
46 
47  char *true_from = NULL;
48  xmlNode *request = NULL;
49  char *reference = crm_strdup_printf("%s-%s-%lld-%u",
50  (task? task : "_empty_"),
51  (sys_from? sys_from : "_empty_"),
52  (long long) time(NULL), ref_counter++);
53 
54  if (uuid_from != NULL) {
55  true_from = crm_strdup_printf("%s_%s", uuid_from,
56  (sys_from? sys_from : "none"));
57  } else if (sys_from != NULL) {
58  true_from = strdup(sys_from);
59  } else {
60  crm_err("Cannot create IPC request: No originating system specified");
61  }
62 
63  // host_from will get set for us if necessary by the controller when routed
64  request = pcmk__xe_create(NULL, __func__);
65  crm_xml_add(request, PCMK_XA_ORIGIN, origin);
69  crm_xml_add(request, PCMK_XA_REFERENCE, reference);
70  crm_xml_add(request, PCMK__XA_CRM_TASK, task);
71  crm_xml_add(request, PCMK__XA_CRM_SYS_TO, sys_to);
72  crm_xml_add(request, PCMK__XA_CRM_SYS_FROM, true_from);
73 
74  /* HOSTTO will be ignored if it is to the DC anyway. */
75  if (host_to != NULL && strlen(host_to) > 0) {
76  crm_xml_add(request, PCMK__XA_CRM_HOST_TO, host_to);
77  }
78 
79  if (msg_data != NULL) {
80  xmlNode *wrapper = pcmk__xe_create(request, PCMK__XE_CRM_XML);
81 
82  pcmk__xml_copy(wrapper, msg_data);
83  }
84  free(reference);
85  free(true_from);
86 
87  return request;
88 }
89 
103 xmlNode *
104 create_reply_adv(const xmlNode *original_request, xmlNode *xml_response_data,
105  const char *origin)
106 {
107  xmlNode *reply = NULL;
108 
109  const char *host_from = crm_element_value(original_request, PCMK__XA_SRC);
110  const char *sys_from = crm_element_value(original_request,
112  const char *sys_to = crm_element_value(original_request,
114  const char *type = crm_element_value(original_request, PCMK__XA_SUBT);
115  const char *operation = crm_element_value(original_request,
117  const char *crm_msg_reference = crm_element_value(original_request,
119 
120  if (type == NULL) {
121  crm_err("Cannot create new_message, no message type in original message");
122  CRM_ASSERT(type != NULL);
123  return NULL;
124  }
125 
126  if (strcmp(type, PCMK__VALUE_REQUEST) != 0) {
127  /* Replies should only be generated for request messages, but it's possible
128  * we expect replies to other messages right now so this can't be enforced.
129  */
130  crm_trace("Creating a reply for a non-request original message");
131  }
132 
133  reply = pcmk__xe_create(NULL, __func__);
134  crm_xml_add(reply, PCMK_XA_ORIGIN, origin);
138  crm_xml_add(reply, PCMK_XA_REFERENCE, crm_msg_reference);
139  crm_xml_add(reply, PCMK__XA_CRM_TASK, operation);
140 
141  /* since this is a reply, we reverse the from and to */
142  crm_xml_add(reply, PCMK__XA_CRM_SYS_TO, sys_from);
143  crm_xml_add(reply, PCMK__XA_CRM_SYS_FROM, sys_to);
144 
145  /* HOSTTO will be ignored if it is to the DC anyway. */
146  if (host_from != NULL && strlen(host_from) > 0) {
147  crm_xml_add(reply, PCMK__XA_CRM_HOST_TO, host_from);
148  }
149 
150  if (xml_response_data != NULL) {
151  xmlNode *wrapper = pcmk__xe_create(reply, PCMK__XE_CRM_XML);
152 
153  pcmk__xml_copy(wrapper, xml_response_data);
154  }
155 
156  return reply;
157 }
158 
170 const char *
172 {
173  if (name == NULL) {
174  return "unknown";
175 
176  } else if (!strcmp(name, "pacemaker-attrd")) {
177  return "attrd";
178 
179  } else if (!strcmp(name, "pacemaker-based")) {
180  return CRM_SYSTEM_CIB;
181 
182  } else if (!strcmp(name, "pacemaker-controld")) {
183  return CRM_SYSTEM_CRMD;
184 
185  } else if (!strcmp(name, "pacemaker-execd")) {
186  return CRM_SYSTEM_LRMD;
187 
188  } else if (!strcmp(name, "pacemaker-fenced")) {
189  return "stonith-ng";
190 
191  } else if (!strcmp(name, "pacemaker-schedulerd")) {
192  return CRM_SYSTEM_PENGINE;
193 
194  } else {
195  return name;
196  }
197 }
198 
212 GHashTable *
214 {
215  GHashTable *commands = g_hash_table_new(g_str_hash, g_str_equal);
216 
217  if (handlers != NULL) {
218  int i;
219 
220  for (i = 0; handlers[i].command != NULL; ++i) {
221  g_hash_table_insert(commands, (gpointer) handlers[i].command,
222  handlers[i].handler);
223  }
224  if (handlers[i].handler != NULL) {
225  // g_str_hash() can't handle NULL, so use empty string for default
226  g_hash_table_insert(commands, (gpointer) "", handlers[i].handler);
227  }
228  }
229  return commands;
230 }
231 
241 xmlNode *
242 pcmk__process_request(pcmk__request_t *request, GHashTable *handlers)
243 {
244  xmlNode *(*handler)(pcmk__request_t *request) = NULL;
245 
246  CRM_CHECK((request != NULL) && (request->op != NULL) && (handlers != NULL),
247  return NULL);
248 
249  if (pcmk_is_set(request->flags, pcmk__request_sync)
250  && (request->ipc_client != NULL)) {
251  CRM_CHECK(request->ipc_client->request_id == request->ipc_id,
252  return NULL);
253  }
254 
255  handler = g_hash_table_lookup(handlers, request->op);
256  if (handler == NULL) {
257  handler = g_hash_table_lookup(handlers, ""); // Default handler
258  if (handler == NULL) {
259  crm_info("Ignoring %s request from %s %s with no handler",
260  request->op, pcmk__request_origin_type(request),
261  pcmk__request_origin(request));
262  return NULL;
263  }
264  }
265 
266  return (*handler)(request);
267 }
268 
275 void
277 {
278  free(request->op);
279  request->op = NULL;
280 
281  pcmk__reset_result(&(request->result));
282 }
283 
284 // Deprecated functions kept only for backward API compatibility
285 // LCOV_EXCL_START
286 
287 #include <crm/common/xml_compat.h>
288 
289 gboolean
290 add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
291 {
292  xmlNode *holder = pcmk__xe_create(msg, field);
293 
294  pcmk__xml_copy(holder, xml);
295  return TRUE;
296 }
297 
298 xmlNode *
299 get_message_xml(const xmlNode *msg, const char *field)
300 {
301  xmlNode *child = pcmk__xe_first_child(msg, field, NULL, NULL);
302 
303  return pcmk__xe_first_child(child, NULL, NULL, NULL);
304 }
305 
306 // LCOV_EXCL_STOP
307 // End deprecated API
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:245
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition: xml.c:883
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
Definition: messages.c:290
#define PCMK__VALUE_RESPONSE
const char * pcmk__message_name(const char *name)
Get name to be used as identifier for cluster messages.
Definition: messages.c:171
const char * name
Definition: cib.c:26
xmlNode * create_reply_adv(const xmlNode *original_request, xmlNode *xml_response_data, const char *origin)
Create a Pacemaker reply (for IPC or cluster layer)
Definition: messages.c:104
GHashTable * pcmk__register_handlers(const pcmk__server_command_t handlers[])
Definition: messages.c:213
#define CRM_FEATURE_SET
Definition: crm.h:72
#define PCMK_XA_REFERENCE
Definition: xml_names.h:367
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
pcmk__client_t * ipc_client
#define PCMK__XA_SUBT
enum crm_ais_msg_types type
Definition: cpg.c:51
void pcmk__reset_request(pcmk__request_t *request)
Definition: messages.c:276
#define PCMK__XA_CRM_HOST_TO
Deprecated Pacemaker XML API.
#define PCMK__XA_CRM_SYS_TO
#define PCMK_XA_ORIGIN
Definition: xml_names.h:346
#define PCMK__XA_CRM_TASK
pcmk__action_result_t result
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
#define crm_trace(fmt, args...)
Definition: logging.h:404
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:98
#define CRM_SYSTEM_PENGINE
Definition: crm.h:92
Wrappers for and extensions to libxml2.
#define PCMK__XA_CRM_SYS_FROM
xmlNode * create_request_adv(const char *task, xmlNode *msg_data, const char *host_to, const char *sys_to, const char *sys_from, const char *uuid_from, const char *origin)
Create a Pacemaker request (for IPC or cluster layer)
Definition: messages.c:40
#define CRM_SYSTEM_CRMD
Definition: crm.h:90
#define CRM_SYSTEM_CIB
Definition: crm.h:89
#define PCMK__XE_CRM_XML
#define crm_err(fmt, args...)
Definition: logging.h:391
#define CRM_ASSERT(expr)
Definition: results.h:42
#define CRM_SYSTEM_LRMD
Definition: crm.h:91
#define PCMK__XA_T
xmlNode * pcmk__process_request(pcmk__request_t *request, GHashTable *handlers)
Definition: messages.c:242
#define PCMK__VALUE_CRMD
xmlNode * get_message_xml(const xmlNode *msg, const char *field)
Definition: messages.c:299
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml.c:720
void pcmk__reset_result(pcmk__action_result_t *result)
Definition: results.c:1065
#define PCMK__VALUE_REQUEST
#define crm_info(fmt, args...)
Definition: logging.h:399
#define PCMK__XA_SRC
#define PCMK_XA_VERSION
Definition: xml_names.h:439