This source file includes following definitions.
- pcmk__controld_api_reply2str
- new_data
- free_data
- post_connect
- set_node_info_data
- set_ping_data
- set_nodes_data
- reply_expected
- dispatch
- pcmk__controld_api_methods
- create_controller_request
- send_controller_request
- create_reprobe_message_data
- pcmk_controld_api_reprobe
- pcmk_controld_api_node_info
- pcmk_controld_api_ping
- pcmk_controld_api_list_nodes
- controller_resource_op
- pcmk_controld_api_fail
- pcmk_controld_api_refresh
- pcmk_controld_api_replies_expected
- create_hello_message
1
2
3
4
5
6
7
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>
21 #include <crm/common/ipc_internal.h>
22 #include <crm/common/ipc_controld.h>
23 #include "crmcommon_private.h"
24
25 struct controld_api_private_s {
26 char *client_uuid;
27 unsigned int replies_expected;
28 };
29
30
31
32
33
34
35
36
37
38 const char *
39 pcmk__controld_api_reply2str(enum pcmk_controld_api_reply reply)
40 {
41 switch (reply) {
42 case pcmk_controld_reply_reprobe:
43 return "reprobe";
44 case pcmk_controld_reply_info:
45 return "info";
46 case pcmk_controld_reply_resource:
47 return "resource";
48 case pcmk_controld_reply_ping:
49 return "ping";
50 case pcmk_controld_reply_nodes:
51 return "nodes";
52 default:
53 return "unknown";
54 }
55 }
56
57
58 static int
59 new_data(pcmk_ipc_api_t *api)
60 {
61 struct controld_api_private_s *private = NULL;
62
63 api->api_data = calloc(1, sizeof(struct controld_api_private_s));
64
65 if (api->api_data == NULL) {
66 return errno;
67 }
68
69 private = api->api_data;
70
71
72
73
74
75
76
77 private->client_uuid = pcmk__getpid_s();
78
79
80
81
82
83 return pcmk_rc_ok;
84 }
85
86 static void
87 free_data(void *data)
88 {
89 free(((struct controld_api_private_s *) data)->client_uuid);
90 free(data);
91 }
92
93
94 static int
95 post_connect(pcmk_ipc_api_t *api)
96 {
97
98
99
100 struct controld_api_private_s *private = api->api_data;
101 const char *client_name = crm_system_name? crm_system_name : "client";
102 xmlNode *hello;
103 int rc;
104
105 hello = create_hello_message(private->client_uuid, client_name,
106 PCMK__CONTROLD_API_MAJOR,
107 PCMK__CONTROLD_API_MINOR);
108 rc = pcmk__send_ipc_request(api, hello);
109 free_xml(hello);
110 if (rc != pcmk_rc_ok) {
111 crm_info("Could not send IPC hello to %s: %s " CRM_XS " rc=%s",
112 pcmk_ipc_name(api, true), pcmk_rc_str(rc), rc);
113 } else {
114 crm_debug("Sent IPC hello to %s", pcmk_ipc_name(api, true));
115 }
116 return rc;
117 }
118
119 static void
120 set_node_info_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
121 {
122 data->reply_type = pcmk_controld_reply_info;
123 if (msg_data == NULL) {
124 return;
125 }
126 data->data.node_info.have_quorum = pcmk__xe_attr_is_true(msg_data, XML_ATTR_HAVE_QUORUM);
127 data->data.node_info.is_remote = pcmk__xe_attr_is_true(msg_data, XML_NODE_IS_REMOTE);
128
129
130
131
132
133
134 crm_element_value_int(msg_data, XML_ATTR_ID, &(data->data.node_info.id));
135
136 data->data.node_info.uuid = crm_element_value(msg_data, XML_ATTR_ID);
137 data->data.node_info.uname = crm_element_value(msg_data, XML_ATTR_UNAME);
138 data->data.node_info.state = crm_element_value(msg_data, PCMK__XA_CRMD);
139 }
140
141 static void
142 set_ping_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
143 {
144 data->reply_type = pcmk_controld_reply_ping;
145 if (msg_data == NULL) {
146 return;
147 }
148 data->data.ping.sys_from = crm_element_value(msg_data,
149 XML_PING_ATTR_SYSFROM);
150 data->data.ping.fsa_state = crm_element_value(msg_data,
151 XML_PING_ATTR_CRMDSTATE);
152 data->data.ping.result = crm_element_value(msg_data, XML_PING_ATTR_STATUS);
153 }
154
155 static void
156 set_nodes_data(pcmk_controld_api_reply_t *data, xmlNode *msg_data)
157 {
158 pcmk_controld_api_node_t *node_info;
159
160 data->reply_type = pcmk_controld_reply_nodes;
161 for (xmlNode *node = first_named_child(msg_data, XML_CIB_TAG_NODE);
162 node != NULL; node = crm_next_same_xml(node)) {
163
164 long long id_ll = 0;
165
166 node_info = calloc(1, sizeof(pcmk_controld_api_node_t));
167 crm_element_value_ll(node, XML_ATTR_ID, &id_ll);
168 if (id_ll > 0) {
169 node_info->id = id_ll;
170 }
171 node_info->uname = crm_element_value(node, XML_ATTR_UNAME);
172 node_info->state = crm_element_value(node, PCMK__XA_IN_CCM);
173 data->data.nodes = g_list_prepend(data->data.nodes, node_info);
174 }
175 }
176
177 static bool
178 reply_expected(pcmk_ipc_api_t *api, const xmlNode *request)
179 {
180
181 return pcmk__str_any_of(crm_element_value(request, F_CRM_TASK),
182 PCMK__CONTROLD_CMD_NODES,
183 CRM_OP_LRM_DELETE,
184 CRM_OP_LRM_FAIL,
185 CRM_OP_NODE_INFO,
186 CRM_OP_PING,
187 CRM_OP_REPROBE,
188 CRM_OP_RM_NODE_CACHE,
189 NULL);
190 }
191
192 static bool
193 dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
194 {
195 struct controld_api_private_s *private = api->api_data;
196 crm_exit_t status = CRM_EX_OK;
197 xmlNode *msg_data = NULL;
198 const char *value = NULL;
199 pcmk_controld_api_reply_t reply_data = {
200 pcmk_controld_reply_unknown, NULL, NULL,
201 };
202
203 if (pcmk__xe_is(reply, "ack")) {
204
205
206
207
208 return private->replies_expected > 0;
209 }
210
211 if (private->replies_expected > 0) {
212 private->replies_expected--;
213 }
214
215
216
217
218
219
220
221
222 value = crm_element_value(reply, F_CRM_MSG_TYPE);
223 if (pcmk__str_empty(value)
224 || !pcmk__str_any_of(value, XML_ATTR_REQUEST, XML_ATTR_RESPONSE, NULL)) {
225 crm_info("Unrecognizable message from controller: "
226 "invalid message type '%s'", pcmk__s(value, ""));
227 status = CRM_EX_PROTOCOL;
228 goto done;
229 }
230
231 if (pcmk__str_empty(crm_element_value(reply, XML_ATTR_REFERENCE))) {
232 crm_info("Unrecognizable message from controller: no reference");
233 status = CRM_EX_PROTOCOL;
234 goto done;
235 }
236
237 value = crm_element_value(reply, F_CRM_TASK);
238 if (pcmk__str_empty(value)) {
239 crm_info("Unrecognizable message from controller: no command name");
240 status = CRM_EX_PROTOCOL;
241 goto done;
242 }
243
244
245
246 reply_data.feature_set = crm_element_value(reply, XML_ATTR_VERSION);
247 reply_data.host_from = crm_element_value(reply, F_CRM_HOST_FROM);
248 msg_data = get_message_xml(reply, F_CRM_DATA);
249
250 if (!strcmp(value, CRM_OP_REPROBE)) {
251 reply_data.reply_type = pcmk_controld_reply_reprobe;
252
253 } else if (!strcmp(value, CRM_OP_NODE_INFO)) {
254 set_node_info_data(&reply_data, msg_data);
255
256 } else if (!strcmp(value, CRM_OP_INVOKE_LRM)) {
257 reply_data.reply_type = pcmk_controld_reply_resource;
258 reply_data.data.resource.node_state = msg_data;
259
260 } else if (!strcmp(value, CRM_OP_PING)) {
261 set_ping_data(&reply_data, msg_data);
262
263 } else if (!strcmp(value, PCMK__CONTROLD_CMD_NODES)) {
264 set_nodes_data(&reply_data, msg_data);
265
266 } else {
267 crm_info("Unrecognizable message from controller: unknown command '%s'",
268 value);
269 status = CRM_EX_PROTOCOL;
270 }
271
272 done:
273 pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
274
275
276 if (pcmk__str_eq(value, PCMK__CONTROLD_CMD_NODES, pcmk__str_casei)) {
277 g_list_free_full(reply_data.data.nodes, free);
278 }
279
280 return false;
281 }
282
283 pcmk__ipc_methods_t *
284 pcmk__controld_api_methods(void)
285 {
286 pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
287
288 if (cmds != NULL) {
289 cmds->new_data = new_data;
290 cmds->free_data = free_data;
291 cmds->post_connect = post_connect;
292 cmds->reply_expected = reply_expected;
293 cmds->dispatch = dispatch;
294 }
295 return cmds;
296 }
297
298
299
300
301
302
303
304
305
306
307
308
309 static xmlNode *
310 create_controller_request(const pcmk_ipc_api_t *api, const char *op,
311 const char *node, xmlNode *msg_data)
312 {
313 struct controld_api_private_s *private = NULL;
314 const char *sys_to = NULL;
315
316 if (api == NULL) {
317 return NULL;
318 }
319 private = api->api_data;
320 if ((node == NULL) && !strcmp(op, CRM_OP_PING)) {
321 sys_to = CRM_SYSTEM_DC;
322 } else {
323 sys_to = CRM_SYSTEM_CRMD;
324 }
325 return create_request(op, msg_data, node, sys_to,
326 (crm_system_name? crm_system_name : "client"),
327 private->client_uuid);
328 }
329
330
331 static int
332 send_controller_request(pcmk_ipc_api_t *api, const xmlNode *request,
333 bool reply_is_expected)
334 {
335 if (crm_element_value(request, XML_ATTR_REFERENCE) == NULL) {
336 return EINVAL;
337 }
338 if (reply_is_expected) {
339 struct controld_api_private_s *private = api->api_data;
340
341 private->replies_expected++;
342 }
343 return pcmk__send_ipc_request(api, request);
344 }
345
346 static xmlNode *
347 create_reprobe_message_data(const char *target_node, const char *router_node)
348 {
349 xmlNode *msg_data;
350
351 msg_data = create_xml_node(NULL, "data_for_" CRM_OP_REPROBE);
352 crm_xml_add(msg_data, XML_LRM_ATTR_TARGET, target_node);
353 if ((router_node != NULL) && !pcmk__str_eq(router_node, target_node, pcmk__str_casei)) {
354 crm_xml_add(msg_data, XML_LRM_ATTR_ROUTER_NODE, router_node);
355 }
356 return msg_data;
357 }
358
359
360
361
362
363
364
365
366
367
368
369 int
370 pcmk_controld_api_reprobe(pcmk_ipc_api_t *api, const char *target_node,
371 const char *router_node)
372 {
373 xmlNode *request;
374 xmlNode *msg_data;
375 int rc = pcmk_rc_ok;
376
377 if (api == NULL) {
378 return EINVAL;
379 }
380 if (router_node == NULL) {
381 router_node = target_node;
382 }
383 crm_debug("Sending %s IPC request to reprobe %s via %s",
384 pcmk_ipc_name(api, true), pcmk__s(target_node, "local node"),
385 pcmk__s(router_node, "local node"));
386 msg_data = create_reprobe_message_data(target_node, router_node);
387 request = create_controller_request(api, CRM_OP_REPROBE, router_node,
388 msg_data);
389 rc = send_controller_request(api, request, true);
390 free_xml(msg_data);
391 free_xml(request);
392 return rc;
393 }
394
395
396
397
398
399
400
401
402
403
404 int
405 pcmk_controld_api_node_info(pcmk_ipc_api_t *api, uint32_t nodeid)
406 {
407 xmlNode *request;
408 int rc = pcmk_rc_ok;
409
410 request = create_controller_request(api, CRM_OP_NODE_INFO, NULL, NULL);
411 if (request == NULL) {
412 return EINVAL;
413 }
414 if (nodeid > 0) {
415 crm_xml_set_id(request, "%lu", (unsigned long) nodeid);
416 }
417
418 rc = send_controller_request(api, request, true);
419 free_xml(request);
420 return rc;
421 }
422
423
424
425
426
427
428
429
430
431
432 int
433 pcmk_controld_api_ping(pcmk_ipc_api_t *api, const char *node_name)
434 {
435 xmlNode *request;
436 int rc = pcmk_rc_ok;
437
438 request = create_controller_request(api, CRM_OP_PING, node_name, NULL);
439 if (request == NULL) {
440 return EINVAL;
441 }
442 rc = send_controller_request(api, request, true);
443 free_xml(request);
444 return rc;
445 }
446
447
448
449
450
451
452
453
454
455 int
456 pcmk_controld_api_list_nodes(pcmk_ipc_api_t *api)
457 {
458 xmlNode *request;
459 int rc = EINVAL;
460
461 request = create_controller_request(api, PCMK__CONTROLD_CMD_NODES, NULL,
462 NULL);
463 if (request != NULL) {
464 rc = send_controller_request(api, request, true);
465 free_xml(request);
466 }
467 return rc;
468 }
469
470
471 static int
472 controller_resource_op(pcmk_ipc_api_t *api, const char *op,
473 const char *target_node, const char *router_node,
474 bool cib_only, const char *rsc_id,
475 const char *rsc_long_id, const char *standard,
476 const char *provider, const char *type)
477 {
478 int rc = pcmk_rc_ok;
479 char *key;
480 xmlNode *request, *msg_data, *xml_rsc, *params;
481
482 if (api == NULL) {
483 return EINVAL;
484 }
485 if (router_node == NULL) {
486 router_node = target_node;
487 }
488
489 msg_data = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP);
490
491
492
493
494
495 key = pcmk__transition_key(0, getpid(), 0,
496 "xxxxxxxx-xrsc-opxx-xcrm-resourcexxxx");
497 crm_xml_add(msg_data, XML_ATTR_TRANSITION_KEY, key);
498 free(key);
499
500 crm_xml_add(msg_data, XML_LRM_ATTR_TARGET, target_node);
501 if (!pcmk__str_eq(router_node, target_node, pcmk__str_casei)) {
502 crm_xml_add(msg_data, XML_LRM_ATTR_ROUTER_NODE, router_node);
503 }
504
505 if (cib_only) {
506
507 crm_xml_add(msg_data, PCMK__XA_MODE, XML_TAG_CIB);
508 }
509
510 xml_rsc = create_xml_node(msg_data, XML_CIB_TAG_RESOURCE);
511 crm_xml_add(xml_rsc, XML_ATTR_ID, rsc_id);
512 crm_xml_add(xml_rsc, XML_ATTR_ID_LONG, rsc_long_id);
513 crm_xml_add(xml_rsc, XML_AGENT_ATTR_CLASS, standard);
514 crm_xml_add(xml_rsc, XML_AGENT_ATTR_PROVIDER, provider);
515 crm_xml_add(xml_rsc, XML_ATTR_TYPE, type);
516
517 params = create_xml_node(msg_data, XML_TAG_ATTRS);
518 crm_xml_add(params, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
519
520
521 key = crm_meta_name(XML_ATTR_TIMEOUT);
522 crm_xml_add(params, key, "60000");
523 free(key);
524
525 request = create_controller_request(api, op, router_node, msg_data);
526 rc = send_controller_request(api, request, true);
527 free_xml(msg_data);
528 free_xml(request);
529 return rc;
530 }
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547 int
548 pcmk_controld_api_fail(pcmk_ipc_api_t *api,
549 const char *target_node, const char *router_node,
550 const char *rsc_id, const char *rsc_long_id,
551 const char *standard, const char *provider,
552 const char *type)
553 {
554 crm_debug("Sending %s IPC request to fail %s (a.k.a. %s) on %s via %s",
555 pcmk_ipc_name(api, true), pcmk__s(rsc_id, "unknown resource"),
556 pcmk__s(rsc_long_id, "no other names"),
557 pcmk__s(target_node, "unspecified node"),
558 pcmk__s(router_node, "unspecified node"));
559 return controller_resource_op(api, CRM_OP_LRM_FAIL, target_node,
560 router_node, false, rsc_id, rsc_long_id,
561 standard, provider, type);
562 }
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580 int
581 pcmk_controld_api_refresh(pcmk_ipc_api_t *api, const char *target_node,
582 const char *router_node,
583 const char *rsc_id, const char *rsc_long_id,
584 const char *standard, const char *provider,
585 const char *type, bool cib_only)
586 {
587 crm_debug("Sending %s IPC request to refresh %s (a.k.a. %s) on %s via %s",
588 pcmk_ipc_name(api, true), pcmk__s(rsc_id, "unknown resource"),
589 pcmk__s(rsc_long_id, "no other names"),
590 pcmk__s(target_node, "unspecified node"),
591 pcmk__s(router_node, "unspecified node"));
592 return controller_resource_op(api, CRM_OP_LRM_DELETE, target_node,
593 router_node, cib_only, rsc_id, rsc_long_id,
594 standard, provider, type);
595 }
596
597
598
599
600
601
602
603
604 unsigned int
605 pcmk_controld_api_replies_expected(const pcmk_ipc_api_t *api)
606 {
607 struct controld_api_private_s *private = api->api_data;
608
609 return private->replies_expected;
610 }
611
612
613
614
615
616
617
618 xmlNode *
619 create_hello_message(const char *uuid, const char *client_name,
620 const char *major_version, const char *minor_version)
621 {
622 xmlNode *hello_node = NULL;
623 xmlNode *hello = NULL;
624
625 if (pcmk__str_empty(uuid) || pcmk__str_empty(client_name)
626 || pcmk__str_empty(major_version) || pcmk__str_empty(minor_version)) {
627 crm_err("Could not create IPC hello message from %s (UUID %s): "
628 "missing information",
629 client_name? client_name : "unknown client",
630 uuid? uuid : "unknown");
631 return NULL;
632 }
633
634 hello_node = create_xml_node(NULL, XML_TAG_OPTIONS);
635 if (hello_node == NULL) {
636 crm_err("Could not create IPC hello message from %s (UUID %s): "
637 "Message data creation failed", client_name, uuid);
638 return NULL;
639 }
640
641 crm_xml_add(hello_node, "major_version", major_version);
642 crm_xml_add(hello_node, "minor_version", minor_version);
643 crm_xml_add(hello_node, "client_name", client_name);
644 crm_xml_add(hello_node, "client_uuid", uuid);
645
646 hello = create_request(CRM_OP_HELLO, hello_node, NULL, NULL, client_name, uuid);
647 if (hello == NULL) {
648 crm_err("Could not create IPC hello message from %s (UUID %s): "
649 "Request creation failed", client_name, uuid);
650 return NULL;
651 }
652 free_xml(hello_node);
653
654 crm_trace("Created hello message from %s (UUID %s)", client_name, uuid);
655 return hello;
656 }