This source file includes following definitions.
- 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
- pcmk_controld_api_shutdown
- pcmk_controld_api_start_election
- 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 static int
32 new_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
45
46
47
48
49
50 private->client_uuid = pcmk__getpid_s();
51
52
53
54
55
56 return pcmk_rc_ok;
57 }
58
59 static void
60 free_data(void *data)
61 {
62 free(((struct controld_api_private_s *) data)->client_uuid);
63 free(data);
64 }
65
66
67 static int
68 post_connect(pcmk_ipc_api_t *api)
69 {
70
71
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,
79 PCMK__CONTROLD_API_MAJOR,
80 PCMK__CONTROLD_API_MINOR);
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
94 static void
95 set_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
109 static void
110 set_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,
117 XML_PING_ATTR_SYSFROM);
118 data->data.ping.fsa_state = crm_element_value(msg_data,
119 XML_PING_ATTR_CRMDSTATE);
120 data->data.ping.result = crm_element_value(msg_data, XML_PING_ATTR_STATUS);
121 }
122
123 static void
124 set_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
145 static bool
146 reply_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
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
162 static void
163 dispatch(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
178
179
180
181
182
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
207
208 reply_data.feature_set = crm_element_value(reply, XML_ATTR_VERSION);
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)) {
213 reply_data.reply_type = pcmk_controld_reply_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)) {
219 reply_data.reply_type = pcmk_controld_reply_resource;
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
234 done:
235 pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
236
237
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
243 pcmk__ipc_methods_t *
244 pcmk__controld_api_methods()
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
258
259
260
261
262
263
264
265
266
267
268
269 static xmlNode *
270 create_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
291 static int
292 send_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
309 static xmlNode *
310 create_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
322
323
324
325
326
327
328
329
330
331
332 int
333 pcmk_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
358
359
360
361
362
363
364
365
366
367 int
368 pcmk_controld_api_node_info(pcmk_ipc_api_t *api, uint32_t nodeid)
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
386
387
388
389
390
391
392
393
394
395 int
396 pcmk_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
410
411
412
413
414
415
416
417
418 int
419 pcmk_controld_api_list_nodes(pcmk_ipc_api_t *api)
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
434
435
436
437
438
439
440
441
442
443
444
445
446 int
447 pcmk_controld_api_shutdown(pcmk_ipc_api_t *api, const char *node_name)
448 {
449 xmlNode *request;
450 int rc = pcmk_rc_ok;
451
452 request = create_controller_request(api, CRM_OP_SHUTDOWN, NULL, NULL);
453 if (request == NULL) {
454 return EINVAL;
455 }
456 rc = send_controller_request(api, request, false);
457 free_xml(request);
458 return rc;
459 }
460
461
462
463
464
465
466
467
468
469
470
471
472
473 int
474 pcmk_controld_api_start_election(pcmk_ipc_api_t *api)
475 {
476 xmlNode *request;
477 int rc = pcmk_rc_ok;
478
479 request = create_controller_request(api, CRM_OP_VOTE, NULL, NULL);
480 if (request == NULL) {
481 return EINVAL;
482 }
483 rc = send_controller_request(api, request, false);
484 free_xml(request);
485 return rc;
486 }
487
488
489 static int
490 controller_resource_op(pcmk_ipc_api_t *api, const char *op,
491 const char *target_node, const char *router_node,
492 bool cib_only, const char *rsc_id,
493 const char *rsc_long_id, const char *standard,
494 const char *provider, const char *type)
495 {
496 int rc = pcmk_rc_ok;
497 char *key;
498 xmlNode *request, *msg_data, *xml_rsc, *params;
499
500 if (api == NULL) {
501 return EINVAL;
502 }
503 if (router_node == NULL) {
504 router_node = target_node;
505 }
506
507 msg_data = create_xml_node(NULL, XML_GRAPH_TAG_RSC_OP);
508
509
510
511
512
513 key = pcmk__transition_key(0, getpid(), 0,
514 "xxxxxxxx-xrsc-opxx-xcrm-resourcexxxx");
515 crm_xml_add(msg_data, XML_ATTR_TRANSITION_KEY, key);
516 free(key);
517
518 crm_xml_add(msg_data, XML_LRM_ATTR_TARGET, target_node);
519 if (!pcmk__str_eq(router_node, target_node, pcmk__str_casei)) {
520 crm_xml_add(msg_data, XML_LRM_ATTR_ROUTER_NODE, router_node);
521 }
522
523 if (cib_only) {
524
525 crm_xml_add(msg_data, PCMK__XA_MODE, XML_TAG_CIB);
526 }
527
528 xml_rsc = create_xml_node(msg_data, XML_CIB_TAG_RESOURCE);
529 crm_xml_add(xml_rsc, XML_ATTR_ID, rsc_id);
530 crm_xml_add(xml_rsc, XML_ATTR_ID_LONG, rsc_long_id);
531 crm_xml_add(xml_rsc, XML_AGENT_ATTR_CLASS, standard);
532 crm_xml_add(xml_rsc, XML_AGENT_ATTR_PROVIDER, provider);
533 crm_xml_add(xml_rsc, XML_ATTR_TYPE, type);
534
535 params = create_xml_node(msg_data, XML_TAG_ATTRS);
536 crm_xml_add(params, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
537
538
539 key = crm_meta_name(XML_ATTR_TIMEOUT);
540 crm_xml_add(params, key, "60000");
541 free(key);
542
543 request = create_controller_request(api, op, router_node, msg_data);
544 rc = send_controller_request(api, request, true);
545 free_xml(msg_data);
546 free_xml(request);
547 return rc;
548 }
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565 int
566 pcmk_controld_api_fail(pcmk_ipc_api_t *api,
567 const char *target_node, const char *router_node,
568 const char *rsc_id, const char *rsc_long_id,
569 const char *standard, const char *provider,
570 const char *type)
571 {
572 crm_debug("Sending %s IPC request to fail %s (a.k.a. %s) on %s via %s",
573 pcmk_ipc_name(api, true), crm_str(rsc_id), crm_str(rsc_long_id),
574 crm_str(target_node), crm_str(router_node));
575 return controller_resource_op(api, CRM_OP_LRM_FAIL, target_node,
576 router_node, false, rsc_id, rsc_long_id,
577 standard, provider, type);
578 }
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596 int
597 pcmk_controld_api_refresh(pcmk_ipc_api_t *api, const char *target_node,
598 const char *router_node,
599 const char *rsc_id, const char *rsc_long_id,
600 const char *standard, const char *provider,
601 const char *type, bool cib_only)
602 {
603 crm_debug("Sending %s IPC request to refresh %s (a.k.a. %s) on %s via %s",
604 pcmk_ipc_name(api, true), crm_str(rsc_id), crm_str(rsc_long_id),
605 crm_str(target_node), crm_str(router_node));
606 return controller_resource_op(api, CRM_OP_LRM_DELETE, target_node,
607 router_node, cib_only, rsc_id, rsc_long_id,
608 standard, provider, type);
609 }
610
611
612
613
614
615
616
617
618 unsigned int
619 pcmk_controld_api_replies_expected(pcmk_ipc_api_t *api)
620 {
621 struct controld_api_private_s *private = api->api_data;
622
623 return private->replies_expected;
624 }
625
626
627
628
629
630
631
632 xmlNode *
633 create_hello_message(const char *uuid, const char *client_name,
634 const char *major_version, const char *minor_version)
635 {
636 xmlNode *hello_node = NULL;
637 xmlNode *hello = NULL;
638
639 if (pcmk__str_empty(uuid) || pcmk__str_empty(client_name)
640 || pcmk__str_empty(major_version) || pcmk__str_empty(minor_version)) {
641 crm_err("Could not create IPC hello message from %s (UUID %s): "
642 "missing information",
643 client_name? client_name : "unknown client",
644 uuid? uuid : "unknown");
645 return NULL;
646 }
647
648 hello_node = create_xml_node(NULL, XML_TAG_OPTIONS);
649 if (hello_node == NULL) {
650 crm_err("Could not create IPC hello message from %s (UUID %s): "
651 "Message data creation failed", client_name, uuid);
652 return NULL;
653 }
654
655 crm_xml_add(hello_node, "major_version", major_version);
656 crm_xml_add(hello_node, "minor_version", minor_version);
657 crm_xml_add(hello_node, "client_name", client_name);
658 crm_xml_add(hello_node, "client_uuid", uuid);
659
660 hello = create_request(CRM_OP_HELLO, hello_node, NULL, NULL, client_name, uuid);
661 if (hello == NULL) {
662 crm_err("Could not create IPC hello message from %s (UUID %s): "
663 "Request creation failed", client_name, uuid);
664 return NULL;
665 }
666 free_xml(hello_node);
667
668 crm_trace("Created hello message from %s (UUID %s)", client_name, uuid);
669 return hello;
670 }