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, XML_NODE_IS_PEER);
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, XML_NODE_IN_CLUSTER);
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, xmlNode *request)
179 {
180 const char *command = crm_element_value(request, F_CRM_TASK);
181
182 if (command == NULL) {
183 return false;
184 }
185
186
187 return !strcmp(command, CRM_OP_REPROBE)
188 || !strcmp(command, CRM_OP_NODE_INFO)
189 || !strcmp(command, CRM_OP_PING)
190 || !strcmp(command, CRM_OP_LRM_FAIL)
191 || !strcmp(command, CRM_OP_LRM_DELETE);
192 }
193
194 static bool
195 dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
196 {
197 struct controld_api_private_s *private = api->api_data;
198 crm_exit_t status = CRM_EX_OK;
199 xmlNode *msg_data = NULL;
200 const char *value = NULL;
201 pcmk_controld_api_reply_t reply_data = {
202 pcmk_controld_reply_unknown, NULL, NULL,
203 };
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219 if (pcmk__str_eq(crm_element_name(reply), "ack", pcmk__str_none)) {
220 return true;
221 }
222
223 if (private->replies_expected > 0) {
224 private->replies_expected--;
225 }
226
227
228
229
230
231
232
233
234 value = crm_element_value(reply, F_CRM_MSG_TYPE);
235 if (pcmk__str_empty(value)
236 || !pcmk__str_any_of(value, XML_ATTR_REQUEST, XML_ATTR_RESPONSE, NULL)) {
237 crm_info("Unrecognizable message from controller: "
238 "invalid message type '%s'", pcmk__s(value, ""));
239 status = CRM_EX_PROTOCOL;
240 goto done;
241 }
242
243 if (pcmk__str_empty(crm_element_value(reply, XML_ATTR_REFERENCE))) {
244 crm_info("Unrecognizable message from controller: no reference");
245 status = CRM_EX_PROTOCOL;
246 goto done;
247 }
248
249 value = crm_element_value(reply, F_CRM_TASK);
250 if (pcmk__str_empty(value)) {
251 crm_info("Unrecognizable message from controller: no command name");
252 status = CRM_EX_PROTOCOL;
253 goto done;
254 }
255
256
257
258 reply_data.feature_set = crm_element_value(reply, XML_ATTR_VERSION);
259 reply_data.host_from = crm_element_value(reply, F_CRM_HOST_FROM);
260 msg_data = get_message_xml(reply, F_CRM_DATA);
261
262 if (!strcmp(value, CRM_OP_REPROBE)) {
263 reply_data.reply_type = pcmk_controld_reply_reprobe;
264
265 } else if (!strcmp(value, CRM_OP_NODE_INFO)) {
266 set_node_info_data(&reply_data, msg_data);
267
268 } else if (!strcmp(value, CRM_OP_INVOKE_LRM)) {
269 reply_data.reply_type = pcmk_controld_reply_resource;
270 reply_data.data.resource.node_state = msg_data;
271
272 } else if (!strcmp(value, CRM_OP_PING)) {
273 set_ping_data(&reply_data, msg_data);
274
275 } else if (!strcmp(value, PCMK__CONTROLD_CMD_NODES)) {
276 set_nodes_data(&reply_data, msg_data);
277
278 } else {
279 crm_info("Unrecognizable message from controller: unknown command '%s'",
280 value);
281 status = CRM_EX_PROTOCOL;
282 }
283
284 done:
285 pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
286
287
288 if (pcmk__str_eq(value, PCMK__CONTROLD_CMD_NODES, pcmk__str_casei)) {
289 g_list_free_full(reply_data.data.nodes, free);
290 }
291
292 return false;
293 }
294
295 pcmk__ipc_methods_t *
296 pcmk__controld_api_methods(void)
297 {
298 pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
299
300 if (cmds != NULL) {
301 cmds->new_data = new_data;
302 cmds->free_data = free_data;
303 cmds->post_connect = post_connect;
304 cmds->reply_expected = reply_expected;
305 cmds->dispatch = dispatch;
306 }
307 return cmds;
308 }
309
310
311
312
313
314
315
316
317
318
319
320
321 static xmlNode *
322 create_controller_request(const pcmk_ipc_api_t *api, const char *op,
323 const char *node, xmlNode *msg_data)
324 {
325 struct controld_api_private_s *private = NULL;
326 const char *sys_to = NULL;
327
328 if (api == NULL) {
329 return NULL;
330 }
331 private = api->api_data;
332 if ((node == NULL) && !strcmp(op, CRM_OP_PING)) {
333 sys_to = CRM_SYSTEM_DC;
334 } else {
335 sys_to = CRM_SYSTEM_CRMD;
336 }
337 return create_request(op, msg_data, node, sys_to,
338 (crm_system_name? crm_system_name : "client"),
339 private->client_uuid);
340 }
341
342
343 static int
344 send_controller_request(pcmk_ipc_api_t *api, xmlNode *request,
345 bool reply_is_expected)
346 {
347 int rc;
348
349 if (crm_element_value(request, XML_ATTR_REFERENCE) == NULL) {
350 return EINVAL;
351 }
352 rc = pcmk__send_ipc_request(api, request);
353 if ((rc == pcmk_rc_ok) && reply_is_expected) {
354 struct controld_api_private_s *private = api->api_data;
355
356 private->replies_expected++;
357 }
358 return rc;
359 }
360
361 static xmlNode *
362 create_reprobe_message_data(const char *target_node, const char *router_node)
363 {
364 xmlNode *msg_data;
365
366 msg_data = create_xml_node(NULL, "data_for_" CRM_OP_REPROBE);
367 crm_xml_add(msg_data, XML_LRM_ATTR_TARGET, target_node);
368 if ((router_node != NULL) && !pcmk__str_eq(router_node, target_node, pcmk__str_casei)) {
369 crm_xml_add(msg_data, XML_LRM_ATTR_ROUTER_NODE, router_node);
370 }
371 return msg_data;
372 }
373
374
375
376
377
378
379
380
381
382
383
384 int
385 pcmk_controld_api_reprobe(pcmk_ipc_api_t *api, const char *target_node,
386 const char *router_node)
387 {
388 xmlNode *request;
389 xmlNode *msg_data;
390 int rc = pcmk_rc_ok;
391
392 if (api == NULL) {
393 return EINVAL;
394 }
395 if (router_node == NULL) {
396 router_node = target_node;
397 }
398 crm_debug("Sending %s IPC request to reprobe %s via %s",
399 pcmk_ipc_name(api, true), pcmk__s(target_node, "local node"),
400 pcmk__s(router_node, "local node"));
401 msg_data = create_reprobe_message_data(target_node, router_node);
402 request = create_controller_request(api, CRM_OP_REPROBE, router_node,
403 msg_data);
404 rc = send_controller_request(api, request, true);
405 free_xml(msg_data);
406 free_xml(request);
407 return rc;
408 }
409
410
411
412
413
414
415
416
417
418
419 int
420 pcmk_controld_api_node_info(pcmk_ipc_api_t *api, uint32_t nodeid)
421 {
422 xmlNode *request;
423 int rc = pcmk_rc_ok;
424
425 request = create_controller_request(api, CRM_OP_NODE_INFO, NULL, NULL);
426 if (request == NULL) {
427 return EINVAL;
428 }
429 if (nodeid > 0) {
430 crm_xml_set_id(request, "%lu", (unsigned long) nodeid);
431 }
432
433 rc = send_controller_request(api, request, true);
434 free_xml(request);
435 return rc;
436 }
437
438
439
440
441
442
443
444
445
446
447 int
448 pcmk_controld_api_ping(pcmk_ipc_api_t *api, const char *node_name)
449 {
450 xmlNode *request;
451 int rc = pcmk_rc_ok;
452
453 request = create_controller_request(api, CRM_OP_PING, node_name, NULL);
454 if (request == NULL) {
455 return EINVAL;
456 }
457 rc = send_controller_request(api, request, true);
458 free_xml(request);
459 return rc;
460 }
461
462
463
464
465
466
467
468
469
470 int
471 pcmk_controld_api_list_nodes(pcmk_ipc_api_t *api)
472 {
473 xmlNode *request;
474 int rc = EINVAL;
475
476 request = create_controller_request(api, PCMK__CONTROLD_CMD_NODES, NULL,
477 NULL);
478 if (request != NULL) {
479 rc = send_controller_request(api, request, true);
480 free_xml(request);
481 }
482 return rc;
483 }
484
485
486 static int
487 controller_resource_op(pcmk_ipc_api_t *api, const char *op,
488 const char *target_node, const char *router_node,
489 bool cib_only, const char *rsc_id,
490 const char *rsc_long_id, const char *standard,
491 const char *provider, const char *type)
492 {
493 int rc = pcmk_rc_ok;
494 char *key;
495 xmlNode *request, *msg_data, *xml_rsc, *params;
496
497 if (api == NULL) {
498 return EINVAL;
499 }
500 if (router_node == NULL) {
501 router_node = target_node;
502 }
503
504 msg_data = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP);
505
506
507
508
509
510 key = pcmk__transition_key(0, getpid(), 0,
511 "xxxxxxxx-xrsc-opxx-xcrm-resourcexxxx");
512 crm_xml_add(msg_data, XML_ATTR_TRANSITION_KEY, key);
513 free(key);
514
515 crm_xml_add(msg_data, XML_LRM_ATTR_TARGET, target_node);
516 if (!pcmk__str_eq(router_node, target_node, pcmk__str_casei)) {
517 crm_xml_add(msg_data, XML_LRM_ATTR_ROUTER_NODE, router_node);
518 }
519
520 if (cib_only) {
521
522 crm_xml_add(msg_data, PCMK__XA_MODE, XML_TAG_CIB);
523 }
524
525 xml_rsc = create_xml_node(msg_data, XML_CIB_TAG_RESOURCE);
526 crm_xml_add(xml_rsc, XML_ATTR_ID, rsc_id);
527 crm_xml_add(xml_rsc, XML_ATTR_ID_LONG, rsc_long_id);
528 crm_xml_add(xml_rsc, XML_AGENT_ATTR_CLASS, standard);
529 crm_xml_add(xml_rsc, XML_AGENT_ATTR_PROVIDER, provider);
530 crm_xml_add(xml_rsc, XML_ATTR_TYPE, type);
531
532 params = create_xml_node(msg_data, XML_TAG_ATTRS);
533 crm_xml_add(params, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
534
535
536 key = crm_meta_name(XML_ATTR_TIMEOUT);
537 crm_xml_add(params, key, "60000");
538 free(key);
539
540 request = create_controller_request(api, op, router_node, msg_data);
541 rc = send_controller_request(api, request, true);
542 free_xml(msg_data);
543 free_xml(request);
544 return rc;
545 }
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562 int
563 pcmk_controld_api_fail(pcmk_ipc_api_t *api,
564 const char *target_node, const char *router_node,
565 const char *rsc_id, const char *rsc_long_id,
566 const char *standard, const char *provider,
567 const char *type)
568 {
569 crm_debug("Sending %s IPC request to fail %s (a.k.a. %s) on %s via %s",
570 pcmk_ipc_name(api, true), pcmk__s(rsc_id, "unknown resource"),
571 pcmk__s(rsc_long_id, "no other names"),
572 pcmk__s(target_node, "unspecified node"),
573 pcmk__s(router_node, "unspecified node"));
574 return controller_resource_op(api, CRM_OP_LRM_FAIL, target_node,
575 router_node, false, rsc_id, rsc_long_id,
576 standard, provider, type);
577 }
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595 int
596 pcmk_controld_api_refresh(pcmk_ipc_api_t *api, const char *target_node,
597 const char *router_node,
598 const char *rsc_id, const char *rsc_long_id,
599 const char *standard, const char *provider,
600 const char *type, bool cib_only)
601 {
602 crm_debug("Sending %s IPC request to refresh %s (a.k.a. %s) on %s via %s",
603 pcmk_ipc_name(api, true), pcmk__s(rsc_id, "unknown resource"),
604 pcmk__s(rsc_long_id, "no other names"),
605 pcmk__s(target_node, "unspecified node"),
606 pcmk__s(router_node, "unspecified node"));
607 return controller_resource_op(api, CRM_OP_LRM_DELETE, target_node,
608 router_node, cib_only, rsc_id, rsc_long_id,
609 standard, provider, type);
610 }
611
612
613
614
615
616
617
618
619 unsigned int
620 pcmk_controld_api_replies_expected(const pcmk_ipc_api_t *api)
621 {
622 struct controld_api_private_s *private = api->api_data;
623
624 return private->replies_expected;
625 }
626
627
628
629
630
631
632
633 xmlNode *
634 create_hello_message(const char *uuid, const char *client_name,
635 const char *major_version, const char *minor_version)
636 {
637 xmlNode *hello_node = NULL;
638 xmlNode *hello = NULL;
639
640 if (pcmk__str_empty(uuid) || pcmk__str_empty(client_name)
641 || pcmk__str_empty(major_version) || pcmk__str_empty(minor_version)) {
642 crm_err("Could not create IPC hello message from %s (UUID %s): "
643 "missing information",
644 client_name? client_name : "unknown client",
645 uuid? uuid : "unknown");
646 return NULL;
647 }
648
649 hello_node = create_xml_node(NULL, XML_TAG_OPTIONS);
650 if (hello_node == NULL) {
651 crm_err("Could not create IPC hello message from %s (UUID %s): "
652 "Message data creation failed", client_name, uuid);
653 return NULL;
654 }
655
656 crm_xml_add(hello_node, "major_version", major_version);
657 crm_xml_add(hello_node, "minor_version", minor_version);
658 crm_xml_add(hello_node, "client_name", client_name);
659 crm_xml_add(hello_node, "client_uuid", uuid);
660
661 hello = create_request(CRM_OP_HELLO, hello_node, NULL, NULL, client_name, uuid);
662 if (hello == NULL) {
663 crm_err("Could not create IPC hello message from %s (UUID %s): "
664 "Request creation failed", client_name, uuid);
665 return NULL;
666 }
667 free_xml(hello_node);
668
669 crm_trace("Created hello message from %s (UUID %s)", client_name, uuid);
670 return hello;
671 }