pacemaker 2.1.1-77db578727
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
ipc_controld.c
Go to the documentation of this file.
1/*
2 * Copyright 2020-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 <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
92#define xml_true(xml, field) crm_is_true(crm_element_value(xml, field))
93
94static void
95set_node_info_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
96{
97 data->reply_type = pcmk_controld_reply_info;
98 if (msg_data == NULL) {
99 return;
100 }
101 data->data.node_info.have_quorum = xml_true(msg_data, XML_ATTR_HAVE_QUORUM);
102 data->data.node_info.is_remote = xml_true(msg_data, XML_NODE_IS_REMOTE);
103 crm_element_value_int(msg_data, XML_ATTR_ID, &(data->data.node_info.id));
104 data->data.node_info.uuid = crm_element_value(msg_data, XML_ATTR_UUID);
105 data->data.node_info.uname = crm_element_value(msg_data, XML_ATTR_UNAME);
106 data->data.node_info.state = crm_element_value(msg_data, XML_NODE_IS_PEER);
107}
108
109static void
110set_ping_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
111{
112 data->reply_type = pcmk_controld_reply_ping;
113 if (msg_data == NULL) {
114 return;
115 }
116 data->data.ping.sys_from = crm_element_value(msg_data,
118 data->data.ping.fsa_state = crm_element_value(msg_data,
120 data->data.ping.result = crm_element_value(msg_data, XML_PING_ATTR_STATUS);
121}
122
123static void
124set_nodes_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
125{
126 pcmk_controld_api_node_t *node_info;
127
128 data->reply_type = pcmk_controld_reply_nodes;
129 for (xmlNode *node = first_named_child(msg_data, XML_CIB_TAG_NODE);
130 node != NULL; node = crm_next_same_xml(node)) {
131
132 long long id_ll = 0;
133
134 node_info = calloc(1, sizeof(pcmk_controld_api_node_t));
135 crm_element_value_ll(node, XML_ATTR_ID, &id_ll);
136 if (id_ll > 0) {
137 node_info->id = id_ll;
138 }
139 node_info->uname = crm_element_value(node, XML_ATTR_UNAME);
140 node_info->state = crm_element_value(node, XML_NODE_IN_CLUSTER);
141 data->data.nodes = g_list_prepend(data->data.nodes, node_info);
142 }
143}
144
145static bool
146reply_expected(pcmk_ipc_api_t *api, xmlNode *request)
147{
148 const char *command = crm_element_value(request, F_CRM_TASK);
149
150 if (command == NULL) {
151 return false;
152 }
153
154 // We only need to handle commands that functions in this file can send
155 return !strcmp(command, CRM_OP_REPROBE)
156 || !strcmp(command, CRM_OP_NODE_INFO)
157 || !strcmp(command, CRM_OP_PING)
158 || !strcmp(command, CRM_OP_LRM_FAIL)
159 || !strcmp(command, CRM_OP_LRM_DELETE);
160}
161
162static void
163dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
164{
165 struct controld_api_private_s *private = api->api_data;
166 crm_exit_t status = CRM_EX_OK;
167 xmlNode *msg_data = NULL;
168 const char *value = NULL;
169 pcmk_controld_api_reply_t reply_data = {
170 pcmk_controld_reply_unknown, NULL, NULL,
171 };
172
173 if (private->replies_expected > 0) {
174 private->replies_expected--;
175 }
176
177 // Do some basic validation of the reply
178
179 /* @TODO We should be able to verify that value is always a response, but
180 * currently the controller doesn't always properly set the type. Even
181 * if we fix the controller, we'll still need to handle replies from
182 * old versions (feature set could be used to differentiate).
183 */
184 value = crm_element_value(reply, F_CRM_MSG_TYPE);
185 if ((value == NULL) || (strcmp(value, XML_ATTR_REQUEST)
186 && strcmp(value, XML_ATTR_RESPONSE))) {
187 crm_debug("Unrecognizable controller message: invalid message type '%s'",
188 crm_str(value));
189 status = CRM_EX_PROTOCOL;
190 goto done;
191 }
192
193 if (crm_element_value(reply, XML_ATTR_REFERENCE) == NULL) {
194 crm_debug("Unrecognizable controller message: no reference");
195 status = CRM_EX_PROTOCOL;
196 goto done;
197 }
198
199 value = crm_element_value(reply, F_CRM_TASK);
200 if (value == NULL) {
201 crm_debug("Unrecognizable controller message: no command name");
202 status = CRM_EX_PROTOCOL;
203 goto done;
204 }
205
206 // Parse useful info from reply
207
209 reply_data.host_from = crm_element_value(reply, F_CRM_HOST_FROM);
210 msg_data = get_message_xml(reply, F_CRM_DATA);
211
212 if (!strcmp(value, CRM_OP_REPROBE)) {
214
215 } else if (!strcmp(value, CRM_OP_NODE_INFO)) {
216 set_node_info_data(&reply_data, msg_data);
217
218 } else if (!strcmp(value, CRM_OP_INVOKE_LRM)) {
220 reply_data.data.resource.node_state = msg_data;
221
222 } else if (!strcmp(value, CRM_OP_PING)) {
223 set_ping_data(&reply_data, msg_data);
224
225 } else if (!strcmp(value, PCMK__CONTROLD_CMD_NODES)) {
226 set_nodes_data(&reply_data, msg_data);
227
228 } else {
229 crm_debug("Unrecognizable controller message: unknown command '%s'",
230 value);
231 status = CRM_EX_PROTOCOL;
232 }
233
234done:
235 pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
236
237 // Free any reply data that was allocated
238 if (pcmk__str_eq(value, PCMK__CONTROLD_CMD_NODES, pcmk__str_casei)) {
239 g_list_free_full(reply_data.data.nodes, free);
240 }
241}
242
245{
246 pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
247
248 if (cmds != NULL) {
249 cmds->new_data = new_data;
250 cmds->free_data = free_data;
251 cmds->post_connect = post_connect;
252 cmds->reply_expected = reply_expected;
253 cmds->dispatch = dispatch;
254 }
255 return cmds;
256}
257
269static xmlNode *
270create_controller_request(pcmk_ipc_api_t *api, const char *op,
271 const char *node, xmlNode *msg_data)
272{
273 struct controld_api_private_s *private = NULL;
274 const char *sys_to = NULL;
275
276 if (api == NULL) {
277 return NULL;
278 }
279 private = api->api_data;
280 if ((node == NULL) && !strcmp(op, CRM_OP_PING)) {
281 sys_to = CRM_SYSTEM_DC;
282 } else {
283 sys_to = CRM_SYSTEM_CRMD;
284 }
285 return create_request(op, msg_data, node, sys_to,
286 (crm_system_name? crm_system_name : "client"),
287 private->client_uuid);
288}
289
290// \return Standard Pacemaker return code
291static int
292send_controller_request(pcmk_ipc_api_t *api, xmlNode *request,
293 bool reply_is_expected)
294{
295 int rc;
296
297 if (crm_element_value(request, XML_ATTR_REFERENCE) == NULL) {
298 return EINVAL;
299 }
300 rc = pcmk__send_ipc_request(api, request);
301 if ((rc == pcmk_rc_ok) && reply_is_expected) {
302 struct controld_api_private_s *private = api->api_data;
303
304 private->replies_expected++;
305 }
306 return rc;
307}
308
309static xmlNode *
310create_reprobe_message_data(const char *target_node, const char *router_node)
311{
312 xmlNode *msg_data;
313
314 msg_data = create_xml_node(NULL, "data_for_" CRM_OP_REPROBE);
315 crm_xml_add(msg_data, XML_LRM_ATTR_TARGET, target_node);
316 if ((router_node != NULL) && !pcmk__str_eq(router_node, target_node, pcmk__str_casei)) {
317 crm_xml_add(msg_data, XML_LRM_ATTR_ROUTER_NODE, router_node);
318 }
319 return msg_data;
320}
321
332int
333pcmk_controld_api_reprobe(pcmk_ipc_api_t *api, const char *target_node,
334 const char *router_node)
335{
336 xmlNode *request;
337 xmlNode *msg_data;
338 int rc = pcmk_rc_ok;
339
340 if (api == NULL) {
341 return EINVAL;
342 }
343 if (router_node == NULL) {
344 router_node = target_node;
345 }
346 crm_debug("Sending %s IPC request to reprobe %s via %s",
347 pcmk_ipc_name(api, true), crm_str(target_node),
348 crm_str(router_node));
349 msg_data = create_reprobe_message_data(target_node, router_node);
350 request = create_controller_request(api, CRM_OP_REPROBE, router_node,
351 msg_data);
352 rc = send_controller_request(api, request, true);
353 free_xml(msg_data);
354 free_xml(request);
355 return rc;
356}
357
367int
369{
370 xmlNode *request;
371 int rc = pcmk_rc_ok;
372
373 request = create_controller_request(api, CRM_OP_NODE_INFO, NULL, NULL);
374 if (request == NULL) {
375 return EINVAL;
376 }
377 if (nodeid > 0) {
378 crm_xml_set_id(request, "%lu", (unsigned long) nodeid);
379 }
380
381 rc = send_controller_request(api, request, true);
382 free_xml(request);
383 return rc;
384}
385
395int
396pcmk_controld_api_ping(pcmk_ipc_api_t *api, const char *node_name)
397{
398 xmlNode *request;
399 int rc = pcmk_rc_ok;
400
401 request = create_controller_request(api, CRM_OP_PING, node_name, NULL);
402 if (request == NULL) {
403 return EINVAL;
404 }
405 rc = send_controller_request(api, request, true);
406 free_xml(request);
407 return rc;
408}
409
418int
420{
421 xmlNode *request;
422 int rc = EINVAL;
423
424 request = create_controller_request(api, PCMK__CONTROLD_CMD_NODES, NULL,
425 NULL);
426 if (request != NULL) {
427 rc = send_controller_request(api, request, true);
428 free_xml(request);
429 }
430 return rc;
431}
432
433// \return Standard Pacemaker return code
434static int
435controller_resource_op(pcmk_ipc_api_t *api, const char *op,
436 const char *target_node, const char *router_node,
437 bool cib_only, const char *rsc_id,
438 const char *rsc_long_id, const char *standard,
439 const char *provider, const char *type)
440{
441 int rc = pcmk_rc_ok;
442 char *key;
443 xmlNode *request, *msg_data, *xml_rsc, *params;
444
445 if (api == NULL) {
446 return EINVAL;
447 }
448 if (router_node == NULL) {
449 router_node = target_node;
450 }
451
452 msg_data = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP);
453
454 /* The controller logs the transition key from resource op requests, so we
455 * need to have *something* for it.
456 * @TODO don't use "crm-resource"
457 */
458 key = pcmk__transition_key(0, getpid(), 0,
459 "xxxxxxxx-xrsc-opxx-xcrm-resourcexxxx");
460 crm_xml_add(msg_data, XML_ATTR_TRANSITION_KEY, key);
461 free(key);
462
463 crm_xml_add(msg_data, XML_LRM_ATTR_TARGET, target_node);
464 if (!pcmk__str_eq(router_node, target_node, pcmk__str_casei)) {
465 crm_xml_add(msg_data, XML_LRM_ATTR_ROUTER_NODE, router_node);
466 }
467
468 if (cib_only) {
469 // Indicate that only the CIB needs to be cleaned
471 }
472
473 xml_rsc = create_xml_node(msg_data, XML_CIB_TAG_RESOURCE);
474 crm_xml_add(xml_rsc, XML_ATTR_ID, rsc_id);
475 crm_xml_add(xml_rsc, XML_ATTR_ID_LONG, rsc_long_id);
476 crm_xml_add(xml_rsc, XML_AGENT_ATTR_CLASS, standard);
477 crm_xml_add(xml_rsc, XML_AGENT_ATTR_PROVIDER, provider);
478 crm_xml_add(xml_rsc, XML_ATTR_TYPE, type);
479
480 params = create_xml_node(msg_data, XML_TAG_ATTRS);
482
483 // The controller parses the timeout from the request
485 crm_xml_add(params, key, "60000"); /* 1 minute */ //@TODO pass as arg
486 free(key);
487
488 request = create_controller_request(api, op, router_node, msg_data);
489 rc = send_controller_request(api, request, true);
490 free_xml(msg_data);
491 free_xml(request);
492 return rc;
493}
494
510int
512 const char *target_node, const char *router_node,
513 const char *rsc_id, const char *rsc_long_id,
514 const char *standard, const char *provider,
515 const char *type)
516{
517 crm_debug("Sending %s IPC request to fail %s (a.k.a. %s) on %s via %s",
518 pcmk_ipc_name(api, true), crm_str(rsc_id), crm_str(rsc_long_id),
519 crm_str(target_node), crm_str(router_node));
520 return controller_resource_op(api, CRM_OP_LRM_FAIL, target_node,
521 router_node, false, rsc_id, rsc_long_id,
522 standard, provider, type);
523}
524
541int
542pcmk_controld_api_refresh(pcmk_ipc_api_t *api, const char *target_node,
543 const char *router_node,
544 const char *rsc_id, const char *rsc_long_id,
545 const char *standard, const char *provider,
546 const char *type, bool cib_only)
547{
548 crm_debug("Sending %s IPC request to refresh %s (a.k.a. %s) on %s via %s",
549 pcmk_ipc_name(api, true), crm_str(rsc_id), crm_str(rsc_long_id),
550 crm_str(target_node), crm_str(router_node));
551 return controller_resource_op(api, CRM_OP_LRM_DELETE, target_node,
552 router_node, cib_only, rsc_id, rsc_long_id,
553 standard, provider, type);
554}
555
563unsigned int
565{
566 struct controld_api_private_s *private = api->api_data;
567
568 return private->replies_expected;
569}
570
576// \todo make this static to this file when breaking API backward compatibility
577xmlNode *
578create_hello_message(const char *uuid, const char *client_name,
579 const char *major_version, const char *minor_version)
580{
581 xmlNode *hello_node = NULL;
582 xmlNode *hello = NULL;
583
584 if (pcmk__str_empty(uuid) || pcmk__str_empty(client_name)
585 || pcmk__str_empty(major_version) || pcmk__str_empty(minor_version)) {
586 crm_err("Could not create IPC hello message from %s (UUID %s): "
587 "missing information",
588 client_name? client_name : "unknown client",
589 uuid? uuid : "unknown");
590 return NULL;
591 }
592
593 hello_node = create_xml_node(NULL, XML_TAG_OPTIONS);
594 if (hello_node == NULL) {
595 crm_err("Could not create IPC hello message from %s (UUID %s): "
596 "Message data creation failed", client_name, uuid);
597 return NULL;
598 }
599
600 crm_xml_add(hello_node, "major_version", major_version);
601 crm_xml_add(hello_node, "minor_version", minor_version);
602 crm_xml_add(hello_node, "client_name", client_name);
603 crm_xml_add(hello_node, "client_uuid", uuid);
604
605 hello = create_request(CRM_OP_HELLO, hello_node, NULL, NULL, client_name, uuid);
606 if (hello == NULL) {
607 crm_err("Could not create IPC hello message from %s (UUID %s): "
608 "Request creation failed", client_name, uuid);
609 return NULL;
610 }
611 free_xml(hello_node);
612
613 crm_trace("Created hello message from %s (UUID %s)", client_name, uuid);
614 return hello;
615}
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:511
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:106
#define CRM_SYSTEM_DC
Definition crm.h:102
#define CRM_OP_HELLO
Definition crm.h:139
#define CRM_OP_REPROBE
Definition crm.h:154
#define CRM_FEATURE_SET
Definition crm.h:69
#define CRM_OP_PING
Definition crm.h:134
#define CRM_OP_LRM_FAIL
Definition crm.h:152
#define CRM_OP_LRM_DELETE
Definition crm.h:151
#define CRM_OP_NODE_INFO
Definition crm.h:135
char * crm_system_name
Definition utils.c:54
#define CRM_OP_INVOKE_LRM
Definition crm.h:148
#define PCMK__CONTROLD_CMD_NODES
#define PCMK__XA_MODE
#define PCMK__CONTROLD_API_MINOR
G_GNUC_INTERNAL int pcmk__send_ipc_request(pcmk_ipc_api_t *api, xmlNode *request)
Definition ipc_client.c:584
#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.
#define create_request(task, xml_data, host_to, sys_to, sys_from, uuid_from)
Definition ipc.h:42
const char * pcmk_ipc_name(pcmk_ipc_api_t *api, bool for_log)
Get the IPC name used with an IPC API connection.
Definition ipc_client.c:241
@ pcmk_ipc_event_reply
Daemon's reply to client IPC request.
Definition ipc.h:82
#define xml_true(xml, field)
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.
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.
unsigned int pcmk_controld_api_replies_expected(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.
pcmk__ipc_methods_t * pcmk__controld_api_methods()
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.
IPC commands for Pacemaker controller.
@ 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_str(x)
Definition logging.h:376
#define crm_info(fmt, args...)
Definition logging.h:353
#define CRM_XS
Definition logging.h:54
#define crm_debug(fmt, args...)
Definition logging.h:355
#define crm_err(fmt, args...)
Definition logging.h:350
#define crm_trace(fmt, args...)
Definition logging.h:356
#define XML_TAG_CIB
Definition msg_xml.h:109
#define XML_LRM_ATTR_ROUTER_NODE
Definition msg_xml.h:305
#define XML_ATTR_TRANSITION_KEY
Definition msg_xml.h:399
#define XML_ATTR_CRM_VERSION
Definition msg_xml.h:112
#define XML_ATTR_UNAME
Definition msg_xml.h:151
#define XML_PING_ATTR_SYSFROM
Definition msg_xml.h:157
#define XML_ATTR_UUID
Definition msg_xml.h:152
#define XML_NODE_IS_PEER
Definition msg_xml.h:278
#define XML_ATTR_REQUEST
Definition msg_xml.h:148
#define F_CRM_HOST_FROM
Definition msg_xml.h:90
#define XML_NODE_IS_REMOTE
Definition msg_xml.h:279
#define XML_ATTR_ID
Definition msg_xml.h:129
#define XML_PING_ATTR_CRMDSTATE
Definition msg_xml.h:158
#define XML_NODE_IN_CLUSTER
Definition msg_xml.h:277
#define XML_ATTR_HAVE_QUORUM
Definition msg_xml.h:118
#define F_CRM_MSG_TYPE
Definition msg_xml.h:87
#define XML_AGENT_ATTR_PROVIDER
Definition msg_xml.h:267
#define XML_AGENT_ATTR_CLASS
Definition msg_xml.h:266
#define XML_TAG_ATTRS
Definition msg_xml.h:205
#define XML_ATTR_ID_LONG
Definition msg_xml.h:131
#define XML_PING_ATTR_STATUS
Definition msg_xml.h:156
#define XML_ATTR_TYPE
Definition msg_xml.h:132
#define XML_ATTR_RESPONSE
Definition msg_xml.h:149
#define XML_LRM_ATTR_TARGET
Definition msg_xml.h:299
#define XML_ATTR_TIMEOUT
Definition msg_xml.h:123
#define XML_ATTR_REFERENCE
Definition msg_xml.h:153
#define F_CRM_DATA
Definition msg_xml.h:84
#define XML_GRAPH_TAG_RSC_OP
Definition msg_xml.h:326
#define F_CRM_TASK
Definition msg_xml.h:85
#define XML_TAG_OPTIONS
Definition msg_xml.h:145
#define XML_ATTR_VERSION
Definition msg_xml.h:127
#define XML_CIB_TAG_NODE
Definition msg_xml.h:199
#define XML_CIB_TAG_RESOURCE
Definition msg_xml.h:214
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:530
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition nvpair.c:566
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:598
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:324
int rc
Definition pcmk_fence.c:35
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition results.c:420
@ CRM_EX_PROTOCOL
Definition results.h:241
@ CRM_EX_OK
Definition results.h:217
@ pcmk_rc_ok
Definition results.h:142
enum crm_exit_e crm_exit_t
@ pcmk__str_casei
int(* new_data)(pcmk_ipc_api_t *api)
void(* free_data)(void *api_data)
void(* 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.
union pcmk_controld_api_reply_t::@0 data
const char * host_from
Name of node that sent reply.
enum pcmk_controld_api_reply reply_type
struct pcmk_controld_api_reply_t::@0::@2 resource
Wrappers for and extensions to libxml2.
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition xml.c:2790
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:2816
void free_xml(xmlNode *child)
Definition xml.c:823
xmlNode * get_message_xml(xmlNode *msg, const char *field)
Definition messages.c:154
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition xml.c:696