pacemaker 2.1.5-a3f44794f94
Scalable High-Availability cluster resource manager
ipc_controld.c
Go to the documentation of this file.
1/*
2 * Copyright 2020-2022 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 <stdbool.h>
14#include <errno.h>
15#include <libxml/tree.h>
16
17#include <crm/crm.h>
18#include <crm/msg_xml.h>
19#include <crm/common/xml.h>
20#include <crm/common/ipc.h>
23#include "crmcommon_private.h"
24
25struct controld_api_private_s {
26 char *client_uuid;
27 unsigned int replies_expected;
28};
29
30// \return Standard Pacemaker return code
31static int
32new_data(pcmk_ipc_api_t *api)
33{
34 struct controld_api_private_s *private = NULL;
35
36 api->api_data = calloc(1, sizeof(struct controld_api_private_s));
37
38 if (api->api_data == NULL) {
39 return errno;
40 }
41
42 private = api->api_data;
43
44 /* This is set to the PID because that's how it was always done, but PIDs
45 * are not unique because clients can be remote. The value appears to be
46 * unused other than as part of F_CRM_SYS_FROM in IPC requests, which is
47 * only compared against the internal system names (CRM_SYSTEM_TENGINE,
48 * etc.), so it shouldn't be a problem.
49 */
50 private->client_uuid = pcmk__getpid_s();
51
52 /* @TODO Implement a call ID model similar to the CIB, executor, and fencer
53 * IPC APIs, so that requests and replies can be matched, and
54 * duplicate replies can be discarded.
55 */
56 return pcmk_rc_ok;
57}
58
59static void
60free_data(void *data)
61{
62 free(((struct controld_api_private_s *) data)->client_uuid);
63 free(data);
64}
65
66// \return Standard Pacemaker return code
67static int
68post_connect(pcmk_ipc_api_t *api)
69{
70 /* The controller currently requires clients to register via a hello
71 * request, but does not reply back.
72 */
73 struct controld_api_private_s *private = api->api_data;
74 const char *client_name = crm_system_name? crm_system_name : "client";
75 xmlNode *hello;
76 int rc;
77
78 hello = create_hello_message(private->client_uuid, client_name,
81 rc = pcmk__send_ipc_request(api, hello);
82 free_xml(hello);
83 if (rc != pcmk_rc_ok) {
84 crm_info("Could not send IPC hello to %s: %s " CRM_XS " rc=%s",
85 pcmk_ipc_name(api, true), pcmk_rc_str(rc), rc);
86 } else {
87 crm_debug("Sent IPC hello to %s", pcmk_ipc_name(api, true));
88 }
89 return rc;
90}
91
92static void
93set_node_info_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
94{
95 data->reply_type = pcmk_controld_reply_info;
96 if (msg_data == NULL) {
97 return;
98 }
99 data->data.node_info.have_quorum = pcmk__xe_attr_is_true(msg_data, XML_ATTR_HAVE_QUORUM);
100 data->data.node_info.is_remote = pcmk__xe_attr_is_true(msg_data, XML_NODE_IS_REMOTE);
101 crm_element_value_int(msg_data, XML_ATTR_ID, &(data->data.node_info.id));
102 data->data.node_info.uuid = crm_element_value(msg_data, XML_ATTR_UUID);
103 data->data.node_info.uname = crm_element_value(msg_data, XML_ATTR_UNAME);
104 data->data.node_info.state = crm_element_value(msg_data, XML_NODE_IS_PEER);
105}
106
107static void
108set_ping_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
109{
110 data->reply_type = pcmk_controld_reply_ping;
111 if (msg_data == NULL) {
112 return;
113 }
114 data->data.ping.sys_from = crm_element_value(msg_data,
116 data->data.ping.fsa_state = crm_element_value(msg_data,
118 data->data.ping.result = crm_element_value(msg_data, XML_PING_ATTR_STATUS);
119}
120
121static void
122set_nodes_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
123{
124 pcmk_controld_api_node_t *node_info;
125
126 data->reply_type = pcmk_controld_reply_nodes;
127 for (xmlNode *node = first_named_child(msg_data, XML_CIB_TAG_NODE);
128 node != NULL; node = crm_next_same_xml(node)) {
129
130 long long id_ll = 0;
131
132 node_info = calloc(1, sizeof(pcmk_controld_api_node_t));
133 crm_element_value_ll(node, XML_ATTR_ID, &id_ll);
134 if (id_ll > 0) {
135 node_info->id = id_ll;
136 }
137 node_info->uname = crm_element_value(node, XML_ATTR_UNAME);
138 node_info->state = crm_element_value(node, XML_NODE_IN_CLUSTER);
139 data->data.nodes = g_list_prepend(data->data.nodes, node_info);
140 }
141}
142
143static bool
144reply_expected(pcmk_ipc_api_t *api, xmlNode *request)
145{
146 const char *command = crm_element_value(request, F_CRM_TASK);
147
148 if (command == NULL) {
149 return false;
150 }
151
152 // We only need to handle commands that functions in this file can send
153 return !strcmp(command, CRM_OP_REPROBE)
154 || !strcmp(command, CRM_OP_NODE_INFO)
155 || !strcmp(command, CRM_OP_PING)
156 || !strcmp(command, CRM_OP_LRM_FAIL)
157 || !strcmp(command, CRM_OP_LRM_DELETE);
158}
159
160static bool
161dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
162{
163 struct controld_api_private_s *private = api->api_data;
164 crm_exit_t status = CRM_EX_OK;
165 xmlNode *msg_data = NULL;
166 const char *value = NULL;
167 pcmk_controld_api_reply_t reply_data = {
168 pcmk_controld_reply_unknown, NULL, NULL,
169 };
170
171 /* If we got an ACK, return true so the caller knows to expect more responses
172 * from the IPC server. We do this before decrementing replies_expected because
173 * ACKs are not going to be included in that value.
174 *
175 * Note that we cannot do the same kind of status checking here that we do in
176 * ipc_pacemakerd.c. The ACK message we receive does not necessarily contain
177 * a status attribute. That is, we may receive this:
178 *
179 * <ack function="crmd_remote_proxy_cb" line="556"/>
180 *
181 * Instead of this:
182 *
183 * <ack function="dispatch_controller_ipc" line="391" status="112"/>
184 */
185 if (pcmk__str_eq(crm_element_name(reply), "ack", pcmk__str_none)) {
186 return true; // More replies needed
187 }
188
189 if (private->replies_expected > 0) {
190 private->replies_expected--;
191 }
192
193 // Do some basic validation of the reply
194
195 /* @TODO We should be able to verify that value is always a response, but
196 * currently the controller doesn't always properly set the type. Even
197 * if we fix the controller, we'll still need to handle replies from
198 * old versions (feature set could be used to differentiate).
199 */
200 value = crm_element_value(reply, F_CRM_MSG_TYPE);
201 if (pcmk__str_empty(value)
203 crm_info("Unrecognizable message from controller: "
204 "invalid message type '%s'", pcmk__s(value, ""));
205 status = CRM_EX_PROTOCOL;
206 goto done;
207 }
208
209 if (pcmk__str_empty(crm_element_value(reply, XML_ATTR_REFERENCE))) {
210 crm_info("Unrecognizable message from controller: no reference");
211 status = CRM_EX_PROTOCOL;
212 goto done;
213 }
214
215 value = crm_element_value(reply, F_CRM_TASK);
216 if (pcmk__str_empty(value)) {
217 crm_info("Unrecognizable message from controller: no command name");
218 status = CRM_EX_PROTOCOL;
219 goto done;
220 }
221
222 // Parse useful info from reply
223
225 reply_data.host_from = crm_element_value(reply, F_CRM_HOST_FROM);
226 msg_data = get_message_xml(reply, F_CRM_DATA);
227
228 if (!strcmp(value, CRM_OP_REPROBE)) {
230
231 } else if (!strcmp(value, CRM_OP_NODE_INFO)) {
232 set_node_info_data(&reply_data, msg_data);
233
234 } else if (!strcmp(value, CRM_OP_INVOKE_LRM)) {
236 reply_data.data.resource.node_state = msg_data;
237
238 } else if (!strcmp(value, CRM_OP_PING)) {
239 set_ping_data(&reply_data, msg_data);
240
241 } else if (!strcmp(value, PCMK__CONTROLD_CMD_NODES)) {
242 set_nodes_data(&reply_data, msg_data);
243
244 } else {
245 crm_info("Unrecognizable message from controller: unknown command '%s'",
246 value);
247 status = CRM_EX_PROTOCOL;
248 }
249
250done:
251 pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
252
253 // Free any reply data that was allocated
254 if (pcmk__str_eq(value, PCMK__CONTROLD_CMD_NODES, pcmk__str_casei)) {
255 g_list_free_full(reply_data.data.nodes, free);
256 }
257
258 return false; // No further replies needed
259}
260
263{
264 pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
265
266 if (cmds != NULL) {
267 cmds->new_data = new_data;
268 cmds->free_data = free_data;
269 cmds->post_connect = post_connect;
270 cmds->reply_expected = reply_expected;
271 cmds->dispatch = dispatch;
272 }
273 return cmds;
274}
275
287static xmlNode *
288create_controller_request(const pcmk_ipc_api_t *api, const char *op,
289 const char *node, xmlNode *msg_data)
290{
291 struct controld_api_private_s *private = NULL;
292 const char *sys_to = NULL;
293
294 if (api == NULL) {
295 return NULL;
296 }
297 private = api->api_data;
298 if ((node == NULL) && !strcmp(op, CRM_OP_PING)) {
299 sys_to = CRM_SYSTEM_DC;
300 } else {
301 sys_to = CRM_SYSTEM_CRMD;
302 }
303 return create_request(op, msg_data, node, sys_to,
304 (crm_system_name? crm_system_name : "client"),
305 private->client_uuid);
306}
307
308// \return Standard Pacemaker return code
309static int
310send_controller_request(pcmk_ipc_api_t *api, xmlNode *request,
311 bool reply_is_expected)
312{
313 int rc;
314
315 if (crm_element_value(request, XML_ATTR_REFERENCE) == NULL) {
316 return EINVAL;
317 }
318 rc = pcmk__send_ipc_request(api, request);
319 if ((rc == pcmk_rc_ok) && reply_is_expected) {
320 struct controld_api_private_s *private = api->api_data;
321
322 private->replies_expected++;
323 }
324 return rc;
325}
326
327static xmlNode *
328create_reprobe_message_data(const char *target_node, const char *router_node)
329{
330 xmlNode *msg_data;
331
332 msg_data = create_xml_node(NULL, "data_for_" CRM_OP_REPROBE);
333 crm_xml_add(msg_data, XML_LRM_ATTR_TARGET, target_node);
334 if ((router_node != NULL) && !pcmk__str_eq(router_node, target_node, pcmk__str_casei)) {
335 crm_xml_add(msg_data, XML_LRM_ATTR_ROUTER_NODE, router_node);
336 }
337 return msg_data;
338}
339
350int
351pcmk_controld_api_reprobe(pcmk_ipc_api_t *api, const char *target_node,
352 const char *router_node)
353{
354 xmlNode *request;
355 xmlNode *msg_data;
356 int rc = pcmk_rc_ok;
357
358 if (api == NULL) {
359 return EINVAL;
360 }
361 if (router_node == NULL) {
362 router_node = target_node;
363 }
364 crm_debug("Sending %s IPC request to reprobe %s via %s",
365 pcmk_ipc_name(api, true), pcmk__s(target_node, "local node"),
366 pcmk__s(router_node, "local node"));
367 msg_data = create_reprobe_message_data(target_node, router_node);
368 request = create_controller_request(api, CRM_OP_REPROBE, router_node,
369 msg_data);
370 rc = send_controller_request(api, request, true);
371 free_xml(msg_data);
372 free_xml(request);
373 return rc;
374}
375
385int
387{
388 xmlNode *request;
389 int rc = pcmk_rc_ok;
390
391 request = create_controller_request(api, CRM_OP_NODE_INFO, NULL, NULL);
392 if (request == NULL) {
393 return EINVAL;
394 }
395 if (nodeid > 0) {
396 crm_xml_set_id(request, "%lu", (unsigned long) nodeid);
397 }
398
399 rc = send_controller_request(api, request, true);
400 free_xml(request);
401 return rc;
402}
403
413int
414pcmk_controld_api_ping(pcmk_ipc_api_t *api, const char *node_name)
415{
416 xmlNode *request;
417 int rc = pcmk_rc_ok;
418
419 request = create_controller_request(api, CRM_OP_PING, node_name, NULL);
420 if (request == NULL) {
421 return EINVAL;
422 }
423 rc = send_controller_request(api, request, true);
424 free_xml(request);
425 return rc;
426}
427
436int
438{
439 xmlNode *request;
440 int rc = EINVAL;
441
442 request = create_controller_request(api, PCMK__CONTROLD_CMD_NODES, NULL,
443 NULL);
444 if (request != NULL) {
445 rc = send_controller_request(api, request, true);
446 free_xml(request);
447 }
448 return rc;
449}
450
451// \return Standard Pacemaker return code
452static int
453controller_resource_op(pcmk_ipc_api_t *api, const char *op,
454 const char *target_node, const char *router_node,
455 bool cib_only, const char *rsc_id,
456 const char *rsc_long_id, const char *standard,
457 const char *provider, const char *type)
458{
459 int rc = pcmk_rc_ok;
460 char *key;
461 xmlNode *request, *msg_data, *xml_rsc, *params;
462
463 if (api == NULL) {
464 return EINVAL;
465 }
466 if (router_node == NULL) {
467 router_node = target_node;
468 }
469
470 msg_data = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP);
471
472 /* The controller logs the transition key from resource op requests, so we
473 * need to have *something* for it.
474 * @TODO don't use "crm-resource"
475 */
476 key = pcmk__transition_key(0, getpid(), 0,
477 "xxxxxxxx-xrsc-opxx-xcrm-resourcexxxx");
478 crm_xml_add(msg_data, XML_ATTR_TRANSITION_KEY, key);
479 free(key);
480
481 crm_xml_add(msg_data, XML_LRM_ATTR_TARGET, target_node);
482 if (!pcmk__str_eq(router_node, target_node, pcmk__str_casei)) {
483 crm_xml_add(msg_data, XML_LRM_ATTR_ROUTER_NODE, router_node);
484 }
485
486 if (cib_only) {
487 // Indicate that only the CIB needs to be cleaned
489 }
490
491 xml_rsc = create_xml_node(msg_data, XML_CIB_TAG_RESOURCE);
492 crm_xml_add(xml_rsc, XML_ATTR_ID, rsc_id);
493 crm_xml_add(xml_rsc, XML_ATTR_ID_LONG, rsc_long_id);
494 crm_xml_add(xml_rsc, XML_AGENT_ATTR_CLASS, standard);
495 crm_xml_add(xml_rsc, XML_AGENT_ATTR_PROVIDER, provider);
496 crm_xml_add(xml_rsc, XML_ATTR_TYPE, type);
497
498 params = create_xml_node(msg_data, XML_TAG_ATTRS);
500
501 // The controller parses the timeout from the request
503 crm_xml_add(params, key, "60000"); /* 1 minute */ //@TODO pass as arg
504 free(key);
505
506 request = create_controller_request(api, op, router_node, msg_data);
507 rc = send_controller_request(api, request, true);
508 free_xml(msg_data);
509 free_xml(request);
510 return rc;
511}
512
528int
530 const char *target_node, const char *router_node,
531 const char *rsc_id, const char *rsc_long_id,
532 const char *standard, const char *provider,
533 const char *type)
534{
535 crm_debug("Sending %s IPC request to fail %s (a.k.a. %s) on %s via %s",
536 pcmk_ipc_name(api, true), pcmk__s(rsc_id, "unknown resource"),
537 pcmk__s(rsc_long_id, "no other names"),
538 pcmk__s(target_node, "unspecified node"),
539 pcmk__s(router_node, "unspecified node"));
540 return controller_resource_op(api, CRM_OP_LRM_FAIL, target_node,
541 router_node, false, rsc_id, rsc_long_id,
542 standard, provider, type);
543}
544
561int
562pcmk_controld_api_refresh(pcmk_ipc_api_t *api, const char *target_node,
563 const char *router_node,
564 const char *rsc_id, const char *rsc_long_id,
565 const char *standard, const char *provider,
566 const char *type, bool cib_only)
567{
568 crm_debug("Sending %s IPC request to refresh %s (a.k.a. %s) on %s via %s",
569 pcmk_ipc_name(api, true), pcmk__s(rsc_id, "unknown resource"),
570 pcmk__s(rsc_long_id, "no other names"),
571 pcmk__s(target_node, "unspecified node"),
572 pcmk__s(router_node, "unspecified node"));
573 return controller_resource_op(api, CRM_OP_LRM_DELETE, target_node,
574 router_node, cib_only, rsc_id, rsc_long_id,
575 standard, provider, type);
576}
577
585unsigned int
587{
588 struct controld_api_private_s *private = api->api_data;
589
590 return private->replies_expected;
591}
592
598// \todo make this static to this file when breaking API backward compatibility
599xmlNode *
600create_hello_message(const char *uuid, const char *client_name,
601 const char *major_version, const char *minor_version)
602{
603 xmlNode *hello_node = NULL;
604 xmlNode *hello = NULL;
605
606 if (pcmk__str_empty(uuid) || pcmk__str_empty(client_name)
607 || pcmk__str_empty(major_version) || pcmk__str_empty(minor_version)) {
608 crm_err("Could not create IPC hello message from %s (UUID %s): "
609 "missing information",
610 client_name? client_name : "unknown client",
611 uuid? uuid : "unknown");
612 return NULL;
613 }
614
615 hello_node = create_xml_node(NULL, XML_TAG_OPTIONS);
616 if (hello_node == NULL) {
617 crm_err("Could not create IPC hello message from %s (UUID %s): "
618 "Message data creation failed", client_name, uuid);
619 return NULL;
620 }
621
622 crm_xml_add(hello_node, "major_version", major_version);
623 crm_xml_add(hello_node, "minor_version", minor_version);
624 crm_xml_add(hello_node, "client_name", client_name);
625 crm_xml_add(hello_node, "client_uuid", uuid);
626
627 hello = create_request(CRM_OP_HELLO, hello_node, NULL, NULL, client_name, uuid);
628 if (hello == NULL) {
629 crm_err("Could not create IPC hello message from %s (UUID %s): "
630 "Request creation failed", client_name, uuid);
631 return NULL;
632 }
633 free_xml(hello_node);
634
635 crm_trace("Created hello message from %s (UUID %s)", client_name, uuid);
636 return hello;
637}
bool pcmk__xe_attr_is_true(const xmlNode *node, const char *name)
Definition: nvpair.c:975
char * pcmk__transition_key(int transition_id, int action_id, int target_rc, const char *node)
Definition: operations.c:296
char * crm_meta_name(const char *field)
Definition: utils.c:468
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
#define CRM_SYSTEM_DC
Definition: crm.h:102
#define CRM_OP_HELLO
Definition: crm.h:138
#define CRM_OP_REPROBE
Definition: crm.h:152
#define CRM_FEATURE_SET
Definition: crm.h:69
#define CRM_OP_PING
Definition: crm.h:133
#define CRM_OP_LRM_FAIL
Definition: crm.h:150
#define CRM_OP_LRM_DELETE
Definition: crm.h:149
#define CRM_OP_NODE_INFO
Definition: crm.h:134
char * crm_system_name
Definition: utils.c:51
#define CRM_OP_INVOKE_LRM
Definition: crm.h:147
#define PCMK__CONTROLD_CMD_NODES
Definition: crm_internal.h:110
#define PCMK__XA_MODE
Definition: crm_internal.h:83
#define PCMK__CONTROLD_API_MINOR
G_GNUC_INTERNAL int pcmk__send_ipc_request(pcmk_ipc_api_t *api, xmlNode *request)
Definition: ipc_client.c:619
#define PCMK__CONTROLD_API_MAJOR
G_GNUC_INTERNAL void pcmk__call_ipc_callback(pcmk_ipc_api_t *api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data)
Definition: ipc_client.c:146
IPC interface to Pacemaker daemons.
#define create_request(task, xml_data, host_to, sys_to, sys_from, uuid_from)
Definition: ipc.h:43
@ pcmk_ipc_event_reply
Daemon's reply to client IPC request.
Definition: ipc.h:83
const char * pcmk_ipc_name(const pcmk_ipc_api_t *api, bool for_log)
Get the IPC name used with an IPC API connection.
Definition: ipc_client.c:243
int pcmk_controld_api_fail(pcmk_ipc_api_t *api, const char *target_node, const char *router_node, const char *rsc_id, const char *rsc_long_id, const char *standard, const char *provider, const char *type)
Ask the controller to fail a resource.
Definition: ipc_controld.c:529
int pcmk_controld_api_list_nodes(pcmk_ipc_api_t *api)
Ask the controller for cluster information.
Definition: ipc_controld.c:437
int pcmk_controld_api_ping(pcmk_ipc_api_t *api, const char *node_name)
Ask the controller for status.
Definition: ipc_controld.c:414
unsigned int pcmk_controld_api_replies_expected(const pcmk_ipc_api_t *api)
Get the number of IPC replies currently expected from the controller.
Definition: ipc_controld.c:586
xmlNode * create_hello_message(const char *uuid, const char *client_name, const char *major_version, const char *minor_version)
Create XML for a controller IPC "hello" message.
Definition: ipc_controld.c:600
int pcmk_controld_api_node_info(pcmk_ipc_api_t *api, uint32_t nodeid)
Send a "node info" controller operation.
Definition: ipc_controld.c:386
int pcmk_controld_api_refresh(pcmk_ipc_api_t *api, const char *target_node, const char *router_node, const char *rsc_id, const char *rsc_long_id, const char *standard, const char *provider, const char *type, bool cib_only)
Ask the controller to refresh a resource.
Definition: ipc_controld.c:562
int pcmk_controld_api_reprobe(pcmk_ipc_api_t *api, const char *target_node, const char *router_node)
Send a reprobe controller operation.
Definition: ipc_controld.c:351
pcmk__ipc_methods_t * pcmk__controld_api_methods(void)
Definition: ipc_controld.c:262
IPC commands for Pacemaker controller.
@ pcmk_controld_reply_nodes
Definition: ipc_controld.h:37
@ pcmk_controld_reply_reprobe
Definition: ipc_controld.h:33
@ pcmk_controld_reply_resource
Definition: ipc_controld.h:35
@ pcmk_controld_reply_ping
Definition: ipc_controld.h:36
@ pcmk_controld_reply_info
Definition: ipc_controld.h:34
@ pcmk_controld_reply_unknown
Definition: ipc_controld.h:32
#define crm_info(fmt, args...)
Definition: logging.h:362
#define CRM_XS
Definition: logging.h:55
#define crm_debug(fmt, args...)
Definition: logging.h:364
#define crm_err(fmt, args...)
Definition: logging.h:359
#define crm_trace(fmt, args...)
Definition: logging.h:365
#define XML_TAG_CIB
Definition: msg_xml.h:115
#define XML_LRM_ATTR_ROUTER_NODE
Definition: msg_xml.h:308
#define XML_ATTR_TRANSITION_KEY
Definition: msg_xml.h:413
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:118
#define XML_ATTR_UNAME
Definition: msg_xml.h:157
#define XML_PING_ATTR_SYSFROM
Definition: msg_xml.h:163
#define XML_ATTR_UUID
Definition: msg_xml.h:158
#define XML_NODE_IS_PEER
Definition: msg_xml.h:281
#define XML_ATTR_REQUEST
Definition: msg_xml.h:154
#define F_CRM_HOST_FROM
Definition: msg_xml.h:96
#define XML_NODE_IS_REMOTE
Definition: msg_xml.h:282
#define XML_ATTR_ID
Definition: msg_xml.h:134
#define XML_PING_ATTR_CRMDSTATE
Definition: msg_xml.h:164
#define XML_NODE_IN_CLUSTER
Definition: msg_xml.h:280
#define XML_ATTR_HAVE_QUORUM
Definition: msg_xml.h:123
#define F_CRM_MSG_TYPE
Definition: msg_xml.h:93
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:270
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:269
#define XML_TAG_ATTRS
Definition: msg_xml.h:211
#define XML_ATTR_ID_LONG
Definition: msg_xml.h:137
#define XML_PING_ATTR_STATUS
Definition: msg_xml.h:162
#define XML_ATTR_TYPE
Definition: msg_xml.h:138
#define XML_ATTR_RESPONSE
Definition: msg_xml.h:155
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:302
#define XML_ATTR_TIMEOUT
Definition: msg_xml.h:128
#define XML_ATTR_REFERENCE
Definition: msg_xml.h:159
#define F_CRM_DATA
Definition: msg_xml.h:90
#define XML_GRAPH_TAG_RSC_OP
Definition: msg_xml.h:329
#define F_CRM_TASK
Definition: msg_xml.h:91
#define XML_TAG_OPTIONS
Definition: msg_xml.h:151
#define XML_ATTR_VERSION
Definition: msg_xml.h:132
#define XML_CIB_TAG_NODE
Definition: msg_xml.h:205
#define XML_CIB_TAG_RESOURCE
Definition: msg_xml.h:217
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
int crm_element_value_ll(const xmlNode *data, const char *name, long long *dest)
Retrieve the long long integer value of an XML attribute.
Definition: nvpair.c:585
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
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:476
@ CRM_EX_PROTOCOL
Protocol violated.
Definition: results.h:260
@ CRM_EX_OK
Success.
Definition: results.h:234
@ pcmk_rc_ok
Definition: results.h:148
enum crm_exit_e crm_exit_t
@ pcmk__str_none
@ pcmk__str_casei
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:952
int(* new_data)(pcmk_ipc_api_t *api)
void(* free_data)(void *api_data)
bool(* dispatch)(pcmk_ipc_api_t *api, xmlNode *msg)
bool(* reply_expected)(pcmk_ipc_api_t *api, xmlNode *request)
int(* post_connect)(pcmk_ipc_api_t *api)
const char * feature_set
CRM feature set advertised by controller.
Definition: ipc_controld.h:60
struct pcmk_controld_api_reply_t::@1::@3 resource
const char * host_from
Name of node that sent reply.
Definition: ipc_controld.h:61
enum pcmk_controld_api_reply reply_type
Definition: ipc_controld.h:59
union pcmk_controld_api_reply_t::@1 data
Wrappers for and extensions to libxml2.
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2930
void crm_xml_set_id(xmlNode *xml, const char *format,...) G_GNUC_PRINTF(2
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2956
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