pacemaker 2.1.8-2.1.8
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
ipc_controld.c
Go to the documentation of this file.
1/*
2 * Copyright 2020-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 <errno.h>
13#include <inttypes.h> // PRIu32
14#include <stdbool.h>
15#include <stdint.h> // uint32_t
16#include <stdio.h>
17
18#include <libxml/tree.h>
19
20#include <crm/crm.h>
21#include <crm/common/xml.h>
22#include <crm/common/ipc.h>
25#include "crmcommon_private.h"
26
27struct controld_api_private_s {
28 char *client_uuid;
29 unsigned int replies_expected;
30};
31
40const char *
42{
43 switch (reply) {
45 return "reprobe";
47 return "info";
49 return "resource";
51 return "ping";
53 return "nodes";
54 default:
55 return "unknown";
56 }
57}
58
59// \return Standard Pacemaker return code
60static int
61new_data(pcmk_ipc_api_t *api)
62{
63 struct controld_api_private_s *private = NULL;
64
65 api->api_data = calloc(1, sizeof(struct controld_api_private_s));
66
67 if (api->api_data == NULL) {
68 return errno;
69 }
70
71 private = api->api_data;
72
73 /* This is set to the PID because that's how it was always done, but PIDs
74 * are not unique because clients can be remote. The value appears to be
75 * unused other than as part of PCMK__XA_CRM_SYS_FROM in IPC requests, which
76 * is only compared against the internal system names (CRM_SYSTEM_TENGINE,
77 * etc.), so it shouldn't be a problem.
78 */
79 private->client_uuid = pcmk__getpid_s();
80
81 /* @TODO Implement a call ID model similar to the CIB, executor, and fencer
82 * IPC APIs, so that requests and replies can be matched, and
83 * duplicate replies can be discarded.
84 */
85 return pcmk_rc_ok;
86}
87
88static void
89free_data(void *data)
90{
91 free(((struct controld_api_private_s *) data)->client_uuid);
92 free(data);
93}
94
95// \return Standard Pacemaker return code
96static int
97post_connect(pcmk_ipc_api_t *api)
98{
99 /* The controller currently requires clients to register via a hello
100 * request, but does not reply back.
101 */
102 struct controld_api_private_s *private = api->api_data;
103 const char *client_name = crm_system_name? crm_system_name : "client";
104 xmlNode *hello;
105 int rc;
106
107 hello = create_hello_message(private->client_uuid, client_name,
110 rc = pcmk__send_ipc_request(api, hello);
111 free_xml(hello);
112 if (rc != pcmk_rc_ok) {
113 crm_info("Could not send IPC hello to %s: %s " CRM_XS " rc=%s",
114 pcmk_ipc_name(api, true), pcmk_rc_str(rc), rc);
115 } else {
116 crm_debug("Sent IPC hello to %s", pcmk_ipc_name(api, true));
117 }
118 return rc;
119}
120
121static void
122set_node_info_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
123{
124 data->reply_type = pcmk_controld_reply_info;
125 if (msg_data == NULL) {
126 return;
127 }
128 data->data.node_info.have_quorum =
130 data->data.node_info.is_remote =
132
133 /* Integer node_info.id is currently valid only for Corosync nodes.
134 *
135 * @TODO: Improve handling after crm_node_t is refactored to handle layer-
136 * specific data better.
137 */
138 crm_element_value_int(msg_data, PCMK_XA_ID, &(data->data.node_info.id));
139
140 data->data.node_info.uuid = crm_element_value(msg_data, PCMK_XA_ID);
141 data->data.node_info.uname = crm_element_value(msg_data, PCMK_XA_UNAME);
142 data->data.node_info.state = crm_element_value(msg_data, PCMK_XA_CRMD);
143}
144
145static void
146set_ping_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
147{
148 data->reply_type = pcmk_controld_reply_ping;
149 if (msg_data == NULL) {
150 return;
151 }
152 data->data.ping.sys_from = crm_element_value(msg_data,
154 data->data.ping.fsa_state = crm_element_value(msg_data,
156 data->data.ping.result = crm_element_value(msg_data, PCMK_XA_RESULT);
157}
158
159static void
160set_nodes_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
161{
162 pcmk_controld_api_node_t *node_info;
163
164 data->reply_type = pcmk_controld_reply_nodes;
165 for (xmlNode *node = pcmk__xe_first_child(msg_data, PCMK_XE_NODE, NULL,
166 NULL);
167 node != NULL; node = pcmk__xe_next_same(node)) {
168
169 long long id_ll = 0;
170
171 node_info = pcmk__assert_alloc(1, sizeof(pcmk_controld_api_node_t));
172 crm_element_value_ll(node, PCMK_XA_ID, &id_ll);
173 if (id_ll > 0) {
174 node_info->id = id_ll;
175 }
176 node_info->uname = crm_element_value(node, PCMK_XA_UNAME);
177 node_info->state = crm_element_value(node, PCMK__XA_IN_CCM);
178 data->data.nodes = g_list_prepend(data->data.nodes, node_info);
179 }
180}
181
182static bool
183reply_expected(pcmk_ipc_api_t *api, const xmlNode *request)
184{
185 // We only need to handle commands that API functions can send
194 NULL);
195}
196
197static bool
198dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
199{
200 struct controld_api_private_s *private = api->api_data;
201 crm_exit_t status = CRM_EX_OK;
202 xmlNode *wrapper = NULL;
203 xmlNode *msg_data = NULL;
204 const char *value = NULL;
205 pcmk_controld_api_reply_t reply_data = {
206 pcmk_controld_reply_unknown, NULL, NULL,
207 };
208
209 if (pcmk__xe_is(reply, PCMK__XE_ACK)) {
210 /* ACKs are trivial responses that do not count toward expected replies,
211 * and do not have all the fields that validation requires, so skip that
212 * processing.
213 */
214 return private->replies_expected > 0;
215 }
216
217 if (private->replies_expected > 0) {
218 private->replies_expected--;
219 }
220
221 // Do some basic validation of the reply
222
223 /* @TODO We should be able to verify that value is always a response, but
224 * currently the controller doesn't always properly set the type. Even
225 * if we fix the controller, we'll still need to handle replies from
226 * old versions (feature set could be used to differentiate).
227 */
228 value = crm_element_value(reply, PCMK__XA_SUBT);
230 NULL)) {
231 crm_info("Unrecognizable message from controller: "
232 "invalid message type '%s'", pcmk__s(value, ""));
233 status = CRM_EX_PROTOCOL;
234 goto done;
235 }
236
237 if (pcmk__str_empty(crm_element_value(reply, PCMK_XA_REFERENCE))) {
238 crm_info("Unrecognizable message from controller: no reference");
239 status = CRM_EX_PROTOCOL;
240 goto done;
241 }
242
243 value = crm_element_value(reply, PCMK__XA_CRM_TASK);
244 if (pcmk__str_empty(value)) {
245 crm_info("Unrecognizable message from controller: no command name");
246 status = CRM_EX_PROTOCOL;
247 goto done;
248 }
249
250 // Parse useful info from reply
251
252 reply_data.feature_set = crm_element_value(reply, PCMK_XA_VERSION);
253 reply_data.host_from = crm_element_value(reply, PCMK__XA_SRC);
254
255 wrapper = pcmk__xe_first_child(reply, PCMK__XE_CRM_XML, NULL, NULL);
256 msg_data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
257
258 if (!strcmp(value, CRM_OP_REPROBE)) {
260
261 } else if (!strcmp(value, CRM_OP_NODE_INFO)) {
262 set_node_info_data(&reply_data, msg_data);
263
264 } else if (!strcmp(value, CRM_OP_INVOKE_LRM)) {
266 reply_data.data.resource.node_state = msg_data;
267
268 } else if (!strcmp(value, CRM_OP_PING)) {
269 set_ping_data(&reply_data, msg_data);
270
271 } else if (!strcmp(value, PCMK__CONTROLD_CMD_NODES)) {
272 set_nodes_data(&reply_data, msg_data);
273
274 } else {
275 crm_info("Unrecognizable message from controller: unknown command '%s'",
276 value);
277 status = CRM_EX_PROTOCOL;
278 }
279
280done:
281 pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
282
283 // Free any reply data that was allocated
284 if (pcmk__str_eq(value, PCMK__CONTROLD_CMD_NODES, pcmk__str_casei)) {
285 g_list_free_full(reply_data.data.nodes, free);
286 }
287
288 return false; // No further replies needed
289}
290
293{
294 pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
295
296 if (cmds != NULL) {
297 cmds->new_data = new_data;
298 cmds->free_data = free_data;
299 cmds->post_connect = post_connect;
300 cmds->reply_expected = reply_expected;
301 cmds->dispatch = dispatch;
302 }
303 return cmds;
304}
305
317static xmlNode *
318create_controller_request(const pcmk_ipc_api_t *api, const char *op,
319 const char *node, xmlNode *msg_data)
320{
321 struct controld_api_private_s *private = NULL;
322 const char *sys_to = NULL;
323
324 if (api == NULL) {
325 return NULL;
326 }
327 private = api->api_data;
328 if ((node == NULL) && !strcmp(op, CRM_OP_PING)) {
329 sys_to = CRM_SYSTEM_DC;
330 } else {
331 sys_to = CRM_SYSTEM_CRMD;
332 }
333 return create_request(op, msg_data, node, sys_to,
334 (crm_system_name? crm_system_name : "client"),
335 private->client_uuid);
336}
337
338// \return Standard Pacemaker return code
339static int
340send_controller_request(pcmk_ipc_api_t *api, const xmlNode *request,
341 bool reply_is_expected)
342{
343 if (crm_element_value(request, PCMK_XA_REFERENCE) == NULL) {
344 return EINVAL;
345 }
346 if (reply_is_expected) {
347 struct controld_api_private_s *private = api->api_data;
348
349 private->replies_expected++;
350 }
351 return pcmk__send_ipc_request(api, request);
352}
353
354static xmlNode *
355create_reprobe_message_data(const char *target_node, const char *router_node)
356{
357 xmlNode *msg_data;
358
359 msg_data = pcmk__xe_create(NULL, "data_for_" CRM_OP_REPROBE);
360 crm_xml_add(msg_data, PCMK__META_ON_NODE, target_node);
361 if ((router_node != NULL) && !pcmk__str_eq(router_node, target_node, pcmk__str_casei)) {
362 crm_xml_add(msg_data, PCMK__XA_ROUTER_NODE, router_node);
363 }
364 return msg_data;
365}
366
377int
378pcmk_controld_api_reprobe(pcmk_ipc_api_t *api, const char *target_node,
379 const char *router_node)
380{
381 xmlNode *request;
382 xmlNode *msg_data;
383 int rc = pcmk_rc_ok;
384
385 if (api == NULL) {
386 return EINVAL;
387 }
388 if (router_node == NULL) {
389 router_node = target_node;
390 }
391 crm_debug("Sending %s IPC request to reprobe %s via %s",
392 pcmk_ipc_name(api, true), pcmk__s(target_node, "local node"),
393 pcmk__s(router_node, "local node"));
394 msg_data = create_reprobe_message_data(target_node, router_node);
395 request = create_controller_request(api, CRM_OP_REPROBE, router_node,
396 msg_data);
397 rc = send_controller_request(api, request, true);
398 free_xml(msg_data);
399 free_xml(request);
400 return rc;
401}
402
412int
414{
415 xmlNode *request;
416 int rc = pcmk_rc_ok;
417
418 request = create_controller_request(api, CRM_OP_NODE_INFO, NULL, NULL);
419 if (request == NULL) {
420 return EINVAL;
421 }
422 if (nodeid > 0) {
423 crm_xml_add_ll(request, PCMK_XA_ID, nodeid);
424 }
425
426 rc = send_controller_request(api, request, true);
427 free_xml(request);
428 return rc;
429}
430
440int
441pcmk_controld_api_ping(pcmk_ipc_api_t *api, const char *node_name)
442{
443 xmlNode *request;
444 int rc = pcmk_rc_ok;
445
446 request = create_controller_request(api, CRM_OP_PING, node_name, NULL);
447 if (request == NULL) {
448 return EINVAL;
449 }
450 rc = send_controller_request(api, request, true);
451 free_xml(request);
452 return rc;
453}
454
463int
465{
466 xmlNode *request;
467 int rc = EINVAL;
468
469 request = create_controller_request(api, PCMK__CONTROLD_CMD_NODES, NULL,
470 NULL);
471 if (request != NULL) {
472 rc = send_controller_request(api, request, true);
473 free_xml(request);
474 }
475 return rc;
476}
477
478// \return Standard Pacemaker return code
479static int
480controller_resource_op(pcmk_ipc_api_t *api, const char *op,
481 const char *target_node, const char *router_node,
482 bool cib_only, const char *rsc_id,
483 const char *rsc_long_id, const char *standard,
484 const char *provider, const char *type)
485{
486 int rc = pcmk_rc_ok;
487 char *key;
488 xmlNode *request, *msg_data, *xml_rsc, *params;
489
490 if (api == NULL) {
491 return EINVAL;
492 }
493 if (router_node == NULL) {
494 router_node = target_node;
495 }
496
497 msg_data = pcmk__xe_create(NULL, PCMK__XE_RSC_OP);
498
499 /* The controller logs the transition key from resource op requests, so we
500 * need to have *something* for it.
501 * @TODO don't use "crm-resource"
502 */
503 key = pcmk__transition_key(0, getpid(), 0,
504 "xxxxxxxx-xrsc-opxx-xcrm-resourcexxxx");
505 crm_xml_add(msg_data, PCMK__XA_TRANSITION_KEY, key);
506 free(key);
507
508 crm_xml_add(msg_data, PCMK__META_ON_NODE, target_node);
509 if (!pcmk__str_eq(router_node, target_node, pcmk__str_casei)) {
510 crm_xml_add(msg_data, PCMK__XA_ROUTER_NODE, router_node);
511 }
512
513 if (cib_only) {
514 // Indicate that only the CIB needs to be cleaned
516 }
517
518 xml_rsc = pcmk__xe_create(msg_data, PCMK_XE_PRIMITIVE);
519 crm_xml_add(xml_rsc, PCMK_XA_ID, rsc_id);
520 crm_xml_add(xml_rsc, PCMK__XA_LONG_ID, rsc_long_id);
521 crm_xml_add(xml_rsc, PCMK_XA_CLASS, standard);
522 crm_xml_add(xml_rsc, PCMK_XA_PROVIDER, provider);
523 crm_xml_add(xml_rsc, PCMK_XA_TYPE, type);
524
525 params = pcmk__xe_create(msg_data, PCMK__XE_ATTRIBUTES);
527
528 // The controller parses the timeout from the request
530 crm_xml_add(params, key, "60000"); /* 1 minute */ //@TODO pass as arg
531 free(key);
532
533 request = create_controller_request(api, op, router_node, msg_data);
534 rc = send_controller_request(api, request, true);
535 free_xml(msg_data);
536 free_xml(request);
537 return rc;
538}
539
555int
557 const char *target_node, const char *router_node,
558 const char *rsc_id, const char *rsc_long_id,
559 const char *standard, const char *provider,
560 const char *type)
561{
562 crm_debug("Sending %s IPC request to fail %s (a.k.a. %s) on %s via %s",
563 pcmk_ipc_name(api, true), pcmk__s(rsc_id, "unknown resource"),
564 pcmk__s(rsc_long_id, "no other names"),
565 pcmk__s(target_node, "unspecified node"),
566 pcmk__s(router_node, "unspecified node"));
567 return controller_resource_op(api, CRM_OP_LRM_FAIL, target_node,
568 router_node, false, rsc_id, rsc_long_id,
569 standard, provider, type);
570}
571
588int
589pcmk_controld_api_refresh(pcmk_ipc_api_t *api, const char *target_node,
590 const char *router_node,
591 const char *rsc_id, const char *rsc_long_id,
592 const char *standard, const char *provider,
593 const char *type, bool cib_only)
594{
595 crm_debug("Sending %s IPC request to refresh %s (a.k.a. %s) on %s via %s",
596 pcmk_ipc_name(api, true), pcmk__s(rsc_id, "unknown resource"),
597 pcmk__s(rsc_long_id, "no other names"),
598 pcmk__s(target_node, "unspecified node"),
599 pcmk__s(router_node, "unspecified node"));
600 return controller_resource_op(api, CRM_OP_LRM_DELETE, target_node,
601 router_node, cib_only, rsc_id, rsc_long_id,
602 standard, provider, type);
603}
604
612unsigned int
614{
615 struct controld_api_private_s *private = api->api_data;
616
617 return private->replies_expected;
618}
619
625// \todo make this static to this file when breaking API backward compatibility
626xmlNode *
627create_hello_message(const char *uuid, const char *client_name,
628 const char *major_version, const char *minor_version)
629{
630 xmlNode *hello_node = NULL;
631 xmlNode *hello = NULL;
632
633 if (pcmk__str_empty(uuid) || pcmk__str_empty(client_name)
634 || pcmk__str_empty(major_version) || pcmk__str_empty(minor_version)) {
635 crm_err("Could not create IPC hello message from %s (UUID %s): "
636 "missing information",
637 client_name? client_name : "unknown client",
638 uuid? uuid : "unknown");
639 return NULL;
640 }
641
642 hello_node = pcmk__xe_create(NULL, PCMK__XE_OPTIONS);
643 crm_xml_add(hello_node, PCMK__XA_MAJOR_VERSION, major_version);
644 crm_xml_add(hello_node, PCMK__XA_MINOR_VERSION, minor_version);
645 crm_xml_add(hello_node, PCMK__XA_CLIENT_NAME, client_name);
646
647 // @TODO Nothing uses this. Drop, or keep for debugging?
648 crm_xml_add(hello_node, PCMK__XA_CLIENT_UUID, uuid);
649
650 hello = create_request(CRM_OP_HELLO, hello_node, NULL, NULL, client_name, uuid);
651 if (hello == NULL) {
652 crm_err("Could not create IPC hello message from %s (UUID %s): "
653 "Request creation failed", client_name, uuid);
654 return NULL;
655 }
656 free_xml(hello_node);
657
658 crm_trace("Created hello message from %s (UUID %s)", client_name, uuid);
659 return hello;
660}
char * pcmk__transition_key(int transition_id, int action_id, int target_rc, const char *node)
Definition actions.c:404
bool pcmk__xe_attr_is_true(const xmlNode *node, const char *name)
Definition nvpair.c:936
#define pcmk__assert_alloc(nmemb, size)
Definition internal.h:297
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:90
#define CRM_SYSTEM_DC
Definition crm.h:87
#define CRM_OP_HELLO
Definition crm.h:124
#define CRM_OP_REPROBE
Definition crm.h:136
#define CRM_FEATURE_SET
Definition crm.h:72
#define CRM_OP_PING
Definition crm.h:119
#define CRM_OP_LRM_FAIL
Definition crm.h:134
#define CRM_OP_RM_NODE_CACHE
Definition crm.h:139
#define CRM_OP_LRM_DELETE
Definition crm.h:133
#define CRM_OP_NODE_INFO
Definition crm.h:120
char * crm_system_name
Definition utils.c:50
#define CRM_OP_INVOKE_LRM
Definition crm.h:131
#define PCMK__CONTROLD_CMD_NODES
G_GNUC_INTERNAL int pcmk__send_ipc_request(pcmk_ipc_api_t *api, const xmlNode *request)
Definition ipc_client.c:668
#define PCMK__CONTROLD_API_MINOR
#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:150
IPC interface to Pacemaker daemons.
#define create_request(task, xml_data, host_to, sys_to, sys_from, uuid_from)
Definition ipc.h:49
@ pcmk_ipc_event_reply
Daemon's reply to client IPC request.
Definition ipc.h:96
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:247
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.
int pcmk_controld_api_list_nodes(pcmk_ipc_api_t *api)
Ask the controller for cluster information.
int pcmk_controld_api_ping(pcmk_ipc_api_t *api, const char *node_name)
Ask the controller for status.
unsigned int pcmk_controld_api_replies_expected(const pcmk_ipc_api_t *api)
Get the number of IPC replies currently expected from the controller.
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.
int pcmk_controld_api_node_info(pcmk_ipc_api_t *api, uint32_t nodeid)
Send a "node info" controller operation.
const char * pcmk__controld_api_reply2str(enum pcmk_controld_api_reply reply)
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.
int pcmk_controld_api_reprobe(pcmk_ipc_api_t *api, const char *target_node, const char *router_node)
Send a reprobe controller operation.
pcmk__ipc_methods_t * pcmk__controld_api_methods(void)
IPC commands for Pacemaker controller.
pcmk_controld_api_reply
Possible types of controller replies.
@ pcmk_controld_reply_nodes
@ pcmk_controld_reply_reprobe
@ pcmk_controld_reply_resource
@ pcmk_controld_reply_ping
@ pcmk_controld_reply_info
@ pcmk_controld_reply_unknown
#define crm_info(fmt, args...)
Definition logging.h:397
#define CRM_XS
Definition logging.h:56
#define crm_debug(fmt, args...)
Definition logging.h:400
#define crm_err(fmt, args...)
Definition logging.h:389
#define crm_trace(fmt, args...)
Definition logging.h:402
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:446
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
char * crm_meta_name(const char *field)
Get the environment variable equivalent of a meta-attribute name.
Definition nvpair.c:959
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:514
const char * crm_xml_add_ll(xmlNode *node, const char *name, long long value)
Create an XML attribute with specified name and long long int value.
Definition nvpair.c:398
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
#define PCMK_META_TIMEOUT
Definition options.h:114
#define PCMK__VALUE_RESPONSE
#define PCMK__VALUE_CIB
#define PCMK__META_ON_NODE
#define PCMK__VALUE_REQUEST
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition results.c:501
@ CRM_EX_PROTOCOL
Protocol violated.
Definition results.h:281
@ CRM_EX_OK
Success.
Definition results.h:255
@ pcmk_rc_ok
Definition results.h:162
enum crm_exit_e crm_exit_t
@ pcmk__str_casei
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1050
int(* new_data)(pcmk_ipc_api_t *api)
bool(* reply_expected)(pcmk_ipc_api_t *api, const xmlNode *request)
void(* free_data)(void *api_data)
bool(* dispatch)(pcmk_ipc_api_t *api, xmlNode *msg)
int(* post_connect)(pcmk_ipc_api_t *api)
const char * feature_set
CRM feature set advertised by controller.
struct pcmk_controld_api_reply_t::@1::@3 resource
const char * host_from
Name of node that sent reply.
enum pcmk_controld_api_reply reply_type
union pcmk_controld_api_reply_t::@1 data
Wrappers for and extensions to libxml2.
void free_xml(xmlNode *child)
Definition xml.c:867
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml.c:440
xmlNode * pcmk__xe_next_same(const xmlNode *node)
Definition xml.c:2108
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition xml.c:720
#define PCMK_XA_CLASS
Definition xml_names.h:241
#define PCMK_XE_NODE
Definition xml_names.h:133
#define PCMK_XA_RESULT
Definition xml_names.h:381
#define PCMK_XA_ID
Definition xml_names.h:296
#define PCMK_XA_CRMD
Definition xml_names.h:251
#define PCMK_XA_PROVIDER
Definition xml_names.h:359
#define PCMK_XA_HAVE_QUORUM
Definition xml_names.h:290
#define PCMK_XA_VERSION
Definition xml_names.h:439
#define PCMK_XA_CRM_FEATURE_SET
Definition xml_names.h:249
#define PCMK_XE_PRIMITIVE
Definition xml_names.h:160
#define PCMK_XA_TYPE
Definition xml_names.h:425
#define PCMK_XA_REMOTE_NODE
Definition xml_names.h:371
#define PCMK_XA_UNAME
Definition xml_names.h:426
#define PCMK_XA_REFERENCE
Definition xml_names.h:367
#define PCMK__XE_RSC_OP
#define PCMK__XA_CRMD_STATE
#define PCMK__XA_CRM_TASK
#define PCMK__XA_CLIENT_NAME
#define PCMK__XA_MAJOR_VERSION
#define PCMK__XA_SUBT
#define PCMK__XA_ROUTER_NODE
#define PCMK__XE_OPTIONS
#define PCMK__XA_MINOR_VERSION
#define PCMK__XE_ACK
#define PCMK__XA_MODE
#define PCMK__XA_IN_CCM
#define PCMK__XA_CLIENT_UUID
#define PCMK__XA_TRANSITION_KEY
#define PCMK__XE_ATTRIBUTES
#define PCMK__XA_CRM_SUBSYSTEM
#define PCMK__XE_CRM_XML
#define PCMK__XA_LONG_ID
#define PCMK__XA_SRC