pacemaker 3.0.1-16e74fc4da
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
32static xmlNode *create_hello_message(const char *uuid, const char *client_name,
33 const char *major_version,
34 const char *minor_version);
35
44const char *
46{
47 switch (reply) {
49 return "reprobe";
51 return "info";
53 return "resource";
55 return "ping";
57 return "nodes";
58 default:
59 return "unknown";
60 }
61}
62
63// \return Standard Pacemaker return code
64static int
65new_data(pcmk_ipc_api_t *api)
66{
67 struct controld_api_private_s *private = NULL;
68
69 api->api_data = calloc(1, sizeof(struct controld_api_private_s));
70
71 if (api->api_data == NULL) {
72 return errno;
73 }
74
75 private = api->api_data;
76
77 /* This is set to the PID because that's how it was always done, but PIDs
78 * are not unique because clients can be remote. The value appears to be
79 * unused other than as part of PCMK__XA_CRM_SYS_FROM in IPC requests, which
80 * is only compared against the internal system names (CRM_SYSTEM_TENGINE,
81 * etc.), so it shouldn't be a problem.
82 */
83 private->client_uuid = pcmk__getpid_s();
84
85 /* @TODO Implement a call ID model similar to the CIB, executor, and fencer
86 * IPC APIs, so that requests and replies can be matched, and
87 * duplicate replies can be discarded.
88 */
89 return pcmk_rc_ok;
90}
91
92static void
93free_data(void *data)
94{
95 free(((struct controld_api_private_s *) data)->client_uuid);
96 free(data);
97}
98
99// \return Standard Pacemaker return code
100static int
101post_connect(pcmk_ipc_api_t *api)
102{
103 /* The controller currently requires clients to register via a hello
104 * request, but does not reply back.
105 */
106 struct controld_api_private_s *private = api->api_data;
107 const char *client_name = crm_system_name? crm_system_name : "client";
108 xmlNode *hello;
109 int rc;
110
111 hello = create_hello_message(private->client_uuid, client_name,
114 rc = pcmk__send_ipc_request(api, hello);
115 pcmk__xml_free(hello);
116 if (rc != pcmk_rc_ok) {
117 crm_info("Could not send IPC hello to %s: %s " QB_XS " rc=%s",
118 pcmk_ipc_name(api, true), pcmk_rc_str(rc), rc);
119 } else {
120 crm_debug("Sent IPC hello to %s", pcmk_ipc_name(api, true));
121 }
122 return rc;
123}
124
125static void
126set_node_info_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
127{
128 data->reply_type = pcmk_controld_reply_info;
129 if (msg_data == NULL) {
130 return;
131 }
132 data->data.node_info.have_quorum =
134 data->data.node_info.is_remote =
136
137 /* Integer node_info.id is currently valid only for Corosync nodes.
138 *
139 * @TODO: Improve handling after pcmk__node_status_t is refactored to handle
140 * layer-specific data better.
141 */
142 crm_element_value_int(msg_data, PCMK_XA_ID, &(data->data.node_info.id));
143
144 data->data.node_info.uuid = crm_element_value(msg_data, PCMK_XA_ID);
145 data->data.node_info.uname = crm_element_value(msg_data, PCMK_XA_UNAME);
146 data->data.node_info.state = crm_element_value(msg_data, PCMK_XA_CRMD);
147}
148
149static void
150set_ping_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
151{
152 data->reply_type = pcmk_controld_reply_ping;
153 if (msg_data == NULL) {
154 return;
155 }
156 data->data.ping.sys_from = crm_element_value(msg_data,
158 data->data.ping.fsa_state = crm_element_value(msg_data,
160 data->data.ping.result = crm_element_value(msg_data, PCMK_XA_RESULT);
161}
162
163static void
164set_nodes_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
165{
166 pcmk_controld_api_node_t *node_info;
167
168 data->reply_type = pcmk_controld_reply_nodes;
169 for (xmlNode *node = pcmk__xe_first_child(msg_data, PCMK_XE_NODE, NULL,
170 NULL);
171 node != NULL; node = pcmk__xe_next(node, PCMK_XE_NODE)) {
172
173 long long id_ll = 0;
174
175 node_info = pcmk__assert_alloc(1, sizeof(pcmk_controld_api_node_t));
176 crm_element_value_ll(node, PCMK_XA_ID, &id_ll);
177 if (id_ll > 0) {
178 node_info->id = id_ll;
179 }
180 node_info->uname = crm_element_value(node, PCMK_XA_UNAME);
181 node_info->state = crm_element_value(node, PCMK__XA_IN_CCM);
182 data->data.nodes = g_list_prepend(data->data.nodes, node_info);
183 }
184}
185
186static bool
187reply_expected(pcmk_ipc_api_t *api, const xmlNode *request)
188{
189 // We only need to handle commands that API functions can send
198 NULL);
199}
200
201static bool
202dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
203{
204 struct controld_api_private_s *private = api->api_data;
205 crm_exit_t status = CRM_EX_OK;
206 xmlNode *wrapper = NULL;
207 xmlNode *msg_data = NULL;
208 const char *value = NULL;
209 pcmk_controld_api_reply_t reply_data = {
210 pcmk_controld_reply_unknown, NULL, NULL,
211 };
212
213 if (pcmk__xe_is(reply, PCMK__XE_ACK)) {
214 /* ACKs are trivial responses that do not count toward expected replies,
215 * and do not have all the fields that validation requires, so skip that
216 * processing.
217 */
218 return private->replies_expected > 0;
219 }
220
221 if (private->replies_expected > 0) {
222 private->replies_expected--;
223 }
224
225 // Do some basic validation of the reply
226
227 value = crm_element_value(reply, PCMK__XA_SUBT);
228 if (pcmk__str_eq(value, PCMK__VALUE_REQUEST, pcmk__str_none)) {
229 /* @COMPAT Controllers <3.0.0 set PCMK__XA_SUBT to PCMK__VALUE_REQUEST
230 * for certain replies. Once we no longer support Pacemaker Remote nodes
231 * connecting to cluster nodes <3.0.0, or rolling upgrades from <3.0.0,
232 * we can drop this check.
233 */
234 crm_trace("Received a reply that was marked as a request "
235 "(bug unless sent by a controller <3.0.0)");
236
237 } else if (!pcmk__str_eq(value, PCMK__VALUE_RESPONSE, pcmk__str_none)) {
238 crm_info("Unrecognizable message from controller: "
239 "invalid message type '%s'", pcmk__s(value, ""));
240 status = CRM_EX_PROTOCOL;
241 goto done;
242 }
243
244 if (pcmk__str_empty(crm_element_value(reply, PCMK_XA_REFERENCE))) {
245 crm_info("Unrecognizable message from controller: no reference");
246 status = CRM_EX_PROTOCOL;
247 goto done;
248 }
249
250 value = crm_element_value(reply, PCMK__XA_CRM_TASK);
251 if (pcmk__str_empty(value)) {
252 crm_info("Unrecognizable message from controller: no command name");
253 status = CRM_EX_PROTOCOL;
254 goto done;
255 }
256
257 // Parse useful info from reply
258
259 reply_data.feature_set = crm_element_value(reply, PCMK_XA_VERSION);
260 reply_data.host_from = crm_element_value(reply, PCMK__XA_SRC);
261
262 wrapper = pcmk__xe_first_child(reply, PCMK__XE_CRM_XML, NULL, NULL);
263 msg_data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
264
265 if (!strcmp(value, CRM_OP_REPROBE)) {
267
268 } else if (!strcmp(value, CRM_OP_NODE_INFO)) {
269 set_node_info_data(&reply_data, msg_data);
270
271 } else if (!strcmp(value, CRM_OP_INVOKE_LRM)) {
273 reply_data.data.resource.node_state = msg_data;
274
275 } else if (!strcmp(value, CRM_OP_PING)) {
276 set_ping_data(&reply_data, msg_data);
277
278 } else if (!strcmp(value, PCMK__CONTROLD_CMD_NODES)) {
279 set_nodes_data(&reply_data, msg_data);
280
281 } else {
282 crm_info("Unrecognizable message from controller: unknown command '%s'",
283 value);
284 status = CRM_EX_PROTOCOL;
285 }
286
287done:
288 pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
289
290 // Free any reply data that was allocated
291 if (pcmk__str_eq(value, PCMK__CONTROLD_CMD_NODES, pcmk__str_casei)) {
292 g_list_free_full(reply_data.data.nodes, free);
293 }
294
295 return false; // No further replies needed
296}
297
300{
301 pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
302
303 if (cmds != NULL) {
304 cmds->new_data = new_data;
305 cmds->free_data = free_data;
306 cmds->post_connect = post_connect;
307 cmds->reply_expected = reply_expected;
308 cmds->dispatch = dispatch;
309 }
310 return cmds;
311}
312
324static xmlNode *
325create_controller_request(const pcmk_ipc_api_t *api, const char *op,
326 const char *node, xmlNode *msg_data)
327{
328 struct controld_api_private_s *private = NULL;
329 const char *sys_to = NULL;
330 char *sender_system = NULL;
331 xmlNode *request = NULL;
332
333 if (api == NULL) {
334 return NULL;
335 }
336 private = api->api_data;
337 if ((node == NULL) && !strcmp(op, CRM_OP_PING)) {
338 sys_to = CRM_SYSTEM_DC;
339 } else {
340 sys_to = CRM_SYSTEM_CRMD;
341 }
342 sender_system = crm_strdup_printf("%s_%s", private->client_uuid,
343 pcmk__s(crm_system_name, "client"));
344 request = pcmk__new_request(pcmk_ipc_controld, sender_system, node, sys_to,
345 op, msg_data);
346 free(sender_system);
347 return request;
348}
349
350// \return Standard Pacemaker return code
351static int
352send_controller_request(pcmk_ipc_api_t *api, const xmlNode *request,
353 bool reply_is_expected)
354{
355 if (crm_element_value(request, PCMK_XA_REFERENCE) == NULL) {
356 return EINVAL;
357 }
358 if (reply_is_expected) {
359 struct controld_api_private_s *private = api->api_data;
360
361 private->replies_expected++;
362 }
363 return pcmk__send_ipc_request(api, request);
364}
365
366static xmlNode *
367create_reprobe_message_data(const char *target_node, const char *router_node)
368{
369 xmlNode *msg_data;
370
371 msg_data = pcmk__xe_create(NULL, "data_for_" CRM_OP_REPROBE);
372 crm_xml_add(msg_data, PCMK__META_ON_NODE, target_node);
373 if ((router_node != NULL) && !pcmk__str_eq(router_node, target_node, pcmk__str_casei)) {
374 crm_xml_add(msg_data, PCMK__XA_ROUTER_NODE, router_node);
375 }
376 return msg_data;
377}
378
389int
390pcmk_controld_api_reprobe(pcmk_ipc_api_t *api, const char *target_node,
391 const char *router_node)
392{
393 xmlNode *request;
394 xmlNode *msg_data;
395 int rc = pcmk_rc_ok;
396
397 if (api == NULL) {
398 return EINVAL;
399 }
400 if (router_node == NULL) {
401 router_node = target_node;
402 }
403 crm_debug("Sending %s IPC request to reprobe %s via %s",
404 pcmk_ipc_name(api, true), pcmk__s(target_node, "local node"),
405 pcmk__s(router_node, "local node"));
406 msg_data = create_reprobe_message_data(target_node, router_node);
407 request = create_controller_request(api, CRM_OP_REPROBE, router_node,
408 msg_data);
409 rc = send_controller_request(api, request, true);
410 pcmk__xml_free(msg_data);
411 pcmk__xml_free(request);
412 return rc;
413}
414
424int
426{
427 xmlNode *request;
428 int rc = pcmk_rc_ok;
429
430 request = create_controller_request(api, CRM_OP_NODE_INFO, NULL, NULL);
431 if (request == NULL) {
432 return EINVAL;
433 }
434 if (nodeid > 0) {
435 crm_xml_add_ll(request, PCMK_XA_ID, nodeid);
436 }
437
438 rc = send_controller_request(api, request, true);
439 pcmk__xml_free(request);
440 return rc;
441}
442
452int
453pcmk_controld_api_ping(pcmk_ipc_api_t *api, const char *node_name)
454{
455 xmlNode *request;
456 int rc = pcmk_rc_ok;
457
458 request = create_controller_request(api, CRM_OP_PING, node_name, NULL);
459 if (request == NULL) {
460 return EINVAL;
461 }
462 rc = send_controller_request(api, request, true);
463 pcmk__xml_free(request);
464 return rc;
465}
466
475int
477{
478 xmlNode *request;
479 int rc = EINVAL;
480
481 request = create_controller_request(api, PCMK__CONTROLD_CMD_NODES, NULL,
482 NULL);
483 if (request != NULL) {
484 rc = send_controller_request(api, request, true);
485 pcmk__xml_free(request);
486 }
487 return rc;
488}
489
490// \return Standard Pacemaker return code
491static int
492controller_resource_op(pcmk_ipc_api_t *api, const char *op,
493 const char *target_node, const char *router_node,
494 bool cib_only, const char *rsc_id,
495 const char *rsc_long_id, const char *standard,
496 const char *provider, const char *type)
497{
498 int rc = pcmk_rc_ok;
499 char *key;
500 xmlNode *request, *msg_data, *xml_rsc, *params;
501
502 if (api == NULL) {
503 return EINVAL;
504 }
505 if (router_node == NULL) {
506 router_node = target_node;
507 }
508
509 msg_data = pcmk__xe_create(NULL, PCMK__XE_RSC_OP);
510
511 /* The controller logs the transition key from resource op requests, so we
512 * need to have *something* for it.
513 * @TODO don't use "crm-resource"
514 */
515 key = pcmk__transition_key(0, getpid(), 0,
516 "xxxxxxxx-xrsc-opxx-xcrm-resourcexxxx");
517 crm_xml_add(msg_data, PCMK__XA_TRANSITION_KEY, key);
518 free(key);
519
520 crm_xml_add(msg_data, PCMK__META_ON_NODE, target_node);
521 if (!pcmk__str_eq(router_node, target_node, pcmk__str_casei)) {
522 crm_xml_add(msg_data, PCMK__XA_ROUTER_NODE, router_node);
523 }
524
525 if (cib_only) {
526 // Indicate that only the CIB needs to be cleaned
528 }
529
530 xml_rsc = pcmk__xe_create(msg_data, PCMK_XE_PRIMITIVE);
531 crm_xml_add(xml_rsc, PCMK_XA_ID, rsc_id);
532 crm_xml_add(xml_rsc, PCMK__XA_LONG_ID, rsc_long_id);
533 crm_xml_add(xml_rsc, PCMK_XA_CLASS, standard);
534 crm_xml_add(xml_rsc, PCMK_XA_PROVIDER, provider);
535 crm_xml_add(xml_rsc, PCMK_XA_TYPE, type);
536
537 params = pcmk__xe_create(msg_data, PCMK__XE_ATTRIBUTES);
539
540 // The controller parses the timeout from the request
542 crm_xml_add(params, key, "60000"); /* 1 minute */ //@TODO pass as arg
543 free(key);
544
545 request = create_controller_request(api, op, router_node, msg_data);
546 rc = send_controller_request(api, request, true);
547 pcmk__xml_free(msg_data);
548 pcmk__xml_free(request);
549 return rc;
550}
551
567int
569 const char *target_node, const char *router_node,
570 const char *rsc_id, const char *rsc_long_id,
571 const char *standard, const char *provider,
572 const char *type)
573{
574 crm_debug("Sending %s IPC request to fail %s (a.k.a. %s) on %s via %s",
575 pcmk_ipc_name(api, true), pcmk__s(rsc_id, "unknown resource"),
576 pcmk__s(rsc_long_id, "no other names"),
577 pcmk__s(target_node, "unspecified node"),
578 pcmk__s(router_node, "unspecified node"));
579 return controller_resource_op(api, CRM_OP_LRM_FAIL, target_node,
580 router_node, false, rsc_id, rsc_long_id,
581 standard, provider, type);
582}
583
600int
601pcmk_controld_api_refresh(pcmk_ipc_api_t *api, const char *target_node,
602 const char *router_node,
603 const char *rsc_id, const char *rsc_long_id,
604 const char *standard, const char *provider,
605 const char *type, bool cib_only)
606{
607 crm_debug("Sending %s IPC request to refresh %s (a.k.a. %s) on %s via %s",
608 pcmk_ipc_name(api, true), pcmk__s(rsc_id, "unknown resource"),
609 pcmk__s(rsc_long_id, "no other names"),
610 pcmk__s(target_node, "unspecified node"),
611 pcmk__s(router_node, "unspecified node"));
612 return controller_resource_op(api, CRM_OP_LRM_DELETE, target_node,
613 router_node, cib_only, rsc_id, rsc_long_id,
614 standard, provider, type);
615}
616
624unsigned int
626{
627 struct controld_api_private_s *private = api->api_data;
628
629 return private->replies_expected;
630}
631
636static xmlNode *
637create_hello_message(const char *uuid, const char *client_name,
638 const char *major_version, const char *minor_version)
639{
640 xmlNode *hello_node = NULL;
641 xmlNode *hello = NULL;
642 char *sender_system = NULL;
643
644 if (pcmk__str_empty(uuid) || pcmk__str_empty(client_name)
645 || pcmk__str_empty(major_version) || pcmk__str_empty(minor_version)) {
646 crm_err("Could not create IPC hello message from %s (UUID %s): "
647 "missing information",
648 client_name? client_name : "unknown client",
649 uuid? uuid : "unknown");
650 return NULL;
651 }
652
653 hello_node = pcmk__xe_create(NULL, PCMK__XE_OPTIONS);
654 crm_xml_add(hello_node, PCMK__XA_MAJOR_VERSION, major_version);
655 crm_xml_add(hello_node, PCMK__XA_MINOR_VERSION, minor_version);
656 crm_xml_add(hello_node, PCMK__XA_CLIENT_NAME, client_name);
657
658 // @TODO Nothing uses this. Drop, or keep for debugging?
659 crm_xml_add(hello_node, PCMK__XA_CLIENT_UUID, uuid);
660
661 sender_system = crm_strdup_printf("%s_%s", uuid, client_name);
662 hello = pcmk__new_request(pcmk_ipc_controld, sender_system, NULL, NULL,
663 CRM_OP_HELLO, hello_node);
664 free(sender_system);
665 pcmk__xml_free(hello_node);
666 if (hello == NULL) {
667 crm_err("Could not create IPC hello message from %s (UUID %s): "
668 "Request creation failed", client_name, uuid);
669 return NULL;
670 }
671
672 crm_trace("Created hello message from %s (UUID %s)", client_name, uuid);
673 return hello;
674}
char * pcmk__transition_key(int transition_id, int action_id, int target_rc, const char *node)
Definition actions.c:432
#define pcmk__assert_alloc(nmemb, size)
Definition internal.h:246
char data[0]
Definition cpg.c:10
enum pcmk_ipc_server type
Definition cpg.c:3
A dumping ground.
#define CRM_SYSTEM_CRMD
Definition crm.h:84
#define CRM_SYSTEM_DC
Definition crm.h:81
#define CRM_OP_HELLO
Definition crm.h:117
#define CRM_OP_REPROBE
Definition crm.h:128
#define CRM_FEATURE_SET
Definition crm.h:66
#define CRM_OP_PING
Definition crm.h:112
#define CRM_OP_LRM_FAIL
Definition crm.h:126
#define CRM_OP_RM_NODE_CACHE
Definition crm.h:131
#define CRM_OP_LRM_DELETE
Definition crm.h:125
#define CRM_OP_NODE_INFO
Definition crm.h:113
char * crm_system_name
Definition utils.c:45
#define CRM_OP_INVOKE_LRM
Definition crm.h:124
#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:684
#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:144
IPC interface to Pacemaker daemons.
@ pcmk_ipc_event_reply
Daemon's reply to client IPC request.
Definition ipc.h:68
@ pcmk_ipc_controld
Controller.
Definition ipc.h:52
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:241
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.
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:365
#define crm_debug(fmt, args...)
Definition logging.h:368
#define crm_err(fmt, args...)
Definition logging.h:357
#define crm_trace(fmt, args...)
Definition logging.h:370
#define pcmk__new_request(server, sender_system, recipient_node, recipient_system, task, data)
char * crm_meta_name(const char *field)
Get the environment variable equivalent of a meta-attribute name.
Definition nvpair.c:525
#define PCMK_META_TIMEOUT
Definition options.h:115
#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:617
@ CRM_EX_PROTOCOL
Protocol violated.
Definition results.h:259
@ CRM_EX_OK
Success.
Definition results.h:233
@ pcmk_rc_ok
Definition results.h:159
enum crm_exit_e crm_exit_t
Exit status codes for tools and daemons.
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
@ pcmk__str_none
@ pcmk__str_casei
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1053
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.
xmlNode * node_state
Resource operation history XML.
enum pcmk_controld_api_reply reply_type
union pcmk_controld_api_reply_t::@1 data
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.
int crm_element_value_ll(const xmlNode *data, const char *name, long long *dest)
Retrieve the long long integer value of an XML attribute.
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.
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
bool pcmk__xe_attr_is_true(const xmlNode *node, const char *name)
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
void pcmk__xml_free(xmlNode *xml)
Definition xml.c:816
#define PCMK_XA_CLASS
Definition xml_names.h:246
#define PCMK_XE_NODE
Definition xml_names.h:136
#define PCMK_XA_RESULT
Definition xml_names.h:386
#define PCMK_XA_ID
Definition xml_names.h:301
#define PCMK_XA_CRMD
Definition xml_names.h:256
#define PCMK_XA_PROVIDER
Definition xml_names.h:364
#define PCMK_XA_HAVE_QUORUM
Definition xml_names.h:295
#define PCMK_XA_VERSION
Definition xml_names.h:444
#define PCMK_XA_CRM_FEATURE_SET
Definition xml_names.h:254
#define PCMK_XE_PRIMITIVE
Definition xml_names.h:164
#define PCMK_XA_TYPE
Definition xml_names.h:430
#define PCMK_XA_REMOTE_NODE
Definition xml_names.h:376
#define PCMK_XA_UNAME
Definition xml_names.h:431
#define PCMK_XA_REFERENCE
Definition xml_names.h:372
#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